How to add text to CIImage?
Asked Answered
D

2

5

I am working with the Photos framework and have created an app that will apply a filter to an image. Now instead of applying a filter, I want to add text on top of the image. This API provides me with a CIImage which I can use to create an output CIImage. I just do not know how to add text at a specific location to a CIImage. If I am correct, it would not be recommended to convert it to a CGImage and then add the text due to performance degradation.

How could one work with an existing CIImage to output that exact same CIImage (preserve original image quality) with text laid on top at a specific location?

//Get full image
let url = contentEditingInput.fullSizeImageURL
let orientation = contentEditingInput.fullSizeImageOrientation
var inputImage = CIImage(contentsOfURL: url)
inputImage = inputImage.imageByApplyingOrientation(orientation)

//TODO: REPLACE WITH TEXT OVERLAY
/*//Add filter
let filterName = "CISepiaTone"
let filter = CIFilter(name: filterName)
filter.setDefaults()
filter.setValue(inputImage, forKey: kCIInputImageKey)
let outputImage: CIImage = filter.outputImage*/

//Create editing output
let jpegData: NSData = self.jpegRepresentationOfImage(outputImage)
let adjustmentData = PHAdjustmentData(formatIdentifier: AdjustmentFormatIdentifier, formatVersion: "1.0", data: filterName.dataUsingEncoding(NSUTF8StringEncoding))

let contentEditingOutput = PHContentEditingOutput(contentEditingInput: contentEditingInput)
jpegData.writeToURL(contentEditingOutput.renderedContentURL, atomically: true)
contentEditingOutput.adjustmentData = adjustmentData

PHPhotoLibrary.sharedPhotoLibrary().performChanges({ () -> Void in
    let request = PHAssetChangeRequest(forAsset: asset)
request.contentEditingOutput = contentEditingOutput
}, completionHandler: { (success: Bool, error: NSError!) -> Void in
    if !success {
        NSLog("Error saving image: %@", error)
    }
})
Dorie answered 1/9, 2014 at 23:46 Comment(0)
P
4

You could draw the text in grayscale into a separate CGImage, convert the CGImage into a CIImage (via [+CIImage imageWithCGImage:]) and then use it as a mask, sending it and the original CIImage to the CIBlendWithMask filter.

Prothorax answered 2/9, 2014 at 0:33 Comment(2)
Beautiful. Just what I was looking for!Dorie
any example in swift?Muslim
B
3

As of last year, there is a new CIFilter available called CIAttributedTextImageGenerator. Here is an example of how I've used it, wrapped up in a utility class method:

+ (CIImage *)imageWithText:(NSString *)message color:(CIColor *)color scaleFactor:(CGFloat)scaleFactor
{
    NSDictionary *attributes = @{
        NSForegroundColorAttributeName : CFBridgingRelease(CGColorCreateSRGB(color.red, color.green, color.blue, color.alpha)),
    };
    NSAttributedString *text = [[NSAttributedString alloc] initWithString:message attributes:attributes];

    CIFilter<CIAttributedTextImageGenerator> *filter = [CIFilter attributedTextImageGeneratorFilter];
    filter.text = text;
    filter.scaleFactor = scaleFactor;

    CIImage *result = filter.outputImage;
    return result;
}

Unfortunately, there seems to be a bug that doesn't let you select a new color for a subsequent invocation of this filter. IOW, once you render this filter once, every subsequent render will produce text of the same color as the first render, regardless of the color you pass in.

At any rate, this will produce a CIImage that you can then overlay onto your inputImage like so:

CIImage *textImage = [YourUtilityClass imageWithText:@"Some text" color:[CIColor whiteColor] scaleFactor:1.0];
CIImage *outputImage = [textImage imageByCompositingOverImage:inputImage];

I don't have a lot of recent experience with Swift, but hopefully this Objective-C code is straightforward enough for you to get the idea.

Badge answered 1/9, 2020 at 23:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.