2015-04-04 1 views
5

Предположим, вы начинаете с UIImage, и вы хотите его обрезать. Наиболее распространенным методом является использование CGImageCreateWithImageInRect, чтобы получить CGImageRef и создать новый образ из него, как так:Как преобразовать объект UIImage, созданный из CGImageRef, в необработанные данные и обратно

CGRect cropRect = CGRectMake(x*width, y*height, width, height); 
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect); 
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef]; 

Теперь предположим, что вы позже должны преобразовать этот UIImage в объект NSData. Например, это произойдет, если вы хотите сохранить изображение на диске с помощью NSKeyedArchiver. Или вы можете получить NSData объект вне, выполнив следующие действия в явном виде:

NSData *imageData = UIImagePNGRepresentation(croppedImage); 

Я сделал это, и позже я попытался реконструировать новый объект UIImage, выполнив:

UIImage *image = [UIImage imageWithData:imageData]; 

Я сделал это для серия из 48 изображений. Большинство из них были прекрасны, но после каждых 4 изображений следующие 2 были повреждены сверху и снизу каждого изображения. Если я вывожу конверсию в NSData и обратно, она работает нормально. Я также получаю ту же самую проблему, если я использую NSKeyedArchiver для записи массива изображений на диск (который, как я предполагаю, вызывает в UImagePNGRпредставлении в своей процедуре кодирования). Моя теория заключается в том, что это должно иметь какое-то отношение к тому, как я создаю изображения из CGImageRefs.

Каково обходное решение для этого? Я не могу понять, как поставить объект CGImageRefs в объект NSData, и я предпочел бы решение, которое правильно построит UIImage, чтобы оно могло быть сериализовано.

Edit:

Некоторые люди просили фактический код запускаемых, поэтому я добавляю его здесь

UIImage *image = self.animationObject.image; 
for (int y=0; y<[self.animationInfoObject.numInY intValue]; y++) { 
    for (int x=0; x<[self.animationInfoObject.numInX intValue]; x++) { 
     CGRect cropRect = CGRectMake(x*width, y*height, width, height); 
     CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect); 
     UIImage *croppedImage = [UIImage imageWithCGImage:imageRef]; 
     NSData *imageData = UIImageJPEGRepresentation(croppedImage, 1.0); 
     [self addImageToArray:imageData]; 
     CFRelease(imageRef); 
    } 
} 

Изображение из self.animationObject.image сетки изображений с numInX и и числовые изображения в каждом направлении. Я обрезаю каждое отдельное изображение из 2D-сетки и сохраняю их.

Позже я поместил изображения в изображение, чтобы оживить их. Вот код:

 NSMutableArray *animationArray = [[NSMutableArray alloc] init]; 
    for (int frame=0; frame<[[photoObject frameArray] count]; frame++) { 
     NSData *imageData =[[photoObject imageArray] objectAtIndex:[[[photoObject frameArray] objectAtIndex:frame] integerValue]-1]; 
     UIImage *image = [UIImage imageWithData:imageData]; 
     [animationArray addObject:image]; 
    } 

Это все работает отлично на iPhone 6, но не работает на iPhone 5. Кроме того, кажется, только проблема, когда сетка изображений долго. Например, для примера я использую self.animationObject.image имеет numInY как 3 и numInX 2, а общий размер изображения - 1536x3072 (каждое мини-изображение 768x1024). Это два нижних изображения, которые имеют верх и низ.

+0

Некоторые более полезные детали. У меня есть составные изображения, каждая из которых содержит 6 меньших изображений в сетке 2x3. Размер каждого изображения составляет 768x1024, поэтому общий размер составного изображения составляет 1536x3072. Это 5-й и 6-й изображения в каждом композите, которые имеют нижнюю и верхнюю половинки. Итак, что-то странное в CGImage, которое, возможно, связано с обрезкой до нижней части большого изображения? Опять же, я должен упомянуть, что это работает отлично, если UIImage не преобразован в NSData, а затем обратно. – Mike

+0

Итак, в этом примере выше ширина 768, высота 1024 и разрывается, когда x равно 0 или 1, а y равно 2. Оно отлично работает, когда y равно 0 или 1. Это случай, когда CGImageCreateWithImageInRect просто не может справиться с большие изображения? – Mike

+0

Его трудно понять, что может быть причиной этого. Я предлагаю упаковать это как тестовое приложение и подать радар на bugreporter.apple.com. Или, если у вас есть случай с DTS, чтобы сэкономить, запустите его в надежде на обход. –

ответ

0

Проблема связана с ориентацией изображения.
Каждый UIImage содержит свойство -imageOrientation, которое определяет ориентацию, которая должна быть применена на UIImage после отображения на экране, когда вы запрашиваете CGImage, вы потеряли эту информацию.
Если вы получаете изображение с камеры внутри предоставленного словаря метаданных, есть также ориентация EXIF, поэтому его зависимость зависит от того, откуда поступают данные.
В моем блоге я написал article об этом и как правильно обрабатывать их, если изображение поступает с камеры.
Быстрое решение может быть прочитано свойство CGImage и применить преобразование в соответствии с свойством -imageOrientation. Вы можете найти различные способы, here и here

Этот фрагмент взят из here, вменяет Awolf

- (UIImage *)croppedImageInRect:(CGRect)rect 
{ 
    double (^rad)(double) = ^(double deg) { 
     return deg/180.0 * M_PI; 
    }; 

    CGAffineTransform rectTransform; 
    switch (self.imageOrientation) { 
     case UIImageOrientationLeft: 
      rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(90)), 0, -self.size.height); 
      break; 
     case UIImageOrientationRight: 
      rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-90)), -self.size.width, 0); 
      break; 
     case UIImageOrientationDown: 
      rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-180)), -self.size.width, -self.size.height); 
      break; 
     default: 
      rectTransform = CGAffineTransformIdentity; 
    }; 
    rectTransform = CGAffineTransformScale(rectTransform, self.scale, self.scale); 

    CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], CGRectApplyAffineTransform(rect, rectTransform)); 
    UIImage *result = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation]; 
    CGImageRelease(imageRef); 

    return result; 
} 
+0

Я не уверен, почему ориентация изображения будет проблемой? Ни один из изображений, которые я видел, вообще не вращался. Все было в правильной ориентации. Просто их часть была заменена. Я проверю ваше решение и посмотрю, поможет ли оно. – Mike

+0

Я тоже не уверен, но я никогда не испытывал изменения во время сохранения изображений на диске, которые не были из-за этого. Вы сказали, что ваши изображения повернуты, это просвещенная догадка. UIimageView учитывает поворот, если он обнаруживает, что отличается от UIImageRotationUp по умолчанию, поэтому он увидит все, что соответствует на экране, но CGImage не имеет атрибута вращения, поэтому вы видите его в разных ориентациях. И проще будет напечатать -imageOrientationProperty каждого UIImage, если вы увидите что-то другое, чем UIImageOrientationUp, это будет проблемой. – Andrea

Смежные вопросы