代码之家  ›  专栏  ›  技术社区  ›  Rob Keniger

如何从nsbitmapImagerep创建具有透明度的8位PNG?

  •  6
  • Rob Keniger  · 技术社区  · 16 年前

    我有32位 NSBitmapImageRep 它有一个基本上是1位值的alpha通道(像素是开还是关)。

    我想将这个位图保存到一个具有透明度的8位PNG文件中。如果我使用 -representationUsingType:properties: 方法 nsbitmapimagerep 并通过 NSPNGFileType ,将创建一个32位PNG,这不是我想要的。

    我知道8位PNG可以读取,它们在预览中打开时没有问题,但是是否可以使用任何内置的Mac OS X API来编写这种类型的PNG文件?如果必要的话,我很乐意去看看核心图片,甚至是QuickTime。粗略的检查 CGImage 医生没有透露任何明显的信息。

    编辑: 如果有人能提供一个32位的工作源代码,我已经开始对这个问题慷慨相助。 nsbitmapimagerep 写一个256色的PNG,1位透明,这是你的。

    5 回复  |  直到 14 年前
        1
  •  1
  •   Kornel    14 年前

    PNGNQ(及 new pngquant 它实现了更高的质量)有BSD风格的许可证,所以您可以将其包含在您的程序中。无需作为单独任务生成。

        2
  •  2
  •   Carl Norum    16 年前

    怎么样 pnglib ?它非常轻,使用方便。

        3
  •  1
  •   Chip Coons    16 年前

    使用低级API的一个很好的参考是 Programming With Quartz

    下面的一些代码是基于那本书中的示例。

    注意:这是未经测试的代码,仅作为起点。

    - (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;
    }
    

    上下文创建函数:

    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;
    }
    

    用途是:

    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];
    
        4
  •  0
  •   cobbal    16 年前

    要尝试的一件事是用8位创建一个nsbitmapImagerep,然后将数据复制到它。

    这实际上需要做很多工作,因为您必须自己计算颜色索引表。

        5
  •  0
  •   Mike Abdullah    16 年前

    CGImageDestination 是你的低层次形象写作的人,但我不知道它是否支持这种特定的能力。