CGContextDrawImage crashes

The code is below:

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
    CGContextRef context = ctx;
    CGContextRetain(context);
    CGContextSetInterpolationQuality(context, kCGInterpolationNone);
    CGContextSetLineCap(context, kCGLineCapButt);
    CGContextSetLineWidth(context, 1);
    CGContextSetRGBStrokeColor(context, 0, 0, 0, 0.8);

    // draw image
    CGContextSaveGState(context);
    CGAffineTransform flipVertical = CGAffineTransformMake(
                                                           1, 0, 0, -1, 0, layer.bounds.size.height
                                                           );
    CGContextConcatCTM(context, flipVertical);

    CGContextDrawImage(context, layer.bounds, imageRef);
    CGContextRestoreGState(context);

    // draw borders
    CGContextAddRect(context, layer.bounds);
    CGContextDrawPath(context, kCGPathStroke);

    CGFloat apertureSize = scaleFactor * (2 * samplingLevel - 1) - 1;
    CGFloat x = self.bounds.size.width / 2 - apertureSize / 2;
    CGFloat y = self.bounds.size.height / 2 - apertureSize / 2;
    CGRect apertureRect = CGRectMake(x, y, apertureSize, apertureSize);

    // draw the aperture
    CGContextSaveGState(context);
    CGContextSetRGBStrokeColor(context, 0, 0, 0, 1);      
    CGContextSetShouldAntialias(context, NO);
    CGContextStrokeRect(context, apertureRect);
    CGContextRestoreGState(context);

    CGContextRelease(context);
}

and it crashes with:

  • objective c difference between functions and methods
  • UICollectionView recieved layout attributes for a cell with an index path that does not exist
  • Set UITableView Delegate and DataSource
  • Drawing Smooth Curves - Methods Needed
  • Calling a method on an uninitialized object (null pointer)
  • How to add table view section header with subscripts?
  • (lldb) thread backtrace
    * thread #1: tid = 0x1c03, 0x37537a5c CoreGraphics`argb32_image_mark_rgb32 + 800, stop reason = EXC_BAD_ACCESS (code=1, address=0x7314b0)
    frame #0: 0x37537a5c CoreGraphics`argb32_image_mark_rgb32 + 800
    frame #1: 0x3750e400 CoreGraphics`argb32_image + 5948
    frame #2: 0x313c5894 libRIP.A.dylib`ripl_Mark + 16
    frame #3: 0x313ca68a libRIP.A.dylib`ripl_BltImage + 998
    frame #4: 0x313c2468 libRIP.A.dylib`ripc_RenderImage + 180
    frame #5: 0x313be300 libRIP.A.dylib`ripc_DrawImage + 584
    frame #6: 0x3750a928 CoreGraphics`CGContextDelegateDrawImage + 48
    frame #7: 0x3750a794 CoreGraphics`CGContextDrawImage + 292
    frame #8: 0x00166e34 MyApp`-[MyView drawLayer:inContext:] + 380 at MyView.m:43
    frame #9: 0x33f054e4 QuartzCore`-[CALayer drawInContext:] + 116
    frame #10: 0x33f04b3e QuartzCore`CABackingStoreUpdate_ + 1782
    frame #11: 0x33f04334 QuartzCore`CA::Layer::display_() + 956
    frame #12: 0x33f03f60 QuartzCore`CA::Layer::display() + 128
    

    Anyone knows why? Thanks!
    I guess it is caused by either CGImage or CGContext, but both of them are Non-null when debugging.
    The image I used to update the view is generated from camera capturing.

    3 Solutions Collect From Internet About “CGContextDrawImage crashes”

    I used sample codes provided by apple (AV Foundation Programming Guide) to create imageRef.

    UIImage *imageFromSampleBuffer(CMSampleBufferRef sampleBuffer) {
    
        CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
        // Lock the base address of the pixel buffer.
        CVPixelBufferLockBaseAddress(imageBuffer,0);
    
        // Get the number of bytes per row for the pixel buffer.
        size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
        // Get the pixel buffer width and height.
        size_t width = CVPixelBufferGetWidth(imageBuffer);
        size_t height = CVPixelBufferGetHeight(imageBuffer);
    
        // Create a device-dependent RGB color space.
        static CGColorSpaceRef colorSpace = NULL;
        if (colorSpace == NULL) {
            colorSpace = CGColorSpaceCreateDeviceRGB();
                if (colorSpace == NULL) {
                // Handle the error appropriately.
                return nil;
            }
        }
    
        // Get the base address of the pixel buffer.
        void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
        // Get the data size for contiguous planes of the pixel buffer.
        size_t bufferSize = CVPixelBufferGetDataSize(imageBuffer);
    
        // Create a Quartz direct-access data provider that uses data we supply.
        CGDataProviderRef dataProvider =
            CGDataProviderCreateWithData(NULL, baseAddress, bufferSize, NULL);
        // Create a bitmap image from data supplied by the data provider.
        CGImageRef cgImage =
            CGImageCreate(width, height, 8, 32, bytesPerRow,
                            colorSpace, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little,
                            dataProvider, NULL, true, kCGRenderingIntentDefault);
        CGDataProviderRelease(dataProvider);
    
        // Create and return an image object to represent the Quartz image.
        UIImage *image = [UIImage imageWithCGImage:cgImage];
        CGImageRelease(cgImage);
    
        CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
    
        return image;
    }
    

    Note this line:

    CGDataProviderRef dataProvider =
            CGDataProviderCreateWithData(NULL, baseAddress, bufferSize, NULL);
    

    CMSampleBuffer is used directly to create a CGImageRef, so CGImageRef will become invalid once the buffer is released.

    Use copy of the buffer data will resolve this problem:

    NSData *data = [NSData dataWithBytes:baseAddress length:bufferSize];
    CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
    

    I encountered the same issue, but the problem was related to ARC and releasing the CGImageRef properly. Make sure the following is called:

    CGImageRelease(imageRef);
    

    change

    CGDataProviderRef dataProvider =
        CGDataProviderCreateWithData(NULL, baseAddress, bufferSize, NULL);
    

    to

    NSData *data = [NSData dataWithBytes:baseAddress length:bufferSize];
    CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
    

    really helps.