“CGBitmapContextCreate:无效的数据字节/行”...为什么相机+过滤搞乱了我的图像裁剪程序?

时间:2012-08-10 18:59:23

标签: iphone ios uiimage cgbitmapcontextcreate

原始图片:enter image description here 已过滤的图片:enter image description here

我正在尝试将UIImages(手机相机胶卷中的照片)裁剪成方块。以下是我正在使用的代码的一部分,其中'image'是正在裁剪的图像:

if( image.size.height > image.size.width )
{
    dimension = image.size.width;
    imageRef = CGImageCreateWithImageInRect([image CGImage], CGRectMake((image.size.height-dimension)/2, 0, dimension, dimension));

如果我使用原始图片,此时看起来像这样:enter image description here

哪个好,我的期望 - 我有一个未在此处显示的旋转算法,可以对此进行排序。

如果我使用过滤后的图片,则如下所示:enter image description here

...不是方形裁剪,而是奇怪地放大了。 所以这似乎是问题所在,我不知道为什么这些过滤后的图像表现不同。

}
else
{
    dimension = image.size.height;
    imageRef = CGImageCreateWithImageInRect([image CGImage], CGRectMake((image.size.width-dimension)/2, 0, dimension, dimension));
}

CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);
CGContextRef bitmap;

bitmap = CGBitmapContextCreate(NULL, dimension, dimension, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

我的问题是,在最后一行, CGBitmapContextCreate ,我有时会收到以下错误:

<Error>: CGBitmapContextCreate: invalid data bytes/row: should be at least 7744 for 8 integer bits/component, 3 components, kCGImageAlphaNoneSkipLast.

奇怪的是,通常,这不会发生 - 到目前为止,我只遇到此错误,当原始图像的高度大于宽度时,它已被另一个应用程序过滤称为Camera + ...过滤之前完全相同的照片没有问题,过滤的风景照片似乎也没问题。

任何人都可以在这里指导我或帮我解释实际发生的事情吗?我从错误消息中了解到足够多,知道如果用一些高于7744的任意数字替换 CGImageGetBytesPerRow(imageRef),则错误不再发生,但是我对这个CGImage的东西不够了解知道实际上对任何东西有什么影响,而且在我看来并不像是一个实际的解决方案。此代码基于我在网络上看到的其他裁剪示例,因此我对这些位图函数的理解有限。

任何想法都会非常感激!

修改

我在SO上发现了这个问题:In this CGBitmapContextCreate, why is bytesPerRow 0?并且它促使我尝试将bytesPerRow参数设置为0.结果这消除了错误,但是我的裁剪例程在与当时相同的情况下无法正常工作这个错误之前发生过。这可能需要一个特殊的人来回答,但是有没有人对图像过滤有足够的了解,以便猜测为什么面向肖像,相机+过滤的照片在某种程度上被这个代码区别对待?我已经更新了标题,因为问题稍有改动。

EDIT2

我在上面的代码中添加了示例图像,最后,在任何必要的旋转之后,最终裁剪的图像如下所示:

原始图片:enter image description here - 完美!

带过滤后的图片:enter image description here - 糟糕!

用于创建这些最终的,应该裁剪的图像的代码是:

CGContextDrawImage(bitmap, CGRectMake(0, 0, dimension, dimension), imageRef);
CGImageRef ref = CGBitmapContextCreateImage(bitmap);
image = [UIImage imageWithCGImage:ref];
UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);

2 个答案:

答案 0 :(得分:2)

简而言之 - 由于某些原因,相机+过滤后的图片与原始图像的值不同imageOrientation。不知何故,这个事实导致了这样一条线:

imageRef = CGImageCreateWithImageInRect([image CGImage], CGRectMake((image.size.height-dimension)/2, 0, dimension, dimension));

根据imageOrientation的{​​{1}}行为不同。因此,虽然原始图像(其图像方向为)正在被此线旋转到其侧面(这就是我使用x偏移进行裁剪的原因)在纵向和横向尺寸中,滤镜图像的方向是向上。因此,我没有得到我预期的旋转,因此过滤后的图像被拉伸了。为了解决这个问题,我在调用image之前检查图像的方向,如果它是纵向大小但是向上方向,我使用y偏移而不是x(如David H在下面提到的代码行。

我的猜测是调用[图像CGImage]将图像旋转到相对的向上位置......所以如果方向是,图像会旋转90度逆时针方向,但如果方向向上,它根本不会旋转。我仍然不明白为什么过滤后的图像最终会采用与原始图像不同的方向,但我认为这只是相机+过滤代码中的某种副作用。所有这些定位的东西都可以简单得多,但这似乎是现在的解决方案。

答案 1 :(得分:1)

一些评论:

1)你想在除以2时舍入值的十六进制值,以便不得到一个小数像素边界(用户roundf())

2)你不处理两个尺寸相同的情况

3)在第一次创建中,你设置x偏移而不是y - 使用这条修改过的行:

imageRef = CGImageCreateWithImageInRect([image CGImage], CGRectMake(0, (image.size.height-dimension)/2, dimension, dimension));