CIImage generate CGImage is unavailable

I want to use CIFilter to create a CGImageRef, but when I get cgimage buffer , it is empty

CIFilter<CITextImageGenerator> * filter = [CIFilter textImageGeneratorFilter];
  filter.text = @"This is a test text";
  filter.fontName = @"HoeflerText-Regula";
  filter.fontSize = 12;
  filter.scaleFactor = 1.0;
  CIImage *image = filter.outputImage;

  CIContext *context = [CIContext contextWithOptions:nil];
  CGImageRef resultRef = [context createCGImage:image fromRect:image.extent];
  UIImage *resultImage = [UIImage imageWithCGImage:resultRef];
   
  CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(resultRef));
  const unsigned char * buffer = CFDataGetBytePtr(data);

And then I could not generate MTLTexture with this cgimage

 MTKTextureLoader *loader = [[MTKTextureLoader alloc] initWithDevice:self.device];
  NSError*error;
  id<MTLTexture> fontTexture = [loader newTextureWithCGImage:resultRef
                     options:@{
    MTKTextureLoaderOptionOrigin : MTKTextureLoaderOriginFlippedVertically,
    MTKTextureLoaderOptionSRGB : @(NO)
  }
                      error:&error];

   How can I finish my work? Any suggestions about this question I am appreciate.

Accepted Reply

Your fontName is incorrect, it's missing an r at the end, it should be @"HoeflerText-Regular".

Adding an r resulted in this image:

Replies

Your fontName is incorrect, it's missing an r at the end, it should be @"HoeflerText-Regular".

Adding an r resulted in this image:

Yes, I fix this problem, and UIImage is correct, but actually I still get the nil data to create MTLTexture. But When I load a png file, everything is ok This is my test code:

self.device = MTLCreateSystemDefaultDevice();
   
  // My Text Image
  CIFilter<CITextImageGenerator> * filter = [CIFilter textImageGeneratorFilter];
   filter.text = @"This is a test text";
   filter.fontName = @"HoeflerText-Regular";
   filter.fontSize = 12;
   filter.scaleFactor = 1.0;
   CIImage *image = filter.outputImage;

   CIContext *cicontext = [CIContext contextWithOptions:nil];
   CGImageRef resultRef = [cicontext createCGImage:image fromRect:image.extent];
   UIImage *resultImage = [UIImage imageWithCGImage:resultRef];
  // PNG Image
//  UIImage *resultImage = [UIImage imageNamed:@"nx"];
//  CGImageRef resultRef = resultImage.CGImage;
    
   CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(resultRef));
   const unsigned char * buffer = CFDataGetBytePtr(data);
   
  CGFloat width = CGImageGetWidth(resultRef), height = CGImageGetHeight(resultRef);
  NSInteger bytesPerPixel = 4, bytesPerRow = bytesPerPixel * width, bitsPerComponent = 8;
  CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  void *rawData = calloc(height * width * bytesPerPixel, sizeof(uint8_t));
  if (rawData == nil) {
    CGColorSpaceRelease(colorSpace);
    colorSpace = NULL;
  }
  CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast|kCGImageByteOrder32Big);
  CGColorSpaceRelease(colorSpace);
  colorSpace = NULL;
  if (context == nil) {
    free(rawData);
  }
  CGContextTranslateCTM(context, 0, height);
  CGContextScaleCTM(context, 1, -1);
  CGContextDrawImage(context, CGRectMake(0, 0, width, height), resultRef);
   
  MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm width:width height:height mipmapped:NO];
  id<MTLTexture> texture = [self.device newTextureWithDescriptor:textureDescriptor];
  if (!texture) {
    free(rawData);
    CGContextRelease(context);
  }
  MTLRegion region = MTLRegionMake3D(0, 0, 0, width, height, 1);
  [texture replaceRegion:region mipmapLevel:0 withBytes:rawData bytesPerRow:bytesPerRow];
  free(rawData);
  CGContextRelease(context);
  _fontTexture = texture;

Thank you very much!

This is my test image named nx

It renders as expected. However your texture background's is black just like your text colour. Because CGContext is premultiplying alpha.

If you change the context's background to red for example, you will see it.

CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast|kCGImageByteOrder32Big);
CGContextSetFillColorWithColor(context, [[UIColor redColor] CGColor]);
CGContextFillRect(context,  CGRectMake(0, 0, width, height));

To bypass CGContext all together, try rendering directly to an MTLTexture using CIContext's render(_: to: commandBuffer: bounds: colorSpace:), you can find more info here: Apple Developer Doc