【问题标题】:CGContextDrawLayerInRect from CGBitmapContextCreate failing iPhone 7 Plus来自 CGBitmapContextCreate 的 CGContextDrawLayerInRect 失败 iPhone 7 Plus
【发布时间】:2017-09-10 20:14:56
【问题描述】:

我有一个 Objective C 项目,它在某一时刻从您的照片库或相机中拍摄一张照片,然后将它们切成小方块(图块),并最终从切碎的图像中创建新的 UIImage 对象正方形。

代码完美在我的旧 iPhone 5 和 iPad Mini 2 上运行。

然而,在我的 iPhone 7 Plus 上,它会产生 blank 输出(而不是我输入的切碎部分)。 iPad Mini 2 和 iPhone 7 Plus 都运行 iOS 10.3.3,并且都是 64 位设备。

完整的功能在这里:

-(void) createTilesFromImage:(UIImage*)img inRect:(CGRect)rect inContext:(CGContextRef)context {

    if (tilesDefined) {
            return;
    }

    tilesDefined = YES;


    // Tileboard layer
    CGSize tileboardsize = rect.size;
    tileboardrect = rect;

    // Chop image
    CGLayerRef imagetochop = CGLayerCreateWithContext(context, tileboardsize, NULL);
    CGContextRef ctx2 = CGLayerGetContext(imagetochop);
    UIGraphicsPushContext(ctx2);
    [img drawInRect:CGRectMake(0, 0, tileboardsize.width, tileboardsize.height)];
    UIGraphicsPopContext();

    // Tile layer size (CG & CA)
    tilesize = CGSizeMake(ceilf(tileboardsize.width / dims.x),ceilf( tileboardsize.height / dims.y ));

    // Bitmap context
    CGContextRef bmpContext = [[QPDrawing shared] newCGBitmapContextWithSize:tilesize withData:YES];

    // Create tile layers
    tiles = [[NSMutableArray alloc] initWithCapacity:dims.x * dims.y];
    int i = 0;
    for (int y = 0; y < dims.y; y++) {
            for (int x = 0; x < dims.x; x++) {
                    tileLayers[i] = CGLayerCreateWithContext(context, tilesize, NULL);               

                    CGContextRef squarecontext = CGLayerGetContext(tileLayers[i]);
                    CGPoint offset = CGPointMake(x * tileboardsize.width / dims.x * -1, y * tileboardsize.height / dims.y * -1);

                    // Invert the layer prior to drawing
                    CGContextTranslateCTM(squarecontext, 0, tilesize.height);
                    CGContextScaleCTM(squarecontext, 1.0, -1.0);
                    CGContextDrawLayerAtPoint(squarecontext, offset, imagetochop);

                    CGContextDrawLayerInRect(bmpContext, (CGRect){0,0,tilesize.width,tilesize.height}, tileLayers[i]);
                    CGImageRef imageRef = CGBitmapContextCreateImage( bmpContext );

                    [tiles addObject: [UIImage imageWithCGImage: imageRef]];

                    CGImageRelease(imageRef);

                    i++;
            }
    }

    // Cleanup
    CGLayerRelease(imagetochop);
    CGContextRelease(bmpContext);

    rect = CGRectInset(rect, 2, 2);
    CGContextAddRect(context, rect);
    CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:1 green:0 blue:0 alpha:1].CGColor);
    CGContextSetLineWidth(context, 2);
    CGContextStrokePath(context);
}

这在创建CGContextRef时调用了一个外部部分,bmpContext -- newCGBitmapContextWithSize:tileSize:withData。该位的代码如下:

- (CGContextRef) newCGBitmapContextWithSize:(CGSize)size withData:(BOOL)includeData {

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    int width = (int)ceilf(size.width);
    int height = (int)ceilf(size.height);
    size_t bitsPerComponent = 8;
    size_t bytesPerPixel    = 4;
    size_t bytesPerRow      = (width * bitsPerComponent * bytesPerPixel + 7) / 8;
    size_t dataSize         = bytesPerRow * height;

    unsigned char *data = NULL; 
    if (includeData) {
            data = malloc(dataSize);
            memset(data, 0, dataSize);
    }

    CGContextRef context = CGBitmapContextCreate(data, size.width, size.height,
            bitsPerComponent, bytesPerRow, colorSpace,
            kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGColorSpaceRelease(colorSpace);
    return context;
}

起初我以为是“drawInRect”调用不知何故不起作用,现在我确信情况并非如此。我认为它与 CGBitmapContextCreate 调用有关。

谢谢!

【问题讨论】:

  • "我有一个 Objective C 项目,它会从你的照片库或相机中拍摄一张照片,然后将它们切成小方块(瓷砖),最终创建新的UIImage 对象来自切碎的正方形。”我的应用程序没有做任何你正在做的事情就做到了。您可能对更简单的方法感兴趣吗?
  • 顺便说一下,与 Plus 的一个明显区别是它是三倍分辨率。您可能没有以某种方式考虑到这一点。
  • 是的! ——尽管我仍然想至少了解为什么这段代码在某些设备上完美运行,而在其他设备上却不行。也许与更宽的色域有关?但我仍然不希望这不起作用。

标签: ios objective-c cgbitmapcontextcreate


【解决方案1】:

在我看来,你做的工作比你需要做的多得多;也许您正在考虑如何将图像划分为图块的问题。您可能对更简单的方法感兴趣。这就是我在 Diabelli's Theme 应用程序中所做的。它是 Swift,但我认为您阅读它不会有任何问题(如果您真的需要,我确实有旧的 Objective-C 代码)。

显然,我循环遍历图像要分割的“图块”。我已经通过h 计算出了行数和列数以及磁贴的大小,w。原图为im。这就是我所要做的:

for row in 0..<ROWS {
    for col in 0..<COLS {
        UIGraphicsBeginImageContextWithOptions(CGSize(
            width: CGFloat(w),height: CGFloat(h)), true, 0)
        im.draw(at: CGPoint(x: CGFloat(-w*col),y: CGFloat(-h*row)))
        let tileImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        // do something with tileImage
    }
}

【讨论】:

    【解决方案2】:

    我能够通过切换到每个颜色分量和浮点分量 16 位来解决这个问题

    - (CGContextRef) newCGBitmapContextWithSize:(CGSize)size withData:(BOOL)includeData {
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    int width = (int)ceilf(size.width);
    int height = (int)ceilf(size.height);
    size_t bitsPerComponent = 16; //8; <--CHANGED
    size_t bytesPerPixel    = 8;  //4; <--CHANGED
    size_t bytesPerRow      = (width * bitsPerComponent * bytesPerPixel + 7) / 8;
    size_t dataSize         = bytesPerRow * height;
    
    unsigned char *data = NULL; 
    if (includeData) {
            data = malloc(dataSize);
            memset(data, 0, dataSize);
    }
    
    CGContextRef context = CGBitmapContextCreate(data, size.width, size.height,
            bitsPerComponent, bytesPerRow, colorSpace,
            kCGImageAlphaPremultipliedLast |
              kCGBitmapFloatComponents | kCGBitmapByteOrder16Little); // <-- CHANGED
    
    CGColorSpaceRelease(colorSpace);
    return context;
    }
    

    这在上述所有设备上都有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      • 2017-02-01
      • 2017-06-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多