【问题标题】:How to convert hex data to UIImage?如何将十六进制数据转换为 UIImage?
【发布时间】:2014-03-22 16:44:23
【问题描述】:

我喜欢在 UIImageView 中显示 .cpbitmap(它的文件格式 iOS 保存壁纸)。问题是我需要转换它。我已经弄清楚如果你得到它的数据(NSData)并转换你得到UIColor的每一位,所以第一个位是R,然后是B,然后是G,然后是Alpha(我认为)。现在我需要从信息中“绘制”一个 UIImage 。有人知道怎么做吗?

这里是 .cpbitmap 文件的链接:https://www.dropbox.com/s/s9v4lahixm9cuql/LockBackground.cpbitmap

如果有人可以帮助我,那就太好了,

谢谢

编辑 我找到了一个可以工作的 python 脚本,有人能把它翻译成 Objective

#!/usr/bin/python
from PIL import Image,ImageOps
import struct
import sys
if len(sys.argv) < 3:
    print "Need two args: filename and result_filename\n";
    sys.exit(0)
filename = sys.argv[1]
result_filename = sys.argv[2]

with open(filename) as f:
    contents = f.read()
    unk1, width, height, unk2, unk3, unk4 = struct.unpack('<6i', contents[-24:])
    im = Image.fromstring('RGBA', (width,height), contents, 'raw', 'RGBA', 0, 1)
    r,g,b,a = im.split()
    im = Image.merge('RGBA', (b,g,r,a))
    im.save(result_filename)

【问题讨论】:

  • 你如何识别图像的分辨率?是预定义的吗?
  • 你是指身高和搭配吗?它的高度和设备的高度相同。
  • 我首先被非标准的图像尺寸所迷惑,但我猜是因为UIMotionEffect渲染的视差效果,尺寸会比物理设备尺寸大(所以作为图像变化,有东西要显示)。凭经验发现大小为 744x1392,我注意到在文件末尾,我可以看到编码在其中的那些尺寸,0x2E8 (744) 和 0x570 (1392)。我不确定您将如何以编程方式提取该数据。 (这不是NSKeyedArchiver,我通常将其与bplist联系起来。)

标签: objective-c bitmap uiimage


【解决方案1】:

将RGBA数据转换为图像的基本过程是用原始数据创建CGDataProviderRef,然后使用CGImageCreate创建CGImageRef,从中可以轻松生成UIImage。所以,这给了你类似的东西:

- (UIImage *) imageForBitmapData:(NSData *)data size:(CGSize)size
{
    void *          bitmapData;
    CGColorSpaceRef colorSpace        = CGColorSpaceCreateDeviceRGB();
    int             bitmapBytesPerRow = (size.width * 4);
    int             bitmapByteCount   = (bitmapBytesPerRow * size.height);

    bitmapData = malloc( bitmapByteCount );
    NSAssert(bitmapData, @"Unable to create buffer");

    [data getBytes:bitmapData length:bitmapByteCount];

    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bitmapData, bitmapByteCount, releasePixels);

    CGImageRef imageRef = CGImageCreate(size.width,
                                        size.height,
                                        8,
                                        32,
                                        bitmapBytesPerRow,
                                        colorSpace,
                                        (CGBitmapInfo)kCGImageAlphaLast,
                                        provider,
                                        NULL,
                                        NO,
                                        kCGRenderingIntentDefault);

    UIImage *image = [UIImage imageWithCGImage:imageRef];

    CGImageRelease(imageRef);
    CGColorSpaceRelease(colorSpace);
    CGDataProviderRelease(provider);

    return image;
}

releasePixels 函数定义如下:

void releasePixels(void *info, const void *data, size_t size)
{
    free((void*)data);
}

唯一的技巧是识别位图的尺寸。有 4,142,592 字节的图像数据(文件末尾有一些额外的东西,如果你在 Xcode 中检查十六进制文件,这是不言而喻的)。这与任何标准设备尺寸无关。但是,如果您查看平均分为 4,142,592 的可能值,您会得到一些有希望的值(496、522、558、576、696、744、899、928 和 992)。如果你只是尝试一下,很明显图像是 744 x 1392。

然后您可以通过上述方法使用这些尺寸,并获得您的图像。


虽然我凭经验发现了图像的大小,但我注意到这些尺寸是在文件末尾编码的。您的 Python 代码证实了这一点,这表明图像宽度是倒数第二个UInt32,高度是倒数第四个UInt32。因此,您可以像这样使用上述例程,从文件末尾附近编码的两个 32 位整数中提取维度:

NSString *path = [[NSBundle mainBundle] pathForResource:@"LockBackground" ofType:@"cpbitmap"];
NSData *data = [NSData dataWithContentsOfFile:path];
NSAssert(data, @"no data found");

UInt32 width;
UInt32 height;
[data getBytes:&width  range:NSMakeRange([data length] - sizeof(UInt32) * 5, sizeof(UInt32))];
[data getBytes:&height range:NSMakeRange([data length] - sizeof(UInt32) * 4, sizeof(UInt32))];

self.imageView.image = [self imageForBitmapData:data size:CGSizeMake(width, height)];

【讨论】:

  • 您好,您的代码对我来说并不适用。为什么我需要图像的高度和宽度? python工具可以在不知道高宽的情况下做到。
  • 好的,我现在有一个有趣的问题要问你。它只适用于 iOS 模拟器,不适用于真正的 iOS 设备,你知道为什么吗,因为我没有一个想法。该文件是可读的(它现在位于设备文档目录中,与模拟器中的文件相同)。你是在 iOS 模拟器上还是在真实的 iOS 设备上测试过?
  • 我修复了它。如果您删除 'free(bitmapData);',一切都会正常工作
  • @DavidG。我的错。我试图通过删除releasePixels 清理功能并立即释放内存来简化我的示例(假设imageWithCGImage 会复制图像数据)。那是个坏主意,我已经恢复到使用CGDataProviderCreateWithData 的最后一个参数的再现。请注意,如果您只是删除了free(),而没有类似releasePixels 的功能,您的应用程序将会泄漏。无论如何,修改后的代码可以在模拟器和设备上运行。
  • 好的,我更新了我的代码。现在我想知道是否有办法反之亦然。我已经做了一些思考,但我无法想出一个好主意。
猜你喜欢
  • 1970-01-01
  • 2015-09-13
  • 2013-10-08
  • 2015-01-26
  • 1970-01-01
  • 2010-10-16
相关资源
最近更新 更多