Преобразование NSData в CGImage и затем обратно в NSData делает файл слишком большим
Я построил камеру, используя AVFoundation
,
Однажды мой AVCaptureStillImageOutput
завершил captureStillImageAsynchronouslyFromConnection:completionHandler:
метод, я создаю объект NSData, как это:
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
Когда у меня есть NSData
объект, я хотел бы повернуть изображение без преобразования в UIImage
, Я узнал, что я могу преобразовать в CGImage
сделать это.
После того, как у меня есть imageData, я начинаю процесс преобразования в CGImage, но я обнаружил, что CGImageRef
заканчивается в тринадцать раз больше, чем NSData
объект.
Вот код, который я использую для преобразования в CGImage
от NSData
:
CGDataProviderRef imgDataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)(imageData));
CGImageRef imageRef = CGImageCreateWithJPEGDataProvider(imgDataProvider, NULL, true, kCGRenderingIntentDefault);
Если я попытаюсь NSLog
размер изображения достигает 30 мегабайт, когда NSData
было 1,5-2 мегабайта изображения!
size_t imageSize = CGImageGetBytesPerRow(imageRef) * CGImageGetHeight(imageRef);
NSLog(@"cgimage size = %zu",imageSize);
Я подумал, что, возможно, когда вы переходите от NSData к CGImage, изображение распаковывается, а затем, может быть, если я преобразую обратно в NSData, оно может вернуться к правильному размеру файла.
imageData = (NSData *) CFBridgingRelease(CGDataProviderCopyData(CGImageGetDataProvider(imageRef)));
Выше NSData
имеет то же самое length
как CGImageRef
объект.
Если я пытаюсь сохранить изображение, это изображение размером 30 Мб, которое нельзя открыть.
Я совершенно новичок в использовании CGImage, поэтому я не уверен, что я преобразовываю из NSData в CGImage и обратно неправильно, или мне нужно вызвать какой-то метод для распаковки снова.
Заранее спасибо,
Будет
2 ответа
Я делал некоторые манипуляции с изображениями и наткнулся на ваш вопрос о SO. Похоже, никто не придумал ответ, так что вот моя теория.
Хотя теоретически возможно преобразовать CGImageRef
вернуться к NSData
как вы описали, сами данные являются недействительными и не являются реальными JPEG или PNG, поскольку вы обнаружили, что они не читаются. Так что я не думаю, что NSData.length
верно. Вы должны прыгнуть через несколько шагов, чтобы воссоздать NSData
представление CGImageRef
:
// incoming image data
NSData *image;
// create the image ref
CGDataProviderRef imgDataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef) image);
CGImageRef imageRef = CGImageCreateWithJPEGDataProvider(imgDataProvider, NULL, true, kCGRenderingIntentDefault);
// image metadata properties (EXIF, GPS, TIFF, etc)
NSDictionary *properties;
// create the new output data
CFMutableDataRef newImageData = CFDataCreateMutable(NULL, 0);
// my code assumes JPEG type since the input is from the iOS device camera
CFStringRef type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef) @"image/jpg", kUTTypeImage);
// create the destination
CGImageDestinationRef destination = CGImageDestinationCreateWithData(newImageData, type, 1, NULL);
// add the image to the destination
CGImageDestinationAddImage(destination, imageRef, (__bridge CFDictionaryRef) properties);
// finalize the write
CGImageDestinationFinalize(destination);
// memory cleanup
CGDataProviderRelease(imgDataProvider);
CGImageRelease(imageRef);
CFRelease(type);
CFRelease(destination);
NSData *newImage = (__bridge_transfer NSData *)newImageData;
С этими шагами newImage.length
должен быть таким же, как image.length
, Я не проверял, так как я фактически делаю обрезку между входом и выходом, но в зависимости от кадрирования размер примерно соответствует ожидаемому (выход составляет примерно половину пикселей ввода, и, следовательно, длина вывода составляет примерно половину размера длины ввода).
если кто-то ищет быструю версию «Covert CGImage to Data», вот она:
extension CGImage {
var jpegData: Data? {
guard let mutableData = CFDataCreateMutable(nil, 0),
let destination = CGImageDestinationCreateWithData(mutableData, kUTTypeJPEG, 1, nil)
else {
return nil
}
CGImageDestinationAddImage(destination, self, nil)
guard CGImageDestinationFinalize(destination) else { return nil }
return mutableData as Data
}
}