NSImage к NSBitmapImageRep

Как преобразовать NSImage в NSBitmapImageRep? У меня есть код:

- (NSBitmapImageRep *)bitmapImageRepresentation
{
    NSBitmapImageRep *ret = (NSBitmapImageRep *)[self representations];

    if(![ret isKindOfClass:[NSBitmapImageRep class]])
    {
        ret = nil;
        for(NSBitmapImageRep *rep in [self representations])
            if([rep isKindOfClass:[NSBitmapImageRep class]])
            {
                ret = rep;
                break;
            }
    }

    if(ret == nil)
    {
        NSSize size = [self size];

        size_t width         = size.width;
        size_t height        = size.height;
        size_t bitsPerComp   = 32;
        size_t bytesPerPixel = (bitsPerComp / CHAR_BIT) * 4;
        size_t bytesPerRow   = bytesPerPixel * width;
        size_t totalBytes    = height * bytesPerRow;

        NSMutableData *data = [NSMutableData dataWithBytesNoCopy:calloc(totalBytes, 1) length:totalBytes freeWhenDone:YES];

        CGColorSpaceRef space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);

        CGContextRef ctx = CGBitmapContextCreate([data mutableBytes], width, height, bitsPerComp, bytesPerRow, CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), kCGBitmapFloatComponents | kCGImageAlphaPremultipliedLast);

        if(ctx != NULL)
        {
            [NSGraphicsContext saveGraphicsState];
            [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:[self isFlipped]]];

            [self drawAtPoint:NSZeroPoint fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];

            [NSGraphicsContext restoreGraphicsState];

            CGImageRef img = CGBitmapContextCreateImage(ctx);

            ret = [[NSBitmapImageRep alloc] initWithCGImage:img];
            [self addRepresentation:ret];

            CFRelease(img);
            CFRelease(space);

            CGContextRelease(ctx);
        }
    }


    return ret;
}

Это работает, но это вызывает утечки памяти. По крайней мере, когда я использую его с ARC. С помощьюinitWithData:[nsimagename TIFFRepresentation] это не работает правильно. Некоторые изображения не очень хороши. Я думаю, что это зависит от формата и цветового пространства изображения. Есть ли другие способы добиться этого?

Результат сmrwalker предлагаемое решение:

Исходное изображение:

Преобразован в bitmapimagerep и обратно к изображению 1 раз:

Преобразовано в bitmapimagerep и обратно в изображение 3 раза:

Как вы видите, изображение становится темнее каждый раз после преобразования в NSBitmapImageRep

 Mecki20 авг. 2018 г., 18:27
Вы выполняете некоторое преобразование цветового пространства, и преобразование цветового пространства обычно не без потерь, поскольку оно часто включает вычисления с плавающей запятой, которые впоследствии необходимо округлить до целочисленных значений. Со временем вы получаете все больше и больше ошибок округления. Ваш код слишком сложен, просто посмотрите здесь:stackoverflow.com/a/17510651/15809
 RickON05 янв. 2014 г., 11:18
Хоккей, у тебя все еще есть полное решение твоего вопроса? Я ищу способ определить цвета пикселей без особых усилий. Может быть, NSBitmapImageRep может мне как-то помочь. Благодарю.

Ответы на вопрос(3)

Решение Вопроса

адаптированный изМайка Эша "Получение и интерпретация данных изображения » Сообщение блога:

- (NSBitmapImageRep *)bitmapImageRepresentation {
  int width = [self size].width;
  int height = [self size].height;

  if(width < 1 || height < 1)
      return nil;

  NSBitmapImageRep *rep = [[NSBitmapImageRep alloc]
                           initWithBitmapDataPlanes: NULL
                           pixelsWide: width
                           pixelsHigh: height
                           bitsPerSample: 8
                           samplesPerPixel: 4
                           hasAlpha: YES
                           isPlanar: NO
                           colorSpaceName: NSDeviceRGBColorSpace
                           bytesPerRow: width * 4
                           bitsPerPixel: 32];

  NSGraphicsContext *ctx = [NSGraphicsContext graphicsContextWithBitmapImageRep: rep];
  [NSGraphicsContext saveGraphicsState];
  [NSGraphicsContext setCurrentContext: ctx];  
  [self drawAtPoint: NSZeroPoint fromRect: NSZeroRect operation: NSCompositeCopy fraction: 1.0];
  [ctx flushGraphics];
  [NSGraphicsContext restoreGraphicsState];

  return [rep autorelease];
}
 hockeyman16 окт. 2012 г., 09:04
Большое спасибо! :)
 mrwalker15 окт. 2012 г., 18:11
Являются ли результаты лучше, если вы используетеNSDeviceRGBColorSpace вместо ?NSCalibratedRGBColorSpace
 mrwalker16 окт. 2012 г., 10:24
Вы'Добро пожаловать Обновил мой ответ, чтобы использовать NSDeviceRGBColorSpace тоже.
 hockeyman15 окт. 2012 г., 16:58
Ну, этот метод работает, но не правильно. Возвращает представление с более темным изображением. Я'Добавлю пример к моему вопросу.

опоздал на вечеринку, но это версия Swift 3 из ответа @mrwalker:

extension NSImage {
    func bitmapImageRepresentation(colorSpaceName: String) -> NSBitmapImageRep? {
        let width = self.size.width
        let height = self.size.height

        if width < 1 || height < 1 {
            return nil
        }

        if let rep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(width), pixelsHigh: Int(height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: colorSpaceName, bytesPerRow: Int(width) * 4, bitsPerPixel: 32)
        {
            let ctx = NSGraphicsContext.init(bitmapImageRep: rep)
            NSGraphicsContext.saveGraphicsState()
            NSGraphicsContext.setCurrent(ctx)
            self.draw(at: NSZeroPoint, from: NSZeroRect, operation: NSCompositingOperation.copy, fraction: 1.0)
            ctx?.flushGraphics()
            NSGraphicsContext.restoreGraphicsState()
            return rep
        }
        return nil
    }
}

@Julius: Ваш код слишком сложен и содержит несколько ошибок.

- (NSBitmapImageRep *)bitmapImageRepresentation
{
   NSArray *ret =[self representations];
   for( NSImageRep *rep in [self representations] )
      if( [rep isKindOfClass:[NSBitmapImageRep class]] ) return rep;
   return nil;
}

Это извлечет первоеNSBitmapImageRep если он является членом в представлениях или вернет ноль, если нетNSBitmapImageRep, Я'дам вам другое решение, которое всегда будет работать независимоNSImageReps в представлении:,NSBitmapImageRepNSPDFImageRep или жеNSCGImageSnapshotRep или же ...

- (NSBitmapImageRep *)bitmapImageRepresentation
{
   CGImageRef CGImage = [self CGImageForProposedRect:nil context:nil hints:nil];
   return [[[NSBitmapImageRep alloc] initWithCGImage:CGImage] autorelease];
}

Или, чтобы избежать создания подклассов NSImage, вы можете написать:

NSImage *img = [[[NSImage alloc] initWithContentsOfFile:filename] autorelease];
CGImageRef CGImage = [img CGImageForProposedRect:nil context:nil hints:nil];
NSBitmapImageRep *rep = [[[NSBitmapImageRep alloc] initWithCGImage:CGImage] autorelease];

Это вернет только одинNSBitmapImageRep что может быть недостаточно хорошо, если изображение содержит более одного представления (например, многоNSBitmapImageRepиз файлов TIFF). Но добавить некоторый код просто.

 Brad Larson26 окт. 2012 г., 21:24
В качестве дополнительного предложения вы можете заменить второй[self representations] сret в итерации, потому что сейчасret не используется.
 Heinrich Giesen27 окт. 2012 г., 11:18
@Brad, хорошее предложение! Благодарю.

Ваш ответ на вопрос