Еще один вопрос по IKImageView:копирование региона
-
21-09-2019 - |
Вопрос
Я пытаюсь использовать функцию выбора и копирования IKImageView.Если все, что вам нужно, это иметь приложение с изображением, выбрать часть и скопировать ее в буфер обмена, это легко.Вы устанавливаете в меню копирования метод copy:(id) первого респондента, и все волшебным образом работает.
Однако, если вам нужно что-то более сложное, например, вы хотите скопировать как часть какой-либо другой операции, я не смогу найти способ сделать это.
У IKImageView, похоже, нет метода копирования, и, похоже, нет метода, который даже сообщал бы вам выбранный прямоугольник!
Я прочитал книгу Хиллегасса, поэтому понимаю, как работает буфер обмена, но не понимаю, как убрать часть изображения из поля зрения...
Теперь я начинаю думать, что допустил ошибку, взяв за основу IKImageView, но именно на нем построен Preview (по крайней мере, я так читал), поэтому я решил, что он должен быть стабильным...и вообще, теперь уже слишком поздно, я слишком увяз в этом, чтобы начинать все сначала...
Итак, кроме отсутствия использования IKImageView, есть ли какие-нибудь предложения о том, как вручную скопировать выбранную область в буфер обмена?
РЕДАКТИРОВАТЬ на самом деле я нашел метод copy(id), но когда я его вызываю, я получаю
<Error>: CGBitmapContextCreate: unsupported parameter combination: 8 integer bits/component; 16 bits/pixel; 1-component color space; kCGImageAlphaPremultipliedLast; 2624 bytes/row.
Чего, очевидно, не происходит, когда я делаю обычное копирование через службу экстренного реагирования...Я понимаю сообщение об ошибке, но не уверен, откуда оно берет эти параметры...
Есть ли способ проследить это и посмотреть, как это происходит?Отладчик не поможет по очевидным причинам, а также потому, что я делаю это в Mozilla, так что отладчик в любом случае не вариант...
РЕДАКТИРОВАТЬ 2 Мне приходит в голову, что найденный мной метод copy:(id) может копировать VIEW, а не копировать фрагмент изображения в буфер обмена, что мне и нужно.
Причина, по которой я подумал, что это копия из буфера обмена, заключается в том, что в другом проекте, где я копирую из IKImageView в буфер обмена прямо из меню редактирования, он просто отправляет копию: (id) в firstResponder, но я не на самом деле я уверен, что с этим сделает тот, кто первым ответит...
РЕДАКТИРОВАТЬ 3 Похоже, что ошибка CGBitmapContextCreate возникает из-за [imageView image]
что, как ни странно, ЯВЛЯЕТСЯ документированный метод.
Возможно, это происходит потому, что я помещаю туда изображение с помощью метода setImage:(id), передавая ему NSImage*...Есть ли другой, более умный способ поместить NSImage в IKImageView?
Решение
А -copy:
метод в IKImageView
делает то, что каждый второй -copy:
метод делает:он копирует текущий выбор в буфер обмена.Однако он реализован как частный метод в IKImageView
по какой-то причине.
Вы можете просто вызвать его напрямую:
[imageView copy:nil];
Это скопирует все, что выбрано в данный момент, в буфер обмена.
Я не думаю, что есть способ напрямую получить доступ к содержимому изображения текущего выделения в IKImageView
используя общедоступные методы, это хороший кандидат для отчета об ошибке/запроса функции.
Однако вы можете использовать частный метод -selectionRect
чтобы получить CGRect
текущего выделения и используйте его для извлечения выбранной части изображения:
//stop the compiler from complaining when we call a private method
@interface IKImageView (CompilerSTFU)
- (CGRect)selectionRect
@end
@implementation YourController
//imageView is an IBOutlet connected to your IKImageView
- (NSImage*)selectedImage
{
//get the current selection
CGRect selection = [imageView selectionRect];
//get the portion of the image that the selection defines
CGImageRef selectedImage = CGImageCreateWithImageInRect([imageView image],(CGRect)selection);
//convert it to an NSBitmapImageRep
NSBitmapImageRep* bitmap = [[[NSBitmapImageRep alloc] initWithCGImage:selectedImage] autorelease];
CGImageRelease(selectedImage);
//create an image from the bitmap data
NSImage* image = [[[NSImage alloc] initWithData:[bitmap TIFFRepresentation]] autorelease];
//in 10.6 you can skip converting to an NSBitmapImageRep by doing this:
//NSImage* image = [[NSImage alloc] initWithCGImage:selectedImage size:NSZeroSize];
return image;
}
@end
Другие советы
Итак, копия:nil терпит неудачу, и [imageView image] терпит неудачу, но оказывается, что у меня есть еще одна копия NSImage с того момента, когда я изначально добавил его в представление, так что я мог это сделать.Кроме того, CGImageCreateWithImageInRect ожидает CGImageRef, а не NSImage*, поэтому мне пришлось выполнить некоторые преобразования.
Кроме того, по какой-то причине прямоугольник выделения перевернут: либо он снизу, а изображение сверху, либо наоборот, поэтому пришлось его перевернуть.
И по какой-то причине компилятор внезапно начал жаловаться, что NSRect не того же типа, что и CGRect (что означает, что он внезапно перешел с 32-битного на 64-битное или что-то в этом роде...не знаю почему...)
В любом случае, вот моя копия selectedImage:
- (NSImage*)selectedImage
{
//get the current selection
CGRect selection = flipCGRect(imageView, [imageView selectionRect]);
//get the portion of the image that the selection defines
struct CGImage * full = [[doc currentImage] CGImageForProposedRect: NULL context: NULL hints: NULL];
CGImageRef selectedImage = CGImageCreateWithImageInRect( full, selection);
//convert it to an NSBitmapImageRep
NSBitmapImageRep* bitmap = [[[NSBitmapImageRep alloc] initWithCGImage:selectedImage] autorelease];
CGImageRelease(selectedImage);
// //create an image from the bitmap data
NSImage* image = [[[NSImage alloc] initWithData:[bitmap TIFFRepresentation]] autorelease];
// //in 10.6 you can skip converting to an NSBitmapImageRep by doing this:
//NSImage* image = [[NSImage alloc] initWithCGImage:selectedImage size:NSZeroSize];
return image;
}
Я написал FlipCGRect, и [doc currentImage] возвращает NSImage*...