来自 CGBitmapContextCreate 的 CGContextDrawLayerInRect 失败 iPhone 7 Plus
CGContextDrawLayerInRect from CGBitmapContextCreate failing iPhone 7 Plus
我有一个 Objective C 项目,它有时会从您的照片库或相机中拍摄一张照片,然后将它们切成小方块(方块),并最终创建新的 UIImage来自切碎方块的对象。
该代码在我的旧 iPhone 5 和 iPad Mini 2 上完美。
但是,在我的 iPhone 7 Plus 上,它会产生 空白 输出(而不是切碎我的部分输入)。 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 调用有某种关系。
谢谢!
在我看来,您所做的工作比您需要做的要多得多;也许您正在考虑如何将图像划分为图块的问题。您可能对更简单的方法感兴趣。这就是我在我的 Diabelli 主题应用程序中所做的。它是 Swift,但我认为您阅读它不会有任何问题(如果您真的需要它,我确实有旧的 Objective-C 代码)。
很明显,我循环遍历了"tiles"要分割的图像。我已经计算出行数和列数,以及图块的大小,w
乘h
。原图为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
}
}
我能够通过切换到每个颜色分量和浮点分量 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;
}
这适用于上述所有设备。
我有一个 Objective C 项目,它有时会从您的照片库或相机中拍摄一张照片,然后将它们切成小方块(方块),并最终创建新的 UIImage来自切碎方块的对象。
该代码在我的旧 iPhone 5 和 iPad Mini 2 上完美。
但是,在我的 iPhone 7 Plus 上,它会产生 空白 输出(而不是切碎我的部分输入)。 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 调用有某种关系。
谢谢!
在我看来,您所做的工作比您需要做的要多得多;也许您正在考虑如何将图像划分为图块的问题。您可能对更简单的方法感兴趣。这就是我在我的 Diabelli 主题应用程序中所做的。它是 Swift,但我认为您阅读它不会有任何问题(如果您真的需要它,我确实有旧的 Objective-C 代码)。
很明显,我循环遍历了"tiles"要分割的图像。我已经计算出行数和列数,以及图块的大小,w
乘h
。原图为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
}
}
我能够通过切换到每个颜色分量和浮点分量 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;
}
这适用于上述所有设备。