【问题标题】:Create UIImage from Leptonica's Pix structure从 Leptonica 的 Pix 结构创建 UIImage
【发布时间】:2012-01-26 03:00:52
【问题描述】:

我想在我的 iOS 应用中使用 Leptonica 库来处理图像。

有人知道我如何从 Leptonica 的 Pix 结构中的原始数据创建 UIImage

/*-------------------------------------------------------------------------*
 *                              Basic Pix                                  *
 *-------------------------------------------------------------------------*/
struct Pix
{
    l_uint32             w;           /* width in pixels                   */
    l_uint32             h;           /* height in pixels                  */
    l_uint32             d;           /* depth in bits                     */
    l_uint32             wpl;         /* 32-bit words/line                 */
    l_uint32             refcount;    /* reference count (1 if no clones)  */
    l_int32              xres;        /* image res (ppi) in x direction    */
                                      /* (use 0 if unknown)                */
    l_int32              yres;        /* image res (ppi) in y direction    */
                                      /* (use 0 if unknown)                */
    l_int32              informat;    /* input file format, IFF_*          */
    char                *text;        /* text string associated with pix   */
    struct PixColormap  *colormap;    /* colormap (may be null)            */
    l_uint32            *data;        /* the image data                    */
};
typedef struct Pix PIX;

?

谢谢!

【问题讨论】:

    标签: objective-c ios uiimage pix


    【解决方案1】:

    首先,您可能想查看:Convert Leptonica Pix Object to QPixmap ( or other image object )

    我们想要的是找到 Pix 和 UIImage 都支持的通用格式,从 Pix 转换为该通用格式,然后从通用格式转换为 UIImage。

    通过查看 Leptonica 库,似乎支持的常见格式是 GIF、JPEG、TIFF、BMP 和 PNG。 JPEG 将是有损的,GIF 和 PNG 都会导致 CPU 的额外工作(当我们从 Pix 转换为 UIImage 时会有额外的编码/解码周期)。由于这些原因,我在下面的示例中选择了 TIFF。如果它不起作用,我会选择 PNG。

    计划如下:

    • 1) 从 Pix 转换为字节缓冲区
    • 2) 获取字节缓冲区并将其存储到 NSData 中
    • 3) 将该数据传递给 NSImage

    看起来 pixWriteMem() 函数是我们 #1 所需要的(前提是对它的支持已编译到库中)。

    从库中包含的示例代码来看,我们似乎负责释放 pixWriteMem() 的输出 - 因此,我们将 YES 传递给 NSData 的 freeWhenDone: 参数。

    类似这样的东西(警告:未经测试的代码):

    UIImage *GetImageFromPix(Pix *thePix)
    {
        UIImage *result = nil;
    
        l_uint8 *bytes = NULL;
        size_t size = 0;
    
        if (0 == pixWriteMem(&bytes, &size, thePix, IFF_TIFF)) {
            NSData *data = [[NSData alloc] initWithBytesNoCopy:bytes length:(NSUInteger)size freeWhenDone:YES];
            result = [UIImage imageWithData:data];
            [data release];
        }
    
        return result;
    }
    

    【讨论】:

    • 非常感谢您的回答。但是,我的 Leptonica 版本似乎是在不支持 pixWrite... 函数的情况下编译的。我是对的,要在支持这些函数的情况下编译它,我应该做类似./configure --with-libtiff=../libtiff/out 然后重新编译它?
    • 是的,看起来您需要使用 libtiff 重新配置。但是,在阅读 Leptonica 中的 README 后:“Leptonica 还允许使用 bmp 和 pnm 格式的图像 I/O,我们为此提供了序列化程序......”,因为 UIImage initWithData: 应该支持 BMP,你可以试试看是否作品。将 IFF_TIFF 更改为 IFF_BMP 看看会发生什么
    • 这很奇怪,但似乎在i386和armv7平台上都没有实现这个功能-它显示Error in pixWriteMemBmp: bmp write to memory not implemented on this platform消息。
    • 我在 leptonica 的源 (tpgit.github.com/Leptonica/environ_8h_source.html#l00114) 中找到了这个:On linux systems, you can do I/O between Pix and memory. Specifically, you can compress (write compressed data to memory from a Pix) and uncompress (read from compressed data in memory to a Pix). For jpeg, png, pnm and bmp, these use the non-posix GNU functions fmemopen() and open_memstream(). These functions are not available on other systems. To use these functions in linux, you must define HAVE_FMEMOPEN to be 1 here.。所以,似乎只能用 libtiff 编译它。
    • 好吧,即使你使用 libtiff 构建,我认为 pixWriteMem...() 函数都需要 fmemopen(),所以你可能仍然会收到错误。您需要多久转换一次?您可能必须将 pix 写入 tmp 文件,然后使用 UIImage 将其读回(不理想,但如果它是不频繁的操作,则不是世界末日)
    【解决方案2】:

    写入中间文件格式。并读回,是一种简单但低效的方法,用于将 Pix 内存数据结构转换为 UIImage 数据结构(或内存中图像的许多容器中的任何其他容器)。

    如果中间文件表示被压缩(例如 png),则计算效率特别低,因为图像数据在写出之前必须经过压缩,并在读回之后解压缩到未压缩的栅格。

    struct Pix 转换为 struct X 的有效方法是填写 X 中的元数据字段(图像大小、深度、分辨率、文本等) ),如果图像被颜色映射,则为 struct X 生成颜色映射,并将图像光栅数据从 Pix 约定转换为 X 约定。最后一个是唯一棘手的部分,因为您需要为两个内存中的光栅表示中的每一个考虑以下内容:

    (1) 栅格线的填充(Pix 填充为 4 个字节)
    (2)多分量像素的存储(Pix在每个像素内按顺序存储各个分量)
    (3) 3分量像素的大小,如rgb(Pix使用4字节:rgba)
    (4) 多字节像素的字节顺序(Pix 使用确定 rgba 字节顺序的宏)
    (5) 像素顺序:对于 Pix,在图像中从左到右,它们在每个 32 位字中按照从 MSB 到 LSB 的顺序存储

    结构 Pix 的规范在 leptonica src 文件 pix.h 中给出。

    【讨论】:

      【解决方案3】:

      这里是一个实现(32 bpp -> UIImage)

      - (UIImage *)imageFromPix:(Pix *)pix
      {
          l_uint32 width = pixGetWidth(pix);
          l_uint32 height = pixGetHeight(pix);
          l_uint32 bitsPerPixel = pixGetDepth(pix);
          l_uint32 bytesPerRow = pixGetWpl(pix) * 4;
          l_uint32 bitsPerComponent = 8;
          if (pixSetSpp(pix, 4) == 0) {
              bitsPerComponent = bitsPerPixel / pixGetSpp(pix);
          }
      
          l_uint32 *pixData = pixGetData(pix);
      
          CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixData, bytesPerRow * height, NULL);
          CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
      
          CGImage *cgImage = CGImageCreate(width, height,
                                           bitsPerComponent, bitsPerPixel, bytesPerRow,
                                           colorSpace, kCGBitmapByteOrderDefault,
                                           provider, NULL, NO, kCGRenderingIntentDefault);
      
          CGDataProviderRelease(provider);
          CGColorSpaceRelease(colorSpace);
      
          UIImage *image = [UIImage imageWithCGImage:cgImage];
          return image;
      }
      

      如果要转换 1 bpp 图像(例如阈值)

      - (UIImage *)imageFrom1bppPix:(Pix *)pix
      {
          Pix *pix32 = pixUnpackBinary(pix, 32, 0);
      
          UIImage *image = [self imageFromPix:pix32];
      
          pixDestroy(&pix32);
      
          return image;
      }
      

      【讨论】:

        【解决方案4】:

        Tesseract-OCR-iOS repo 中有 UIImage 和 Pix 对象之间转换的实现。

        查看G8Tesseract.m中的以下方法:

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-10
          • 1970-01-01
          • 1970-01-01
          • 2012-04-17
          相关资源
          最近更新 更多