2010-03-03 20 views
6

Tôi có một 322 bit32 bit có kênh alpha với giá trị 1 bit về cơ bản (các điểm ảnh bật hoặc tắt).Làm cách nào để tạo PNG 8 bit có độ trong suốt từ NSBitmapImageRep?

Tôi muốn lưu bitmap này vào tệp PNG 8 bit có độ trong suốt. Nếu tôi sử dụng phương thức -representationUsingType:properties: của NSBitmapImageRep và chuyển vào NSPNGFileType, một PNG 32 bit được tạo, không phải là thứ tôi muốn.

Tôi biết rằng PNG 8 bit có thể đọc được, chúng mở trong Xem trước không có vấn đề gì, nhưng có thể viết loại tệp PNG này bằng cách sử dụng bất kỳ API Mac OS X tích hợp nào không? Tôi rất vui khi được thả xuống Core Image hoặc thậm chí là QuickTime nếu cần. Việc kiểm tra lướt qua tài liệu CGImage không tiết lộ bất kỳ điều gì rõ ràng.

EDIT: Tôi đã bắt đầu một bounty về câu hỏi này, nếu ai đó có thể cung cấp mã nguồn làm việc mà phải mất một NSBitmapImageRep 32-bit và viết một 256-màu PNG với 1-bit minh bạch, nó là của bạn.

+0

8-bit bằng 256 màu? Tôi hy vọng bạn không có nhiều hơn 256 màu trong hình ảnh. Nếu bạn có thể có nhiều hơn 256 màu, bạn có thể muốn sử dụng pngnq (bundling nó trong ứng dụng của bạn và chạy nó với NSTask) thay vào đó: http://pngnq.sourceforge.net/ –

+0

Vâng, 256 màu. Tôi đang tìm một cái gì đó giống như đầu ra bằng cách sử dụng '-representationUsingType: properties' với' NSGIFFileType' ngoại trừ với một PNG 8-bit là đầu ra. pngnq là một lựa chọn (cảm ơn) nhưng tôi hy vọng sẽ xử lý nó mà không có các tác vụ sinh sản nếu có thể. –

Trả lời

1

pngnq (và new pngquant đạt chất lượng cao hơn) có giấy phép kiểu BSD, vì vậy bạn chỉ có thể đưa nó vào bạn chương trình r. Không cần đẻ trứng dưới dạng nhiệm vụ riêng biệt.

+0

Điều này thực sự hiệu quả và sửa lỗi vấn đề, cảm ơn. –

0

Một điều cần thử là tạo NSBitmapImageRep với 8 bit, sau đó sao chép dữ liệu vào đó.

Điều này thực sự sẽ có nhiều công việc, vì bạn sẽ phải tự tính toán bảng chỉ mục màu.

+0

Đúng. Đề xuất của Peter Hosey về cách sử dụng ** pngnq ** giải quyết vấn đề tạo bảng màu này khá độc đáo, mặc dù cần phải sinh ra một nhiệm vụ. –

2

Làm thế nào về pnglib? Nó rất nhẹ và dễ sử dụng.

+0

Điều này chắc chắn là một lựa chọn nhưng vì tôi đã không làm việc với 'pnglib' trước khi có rất nhiều học tập liên quan, tôi đã thực sự hy vọng cho một cái gì đó cao cấp hơn. –

+0

@Rob, không có nhiều học tập cho pnglib, nó thực sự khá đơn giản như xa như các thư viện C đi. Bạn có thể bị mắc kẹt vì một thứ khác, hầu hết các API cấp cao hơn giả định các trường hợp tổng quát hơn, thường có nghĩa là hình ảnh 24 hoặc 32 bpp. –

0

CGImageDestination là người của bạn viết hình ảnh mức độ thấp, nhưng tôi không biết liệu nó có hỗ trợ khả năng cụ thể đó hay không.

+0

Vâng, có vẻ như nó sẽ là câu trả lời nhưng cho đến nay tôi đã không thể tìm thấy một cách để xác định loại PNG để tạo ra, tất cả mọi thứ tôi cố gắng viết một PNG 32-bit. –

1

Một tham khảo tuyệt vời để làm việc với các API cấp thấp hơn là Programming With Quartz

Một số mã dưới đây dựa trên các ví dụ từ cuốn sách đó.

Lưu ý: Đây là un-kiểm tra mã có nghĩa là chỉ có một điểm khởi đầu ....

- (NSBitmapImageRep*)convertImageRep:(NSBitmapImageRep*)startingImage{ 

    CGImageRef anImage = [startingImage CGImage]; 

    CGContextRef bitmapContext; 
    CGRect ctxRect; 
    size_t bytesPerRow, width, height; 

    width = CGImageGetWidth(anImage); 
    height = CGImageGetHeight(anImage); 
    ctxRect = CGRectMake(0.0, 0.0, width, height); 
    bytesPerRow = (width * 4 + 63) & ~63; 
    bitmapData = calloc(bytesPerRow * height, 1); 
    bitmapContext = createRGBBitmapContext(width, height, TRUE); 
    CGContextDrawImage (bitmapContext, ctxRect, anImage); 

    //Now extract the image from the context 
    CGImageRef  bitmapImage = nil; 
    bitmapImage = CGBitmapContextCreateImage(bitmapContext); 
    if(!bitmapImage){ 
     fprintf(stderr, "Couldn't create the image!\n"); 
     return nil; 
    } 

    NSBitmapImageRep *newImage = [[NSBitmapImageRep alloc] initWithCGImage:bitmapImage]; 
    return newImage; 
} 

Context Creation Chức năng:

CGContextRef createRGBBitmapContext(size_t width, size_t height, Boolean needsTransparentBitmap) 
{ 
    CGContextRef context; 
    size_t bytesPerRow; 
    unsigned char *rasterData; 

    //minimum bytes per row is 4 bytes per sample * number of samples 
    bytesPerRow = width*4; 
    //round up to nearest multiple of 16. 
    bytesPerRow = COMPUTE_BEST_BYTES_PER_ROW(bytesPerRow); 

    int bitsPerComponent = 2; // to get 256 colors (2xRGBA) 

    //use function 'calloc' so memory is initialized to 0. 
    rasterData = calloc(1, bytesPerRow * height); 
    if(rasterData == NULL){ 
     fprintf(stderr, "Couldn't allocate the needed amount of memory!\n"); 
     return NULL; 
    } 

    // uses the generic calibrated RGB color space. 
    context = CGBitmapContextCreate(rasterData, width, height, bitsPerComponent, bytesPerRow, 
            CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), 
            (needsTransparentBitmap ? kCGImageAlphaPremultipliedFirst : 
            kCGImageAlphaNoneSkipFirst) 
            ); 
    if(context == NULL){ 
     free(rasterData); 
     fprintf(stderr, "Couldn't create the context!\n"); 
     return NULL; 
    } 

    //Either clear the rect or paint with opaque white, 
    if(needsTransparentBitmap){ 
     CGContextClearRect(context, CGRectMake(0, 0, width, height)); 
    }else{ 
     CGContextSaveGState(context); 
     CGContextSetFillColorWithColor(context, getRGBOpaqueWhiteColor()); 
     CGContextFillRect(context, CGRectMake(0, 0, width, height)); 
     CGContextRestoreGState(context); 
    } 
    return context; 
} 

Cách sử dụng sẽ là:

NSBitmapImageRep *startingImage; // assumed to be previously set. 
NSBitmapImageRep *endingImageRep = [self convertImageRep:startingImage]; 
// Write out as data 
NSData *outputData = [endingImageRep representationUsingType:NSPNGFileType properties:nil]; 
// somePath is set elsewhere 
[outputData writeToFile:somePath atomically:YES]; 
+0

Cảm ơn, điều này sẽ làm việc độc đáo để tạo bitmap nhưng nó không thực sự giải quyết vấn đề bằng cách viết một tệp PNG 8 bit 256 bit. –

+0

Xin lỗi, tôi đã rời bước đó. Tôi sẽ chỉnh sửa câu trả lời của mình để bao gồm hai cuộc gọi cần thiết. –

+0

Tôi đã xem xét điều này và theo "Định dạng pixel được hỗ trợ" trong Hướng dẫn lập trình 2D của Quartz, bạn không thể tạo ngữ cảnh RGB 8 bit, vì vậy mã này không thể hoạt động. Nếu bạn thử chạy nó, nó không tạo được ngữ cảnh do "kết hợp tham số không hợp lệ". http://developer.apple.com/mac/library/DOCUMENTATION/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html#//apple_ref/doc/uid/TP30001066-CH203-BCIBHHBB –