2015-04-04 31 views
5

Załóżmy, że zaczynasz od UIImage i chcesz go przyciąć. Najpopularniejszą metodą jest użycie CGImageCreateWithImageInRect dostać CGImageRef i utworzyć nowy obraz z niej tak:Jak przekonwertować obiekt UIImage utworzony z CGImageRef na surowe dane iz powrotem

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

Teraz powiedzmy, że później trzeba konwertować te UIImage do obiektu NSData. Na przykład stanie się tak, jeśli chcesz zapisać obraz na dysku za pomocą NSKeyedArchiver. Albo można uzyskać NSData sprzeciwić się wykonując wyraźnie następuje:

NSData *imageData = UIImagePNGRepresentation(croppedImage); 

Zrobiłem to i później starałem się zrekonstruować nowego obiektu UIImage wykonując:

UIImage *image = [UIImage imageWithData:imageData]; 

Zrobiłem to dla seria 48 zdjęć. Większość z nich była w porządku, ale po każdych 4 zdjęciach kolejne 2 zostały uszkodzone z zamienionymi górnymi i dolnymi częściami każdego obrazu. Jeśli wyjmę konwersję na NSData iz powrotem, działa dobrze. Też mam ten sam problem, jeśli używam NSKeyedArchiver do zapisu tablicy obrazów na dysk (co, jak przypuszczam, wywołuje coś takiego jak UIImagePNGRepresentation w swojej procedurze kodowania). Moja teoria mówi, że to musi mieć coś wspólnego z tym, jak buduję obrazy z CGImageRefs.

Co to jest obejście tego problemu? Nie mogę się domyślić, jak umieścić CGImageRefs w obiekcie NSData i wolałbym rozwiązanie, które poprawnie zbuduje UIImage, aby mogło być serializowane.

Edit:

Niektórzy ludzie pytali o rzeczywisty kod uruchomiony, więc dodaję tutaj

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); 
    } 
} 

Obraz z self.animationObject.image ma siatki i obrazów z numInX i NUMINY zdjęć w każdym kierunku. Odcinam poszczególne obrazy z siatki 2D i zapisuję je.

Później umieszczam obrazy w widoku obrazu, aby je ożywiać. Oto kod:

 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]; 
    } 

To wszystko działa dobrze na iPhone 6, ale nie działa na iPhone 5. Wydaje się również, aby być tylko problem gdy siatka obrazów jest długa. Na przykład dla przykładu używam self.animationObject.image ma numInY jako 3 i numInX 2, a całkowity rozmiar obrazu to 1536x3072 (każdy mini-obraz to 768 x 1024). To są dwa dolne obrazy, które mają odwrócone szczyty i dna.

+0

Niektóre bardziej użytecznych szczegółów. Mam złożone obrazy, z których każda zawiera 6 mniejszych obrazów w siatce 2x3. Rozmiar każdego obrazu to 768 x 1024, więc całkowity rozmiar złożonego obrazu to 1536 x 3072. Jest to 5. i 6. obraz w każdym kompozycie, które mają zamienioną dolną i górną połówkę. Czy jest coś dziwnego w CGImage, które wynika z przycięcia do dolnej części dużego obrazu? Ponownie powinienem wspomnieć, że działa to doskonale, jeśli UIImage nie jest konwertowany na NSData, a następnie z powrotem. – Mike

+0

Tak więc w powyższym przykładzie szerokość wynosi 768, wysokość 1024 i łamie się, gdy x wynosi 0 lub 1, a y 2. Działa to dobrze, gdy y wynosi 0 lub 1. Czy jest to przypadek, w którym CGImageCreateWithImageInRect po prostu nie może sobie poradzić obrazy tak duże? – Mike

+0

Trudno dostrzec, co może być przyczyną tego. Proponuję zapakowanie tego jako aplikacji testowej i wypełnienie radaru na stronie bugreporter.apple.com. Lub jeśli masz do czynienia z incydentem DTS, uruchom go przez nich w nadziei na obejście. –

Odpowiedz

0

Problem wynika z orientacji obrazu.
Każda właściwość UII zawiera właściwość -imageOrientation, która definiuje orientację, która ma zostać zastosowana na wyświetlonym ekranie, gdy użytkownik poprosi o utratę tej informacji.
Jeśli otrzymasz obraz z kamery wewnątrz dostarczonego słownika metadanych, istnieje również orientacja EXIF, więc zależy to od tego, skąd pochodzą dane.
Na moim blogu napisałem o tym article oraz o tym, jak postępować z nimi prawidłowo, jeśli obraz pochodzi z aparatu.
Szybkim rozwiązaniem może być odczytanie właściwości CGImage i zastosowanie transformacji zgodnie z właściwością -imageOrientation. Można znaleźć różne sposoby, here i here

Ten fragment pochodzi z here kredyty do 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

Nie jestem pewien, dlaczego problem dotyczy orientacji obrazu? Żadne z obrazów, które widziałem nie zostały w ogóle zmienione. Wszystko było we właściwej orientacji. Tylko niektóre z nich zostały zamienione. Przetestuję twoje rozwiązanie i zobaczę, czy to pomaga. – Mike

+0

Nie jestem również pewien, ale nigdy nie doświadczyłem zmiany rotacji podczas zapisywania obrazów na dysku, które nie były z tego powodu. Powiedziałeś, że twoje obrazy zostały obrócone, to wykształcone przypuszczenie. UIimageView bierze pod uwagę rotację, jeśli stwierdzi, że różni się od domyślnej UIImageRotationUp, więc zobaczy wszystko poprawnie na ekranie, ale CGImage nie ma atrybutu obrotu, dlatego widzisz trochę w innej orientacji. Prostszym sposobem byłoby wydrukowanie właściwości -imageOrientationProperty każdej jednostki UII, jeśli zobaczysz coś innego niż UIImageOrientationUp, to będzie problem. – Andrea