NSImage теряет качество при writeToFile - PullRequest
0 голосов
/ 18 октября 2011

По сути, я пытаюсь создать программу для пакетной обработки изображений, которая будет изменять размер каждого изображения и добавлять границу вокруг края (граница также будет состоять из изображений). Хотя я еще не дошел до этой реализации, и это выходит за рамки моего вопроса, я задаю его, потому что, даже если я получу здесь хороший ответ, я все равно, возможно, выберу неправильный подход и помогу в признании этого. будет принята с благодарностью. Во всяком случае, вот мой вопрос:

Вопрос: Могу ли я взять существующий код, который у меня есть ниже, и изменить его для создания изображений более высокого качества, сохраненных в файл, чем код, который выводится в настоящее время? Я буквально потратил 10+ часов, пытаясь понять, что я делаю неправильно; «secondImage» перетянул высококачественное изображение с измененным размером в пользовательский вид, но все, что я пытался сделать, чтобы сохранить файл, привело к получению изображения значительно более низкого качества (не так сильно пикселизованного, просто заметно более размытого). Наконец, я нашел некоторый код в примере Apple «Reducer» (в конце ImageReducer.m), который блокирует фокус и получает NSBitmapImageRep из текущего представления. Это привело к значительному увеличению качества изображения на , однако вывод из Photoshop, выполняющий ту же самую операцию, был немного более четким. Похоже, что изображение, отображаемое в виде, имеет то же качество, что и сохраненное в файл, и поэтому оба качества ниже того же изображения в Photoshop, уменьшенном до 50%, как и это. Можно ли получить изображения с измененным размером более высокого качества, чем это?

Кроме того, как я могу изменить существующий код, чтобы иметь возможность контролировать качество изображения, сохраняемого в файл? Могу ли я изменить сжатие и плотность пикселей? Я был бы признателен за любую помощь с изменением моего кода или указанием мне хороших примеров или учебных пособий (желательно позже). Большое спасибо!

- (void)drawRect:(NSRect)rect {

// Getting source image
NSImage *image = [[NSImage alloc] initWithContentsOfFile: @"/Users/TheUser/Desktop/4.jpg"];

// Setting NSRect, which is how resizing is done in this example. Is there a better way?
NSRect halfSizeRect = NSMakeRect(0, 0, image.size.width * 0.5, image.size.height * 0.5);

// Sort of used as an offscreen image or palate to do drawing onto; the future I will use to group several images into one.
NSImage *secondaryImage = [[NSImage alloc] initWithSize: halfSizeRect.size];
[secondaryImage lockFocus];

[[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationHigh];

[image drawInRect: halfSizeRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0];

[secondaryImage unlockFocus];
[secondaryImage drawInRect: halfSizeRect fromRect: NSZeroRect   operation: NSCompositeSourceOver fraction: 1.0];

// Trying to add image quality options; does this usage even affect the final image?
NSBitmapImageRep *bip = nil;
bip = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide: secondaryImage.size.width pixelsHigh: secondaryImage.size.width bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:0 bitsPerPixel:0];

[secondaryImage addRepresentation: bip];

// Four lines below are from aforementioned "ImageReducer.m"
NSSize size = [secondaryImage size];
[secondaryImage lockFocus];
NSBitmapImageRep *bitmapImageRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0, 0, size.width, size.height)];
[secondaryImage unlockFocus];

NSDictionary *prop = [NSDictionary dictionaryWithObject: [NSNumber numberWithFloat: 1.0] forKey: NSImageCompressionFactor];
NSData *outputData = [bitmapImageRep representationUsingType:NSJPEGFileType properties: prop];
[outputData writeToFile:@"/Users/TheUser/Desktop/4_halfsize.jpg" atomically:NO];

// release from memory
[image release];    
[secondaryImage release];
[bitmapImageRep release];
[bip release];
}

Ответы [ 2 ]

0 голосов
/ 19 октября 2011

Наконец, один из тех "Ага!" моменты! Я попытался использовать тот же код в высококачественном файле .tif, и результирующее изображение было в 8 раз меньше (по размерам), а не на 50%, которые я сказал, чтобы сделать. Когда я попытался отобразить его, это изменило бы масштаб изображения, оно оказалось еще в 4 раза меньше оригинала, когда оно должно было отображаться с той же высотой и шириной. Я обнаружил, что неправильное восприятие NSSize из импортированного изображения. Ранее оно читало:

NSRect halfSizeRect = NSMakeRect(0, 0, image.size.width * 0.5, image.size.height * 0.5);

Где это должно быть:

NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData: [image TIFFRepresentation]];
NSRect halfSizeRect = NSMakeRect(0, 0, [imageRep pixelsWide]/2, [imageRep pixelsHigh]/2);

Очевидно, что это как-то связано с DPI и джазом, поэтому мне нужно было получить правильный размер из BitmapImageRep, а не из image.size. С этим изменением мне удалось сохранить качество, практически неотличимое от Photoshop.

0 голосов
/ 18 октября 2011

Я не уверен, почему вы спотыкаетесь на экран и обратно.Это может повлиять на результат, и в этом нет необходимости.

Вы можете выполнить все это, используя CGImage и CGBitmapContext, используя результирующее изображение для рисования на экране, если это необходимо.Я использовал эти API и получил хорошие результаты (но я не знаю, как они сравниваются с вашим текущим подходом).

Еще одно примечание: визуализируйте с более высоким качеством для промежуточного, затем измените размер и уменьшите до 8 бит / сверсия, которую вы пишете.Это не будет иметь существенного значения сейчас, но это будет (в большинстве случаев), как только вы введете фильтрацию.

...