Core Image recipe for QR code icon image

This thread has been locked by a moderator; it no longer accepts new replies.
  1. Create the QRCode
CIFilter<CIBlendWithMask> *f = CIFilter.QRCodeGenerator;

f.message = [@"Message" dataUsingEncoding:NSASCIIStringEncoding];

f.correctionLevel = @"Q"; // increase level 

CIImage *qrcode = f.outputImage;
  1. Overlay the icon
CIImage *icon = [CIImage imageWithURL:url];

CGAffineTransform *t = CGAffineTransformMakeTranslation(
  (qrcode.extent.width-icon.extent.width)/2.0,
  (qrcode.extent.height-icon.extent.height)/2.0);

icon = [icon imageByApplyingTransform:t];
qrcode = [icon imageByCompositingOver:qrcode];
  1. Round off the corners
static dispatch_once_t onceToken;
static CIWarpKernel *k;
dispatch_once(&onceToken, ^ {
    k = [CIWarpKernel kernelWithFunctionName:name
                        fromMetalLibraryData:metalLibData()
                                       error:nil];
});

CGRect iExtent = image.extent;
qrcode = [k applyWithExtent:qrcode.extent
                roiCallback:^CGRect(int i, CGRect r) {
                    return CGRectInset(r, -radius, -radius); }
                 inputImage:qrcode
                  arguments:@[[CIVector vectorWithCGRect:qrcode.extent], @(radius)]];

…and this code for the kernel should go in a separate .ci.metal source file:

float2 bend_corners (float4 extent, float s, destination dest)
{
    float2 p, dc = dest.coord();
    float ratio = 1.0;
    
    // Round lower left corner
    p = float2(extent.x+s,extent.y+s);
    if (dc.x < p.x && dc.y < p.y) {
        float2 d = abs(dc - p);
        ratio = min(d.x,d.y)/max(d.x,d.y);
        ratio = sqrt(1.0 + ratio*ratio);
        return (dc - p)*ratio + p;
    }
    
    // Round lower right corner
    p = float2(extent.x+extent.z-s, extent.y+s);
    
    if (dc.x > p.x && dc.y < p.y) {
        float2 d = abs(dc - p);
        ratio = min(d.x,d.y)/max(d.x,d.y);
        ratio = sqrt(1.0 + ratio*ratio);
        return (dc - p)*ratio + p;
    }
    
    // Round upper left corner
    p = float2(extent.x+s,extent.y+extent.w-s);
    if (dc.x < p.x && dc.y > p.y) {
        float2 d = abs(dc - p);
        ratio = min(d.x,d.y)/max(d.x,d.y);
        ratio = sqrt(1.0 + ratio*ratio);
        return (dc - p)*ratio + p;
    }
    
    // Round upper right corner
    p = float2(extent.x+extent.z-s, extent.y+extent.w-s);
    if (dc.x > p.x && dc.y > p.y) {
        float2 d = abs(dc - p);
        ratio = min(d.x,d.y)/max(d.x,d.y);
        ratio = sqrt(1.0 + ratio*ratio);
        return (dc - p)*ratio + p;
    }
    
    return dc;
}
Boost
Core Image recipe for QR code icon image
 
 
Q