Search code examples
iosobjective-cuicolorcore-imagecgcolor

Colorwithpattern for coreimage color


I am using CIAztecCodeGenerator to generate an Aztec code.

I'm trying to set a pattern instead of a solid color for the foreground color for it however it is rendering as blank/white I was wondering if anyone knew what I am doing wrong.

[colorFilter setValue:[CIColor colorWithCGColor:[[UIColor colorWithPatternImage:image] CGColor]] forKey:@"inputColor0"];

Solution

  • It's a bit more complicated, but you can use a custom pattern by combining and blending the images in a certain way:

    import CoreImage.CIFilterBuiltins // needed for using the type-safe filter interface
    
    // ...
    
    let patternImage = UIImage(named: "<image_name>")!
    var patternInput = CIImage(cgImage: patternImage.cgImage!)
    
    // potentially scale the pattern image
    patternInput = patternInput.transformed(by: CGAffineTransform(scaleX: 0.5, y: 0.5))
    
    let codeFilter = CIFilter.aztecCodeGenerator()
    codeFilter.message = "<message>".data(using: .utf8)!
    var codeImage = codeFilter.outputImage!
    
    // invert code so the actual code part is white
    let colorInvertFilter = CIFilter.colorInvert()
    colorInvertFilter.inputImage = codeImage
    codeImage = colorInvertFilter.outputImage!
    
    // potentially scale the barcode (using nearest sampling to retain sharp edges)
    codeImage = codeImage.samplingNearest().transformed(by: CGAffineTransform(scaleX: 50, y: 50))
    
    let blendFilter = CIFilter.blendWithMask()
    blendFilter.inputImage = patternInput
    // using white color as background here, but can be any (or transparent when alpha = 0)
    blendFilter.backgroundImage = CIImage(color: CIColor.white).cropped(to: codeImage.extent)
    blendFilter.maskImage = codeImage
    
    let output = blendFilter.outputImage!
    

    Objective-C version:

    // the image containing the pattern you want to show over the aztec code
    CIImage *patternImage = [CIImage imageWithData:imageData];
    
    // potentially scale the pattern image, if necessary
    patternImage = [patternImage imageByApplyingTransform:CGAffineTransformMakeScale(0.5, 0.5)];
    
    // generate aztec code image
    CIFilter *qrFilter = [CIFilter filterWithName:@"CIAztecCodeGenerator"];
    [qrFilter setValue:stringData forKey:@"inputMessage"];
    CIImage *codeImage = qrFilter.outputImage;
    
    // invert code so the actual code part is white (used for masking below)
    codeImage = [codeImage imageByApplyingFilter: @"CIColorInvert"];
    
    // potentially scale the aztec code (using nearest sampling to retain sharp edges)
    codeImage = [[codeImage imageBySamplingNearest] imageByApplyingTransform:CGAffineTransformMakeScale(50, 50)];
    
    // the background color for your aztec code; basically a solid color image of the same size of the code
    CIImage *background = [[CIImage imageWithColor:[CIColor whiteColor]] imageByCroppingToRect:codeImage.extent];
    
    //
    CIFilter *blendFilter = [CIFilter filterWithName:@"CIBlendWithMask"];
    [blendFilter setValue:patternImage forKey:@"inputImage"]; // the pattern image is in the foreground
    [blendFilter setValue:background forKey:@"backgroundImage"]; // solid color in the aztec code, but could be any color or image
    [blendFilter setValue:codeImage forKey:@"maskImage"]; // use the aztec code as a mask for the pattern image over the background
    
    CIImage *output = blendFilter.outputImage
    

    Note that the numbers in the two scaling steps depend on how large you want to display the code and how the pattern image should be scaled above the code.