CGBitmapContextCreate: недопустимые байты данных / строка, почему камера + фильтрация мешает моей процедуре обрезки изображения?

Исходное изображение: введите описание изображения здесьОтфильтрованное изображение:  введите описание изображения здесь

Я пытаюсь обрезать UIImages (фотографии в фотопленке телефона) на квадраты. Вот часть кода, который я использую, где «изображение» - это изображение, которое обрезается:

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

Если я использую исходное изображение, оно выглядит следующим образом: введите описание изображения здесь

Это нормально и чего я ожидаю - у меня есть алгоритм вращения, который здесь не показан.

Если я использую отфильтрованное изображение, оно выглядит так: введите описание изображения здесь

... не квадратная обрезка, а странное увеличение. Кажется, в этом и заключается проблема, и я не знаю, почему эти отфильтрованные изображения ведут себя по-другому.

}
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 +. ... та же самая фотография до фильтрации не вызывает проблем, и фильтрованная фотография пейзажа тоже кажется хорошей.

Может ли кто-нибудь направить меня сюда или помочь объяснить, что на самом деле происходит? Я достаточно понимаю из сообщения об ошибке, чтобы знать, что если я заменю CGImageGetBytesPerRow (imageRef) на произвольное число выше 7744, ошибка больше не возникает, но я недостаточно разбираюсь в этом материале CGImage, чтобы знать, какое влияние это на самом деле оказывает на что-либо, и мне это не кажется реальным решением. Этот код основан на других примерах обрезки, которые я видел в Интернете, поэтому мое понимание этих растровых функций ограничено.

Любые мысли были бы очень признательны!

ИЗМЕНИТЬ

Я нашел этот вопрос на SO: Почему в этом CGBitmapContextCreate bytesPerRow 0? и мне было предложено попробовать установить для параметра bytesPerRow значение 0. Оказывается, это устраняет ошибку, но моя процедура обрезки не работает должным образом в тех же ситуациях, когда эта ошибка возникала раньше. Для ответа на этот вопрос может потребоваться специальный человек, но разве кто-нибудь знает достаточно о фильтрации изображений, чтобы догадаться, почему портретно-ориентированные фотографии с фильтром камеры и камеры каким-либо образом обрабатываются этим кодом по-другому? Я обновил заголовок, так как вопрос немного изменился.

РЕДАКТИРОВАТЬ2

Я добавил примеры изображений в приведенный выше код, и, в конце концов, после любого необходимого поворота окончательные кадрированные изображения выглядят следующим образом:

с исходным изображением: введите описание изображения здесь- отлично!

с отфильтрованным изображением: введите описание изображения здесь- ужасно!

Код, который использовался для создания этих окончательных, предположительно обрезанных изображений, таков:

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

person cowfaboo    schedule 10.08.2012    source источник
comment
Можете ли вы опубликовать пример отфильтрованных изображений до и после?   -  person Adam B    schedule 11.08.2012
comment
Примеры изображений теперь размещены - второй набор изображений - это то место, где происходит странное поведение. Любое понимание, которое у вас есть, будет очень признательно.   -  person cowfaboo    schedule 14.08.2012


Ответы (2)


Короче говоря, камера + отфильтрованные изображения по какой-то причине поступают с другим значением imageOrientation, чем исходные изображения. Почему-то этот факт вызывает такую ​​строку:

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

вести себя по-разному в зависимости от imageOrientation из image. Итак, в то время как исходное изображение, ориентация которого была либо вправо, либо влево, было повернуто на бок по этой линии (вот почему я обрезал со смещением x как для книжной, так и для альбомной ориентации) отфильтрованное изображение имеет ориентацию вверх. Из-за этого у меня не получалось вращение, которое я ожидал, и поэтому отфильтрованные изображения растягивались. Чтобы решить эту проблему, я проверяю ориентацию изображения перед вызовом CGImageCreateWithImageInRect, и если оно имеет портретный размер, но имеет ориентацию вверх, я обрезаю со смещением y вместо x (например, строка кода Дэвид Х. упоминается ниже).

Я предполагаю, что вызов [image CGImage] поворачивает изображение в относительную позицию вверх ... поэтому, если ориентация вправо, изображение поворачивается на 90 градусов против часовой стрелки. , но если ориентация вверх, он вообще не поворачивается. Я до сих пор не понимаю, почему отфильтрованные изображения в конечном итоге имеют другую ориентацию, чем их оригиналы, но я предполагаю, что это просто своего рода побочный эффект в коде фильтрации камеры. Вся эта ориентация могла бы быть намного проще, но, похоже, на данный момент это решение.

person cowfaboo    schedule 14.08.2012

Несколько комментариев:

1) вы хотите округлить шестнадцатеричное значение значения при делении на 2, чтобы не попасть на границу дробных пикселей (пользователь roundf ())

2) Вы не относитесь к корпусу обоих размеров одинаково

3) при первом создании вы устанавливаете смещение по оси x, а не по оси y - используйте эту измененную строку:

imageRef = CGImageCreateWithImageInRect([image CGImage], CGRectMake(0, (image.size.height-dimension)/2, dimension, dimension));
person David H    schedule 11.08.2012
comment
Спасибо за ответ, Дэвид. На самом деле я занимаюсь случаем равных размеров, но я не стал включать его здесь, потому что это простой случай, который не способствует возникновению этой конкретной проблемы. Кроме того, я действительно устанавливаю смещение по оси x в обоих файлах по какой-то причине. Если вы посмотрите на опубликованные мной изображения, кажется, что CGImageCreateWithImageInRect набрасывает портретно-ориентированные изображения на свою сторону, и поэтому мне все равно приходится обрезать в направлении x, прежде чем повернуть полученное изображение обратно в его исходную ориентацию. Если у вас есть другие предложения, буду рад их выслушать. - person cowfaboo; 14.08.2012
comment
Думаю, я уже давал вам ответ раньше, но вы не меняли свой код. Если высота ›ширина, то вы собираетесь обрезать ось y, так что размер прямоугольника будет соответствовать ширине и будет смещение по оси y. Если верно обратное, то вы обрежете по высоте, и будет смещение по оси x. В вашем коде вы всегда применяете смещение к x. Растяжение, вероятно, связано с тем, что вы пытаетесь захватить прямоугольник из оригинала, который находится за пределами исходного изображения. - person David H; 14.08.2012
comment
Я понимаю, о чем вы говорите, и вы правы в том, что именно отсюда происходит растяжка. Однако, если бы я просто изменил свой код на то, что вы предлагаете, тогда только отфильтрованные изображения будут правильно обрезаны, а обычные изображения вместо этого будут растянуты. Остается вопрос, почему отфильтрованные изображения ведут себя иначе, чем нефильтрованные, и я обнаружил, что это связано с тем фактом, что отфильтрованные изображения поступают с другим свойством ориентации, чем нефильтрованные. Я объяснил это, и теперь, похоже, все работает. - person cowfaboo; 14.08.2012
comment
Были ли ширина и высота взяты из CGImageRef или UIImage? Я бы посоветовал вам использовать функции CGImageGet ... для получения размеров. Это должно быть фактическое растровое изображение. - person David H; 14.08.2012
comment
Мои измерения взяты из UIImage, и вы правы, это усложняет вещи, чем они должны быть. Проблема, кажется, теперь решена, но ее можно упростить, так что спасибо за это - теперь я определенно лучше понимаю, что происходит в этом коде. - person cowfaboo; 14.08.2012