我的服务器加载的图片在 iPad 应用程序上颜色不正确

8

我正在开发一款iPad应用程序,用于展示摄影师的图片。这些照片被上传到一个Web服务器上,并通过应用程序直接提供服务,在使用以下方法下载并显示:

if([[NSFileManager defaultManager] fileExistsAtPath:[url path]]){
    CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)url, NULL);
    CGImageRef cgImage = nil;
    if(source){
        cgImage = CGImageSourceCreateImageAtIndex(source, 0, (CFDictionaryRef)dict);
    }

    UIImage *retImage = [UIImage imageWithCGImage:cgImage];

    if(cgImage){
        CGImageRelease(cgImage);
    }
    if(source){
        CFRelease(source);
    }

    return retImage;
}

我可以观察到照片的颜色显示在原始图片和iPad上有严重变化(从磁盘或Mac上的摄影师的Mac显示相同)。在iPad上(无论是在应用程序中还是在Safari中),结果都是错误的。经过一些搜索,我发现一些帖子解释了iDevices不使用嵌入式色彩配置文件,所以我发现我正在这样做。照片是使用以下信息保存的:

colorspace: RGB, colorprofile: sRGB iec...

我在一些文章中发现(例如这个链接来自imageoptimanalogsenses),我应该通过将图片转换为sRGB格式并不嵌入颜色配置文件来保存设备导出的图片,但我不知道该如何做?每次尝试时(我没有photoshop,因此我使用命令行ImageMagick),生成的图片具有以下信息,并且在我的iPad上(以及我测试过的任何其他iPad上)仍然无法正确显示:

colorspace: RGB

这是一个例子,图片在网页上可以正常显示,但在iPhone或iPad上却不能正确显示。

我希望能够将其转换为正确的显示方式,如果您有任何想法,都非常欢迎 :)

[编辑] 我已经成功使用Photoshop的“保存为Web”选项获得了正确的图像,使用以下参数: ok photoshop export parameters 但我仍然无法自动将这些设置应用于所有我的图片。


颜色没有改变,只是因为设备的Retina显示屏而出现了外观上的变化。 - aBilal17
3个回答

1

要读取一张图片,只需使用:

UIImage *image = [UIImage imageWithContentsOfFile:path];

关于颜色配置文件问题,尝试使用命令行工具sips来修复图像文件。可以尝试以下方式:
mkdir converted
sips -m "/System/Library/ColorSync/Profiles/sRGB Profile.icc" *.JPG --out converted

0

你可以通过CGImage先获取颜色空间。

@property(nonatomic, readonly) CGImageRef CGImage

CGColorSpaceRef CGImageGetColorSpace (
   CGImageRef image
);

根据颜色空间进行格式转换。因此,要获取图像的颜色空间,您需要执行以下操作:
CGColorSpaceRef colorspace = CGImageGetColorSpace([myUIImage CGImage]);

注意:确保遵循CG对象的获取/创建/复制规则。

颜色转换为RGB8(也可以应用于RGB16或RGB32,在方法newBitmapRGBA8ContextFromImage中更改每个组件的位数):

// Create a bitmap
unsigned char *bitmap = [ImageHelper convertUIImageToBitmapRGBA8:image];

    // Create a UIImage using the bitmap
UIImage *imageCopy = [ImageHelper convertBitmapRGBA8ToUIImage:bitmap withWidth:width withHeight:height];

    // Display the image copy on the GUI
UIImageView *imageView = [[UIImageView alloc] initWithImage:imageCopy];

ImageHelper.h

#import <Foundation/Foundation.h>


@interface ImageHelper : NSObject {

}

/** Converts a UIImage to RGBA8 bitmap.
 @param image - a UIImage to be converted
 @return a RGBA8 bitmap, or NULL if any memory allocation issues. Cleanup memory with free() when done.
 */
+ (unsigned char *) convertUIImageToBitmapRGBA8:(UIImage *)image;

/** A helper routine used to convert a RGBA8 to UIImage
 @return a new context that is owned by the caller
 */
+ (CGContextRef) newBitmapRGBA8ContextFromImage:(CGImageRef)image;


/** Converts a RGBA8 bitmap to a UIImage. 
 @param buffer - the RGBA8 unsigned char * bitmap
 @param width - the number of pixels wide
 @param height - the number of pixels tall
 @return a UIImage that is autoreleased or nil if memory allocation issues
 */
+ (UIImage *) convertBitmapRGBA8ToUIImage:(unsigned char *)buffer 
    withWidth:(int)width
    withHeight:(int)height;

@end

ImageHelper.m

#import "ImageHelper.h"


@implementation ImageHelper


+ (unsigned char *) convertUIImageToBitmapRGBA8:(UIImage *) image {

    CGImageRef imageRef = image.CGImage;

    // Create a bitmap context to draw the uiimage into
    CGContextRef context = [self newBitmapRGBA8ContextFromImage:imageRef];

    if(!context) {
        return NULL;
    }

    size_t width = CGImageGetWidth(imageRef);
    size_t height = CGImageGetHeight(imageRef);

    CGRect rect = CGRectMake(0, 0, width, height);

    // Draw image into the context to get the raw image data
    CGContextDrawImage(context, rect, imageRef);

    // Get a pointer to the data    
    unsigned char *bitmapData = (unsigned char *)CGBitmapContextGetData(context);

    // Copy the data and release the memory (return memory allocated with new)
    size_t bytesPerRow = CGBitmapContextGetBytesPerRow(context);
    size_t bufferLength = bytesPerRow * height;

    unsigned char *newBitmap = NULL;

    if(bitmapData) {
        newBitmap = (unsigned char *)malloc(sizeof(unsigned char) * bytesPerRow * height);

        if(newBitmap) { // Copy the data
            for(int i = 0; i < bufferLength; ++i) {
                newBitmap[i] = bitmapData[i];
            }
        }

        free(bitmapData);

    } else {
        NSLog(@"Error getting bitmap pixel data\n");
    }

    CGContextRelease(context);

    return newBitmap;   
}

+ (CGContextRef) newBitmapRGBA8ContextFromImage:(CGImageRef) image {
    CGContextRef context = NULL;
    CGColorSpaceRef colorSpace;
    uint32_t *bitmapData;

    size_t bitsPerPixel = 32;
    size_t bitsPerComponent = 8;
    size_t bytesPerPixel = bitsPerPixel / bitsPerComponent;

    size_t width = CGImageGetWidth(image);
    size_t height = CGImageGetHeight(image);

    size_t bytesPerRow = width * bytesPerPixel;
    size_t bufferLength = bytesPerRow * height;

    colorSpace = CGColorSpaceCreateDeviceRGB();

    if(!colorSpace) {
        NSLog(@"Error allocating color space RGB\n");
        return NULL;
    }

    // Allocate memory for image data
    bitmapData = (uint32_t *)malloc(bufferLength);

    if(!bitmapData) {
        NSLog(@"Error allocating memory for bitmap\n");
        CGColorSpaceRelease(colorSpace);
        return NULL;
    }

    //Create bitmap context

    context = CGBitmapContextCreate(bitmapData, 
            width, 
            height, 
            bitsPerComponent, 
            bytesPerRow, 
            colorSpace, 
            kCGImageAlphaPremultipliedLast);    // RGBA
    if(!context) {
        free(bitmapData);
        NSLog(@"Bitmap context not created");
    }

    CGColorSpaceRelease(colorSpace);

    return context; 
}

+ (UIImage *) convertBitmapRGBA8ToUIImage:(unsigned char *) buffer 
        withWidth:(int) width
       withHeight:(int) height {


    size_t bufferLength = width * height * 4;
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer, bufferLength, NULL);
    size_t bitsPerComponent = 8;
    size_t bitsPerPixel = 32;
    size_t bytesPerRow = 4 * width;

    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    if(colorSpaceRef == NULL) {
        NSLog(@"Error allocating color space");
        CGDataProviderRelease(provider);
        return nil;
    }

    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

    CGImageRef iref = CGImageCreate(width, 
                height, 
                bitsPerComponent, 
                bitsPerPixel, 
                bytesPerRow, 
                colorSpaceRef, 
                bitmapInfo, 
                provider,   // data provider
                NULL,       // decode
                YES,            // should interpolate
                renderingIntent);

    uint32_t* pixels = (uint32_t*)malloc(bufferLength);

    if(pixels == NULL) {
        NSLog(@"Error: Memory not allocated for bitmap");
        CGDataProviderRelease(provider);
        CGColorSpaceRelease(colorSpaceRef);
        CGImageRelease(iref);       
        return nil;
    }

    CGContextRef context = CGBitmapContextCreate(pixels, 
                 width, 
                 height, 
                 bitsPerComponent, 
                 bytesPerRow, 
                 colorSpaceRef, 
                 bitmapInfo); 

    if(context == NULL) {
        NSLog(@"Error context not created");
        free(pixels);
    }

    UIImage *image = nil;
    if(context) {

        CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), iref);

        CGImageRef imageRef = CGBitmapContextCreateImage(context);

        // Support both iPad 3.2 and iPhone 4 Retina displays with the correct scale
        if([UIImage respondsToSelector:@selector(imageWithCGImage:scale:orientation:)]) {
            float scale = [[UIScreen mainScreen] scale];
            image = [UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
        } else {
            image = [UIImage imageWithCGImage:imageRef];
        }

        CGImageRelease(imageRef);   
        CGContextRelease(context);  
    }

    CGColorSpaceRelease(colorSpaceRef);
    CGImageRelease(iref);
    CGDataProviderRelease(provider);

    if(pixels) {
        free(pixels);
    }   
    return image;
}

@end

0

@PhilippeAuriach 我认为你可能会遇到[UIImage imageWithCGImage:cgImage]的问题,我的建议是使用[UIImage imageWithContentsOfFile:path]代替上述方法。

以下代码可能会对你有所帮助。

if([[NSFileManager defaultManager] fileExistsAtPath:[url path]]){
    //Provide image path here...
    UIImage *image = [UIImage imageWithContentsOfFile:path];

    if(image){
        return image;
    }else{
       //Return default image
       return image;
    }
}

我已经尝试过了,但是什么也没改变,图像的颜色依然相同。 - PhilippeAuriach

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接