【问题标题】:how to read bitmap and meta-data from a png stream/file efficiently?如何有效地从 png 流/文件中读取位图和元数据?
【发布时间】:2012-12-14 04:01:50
【问题描述】:

我需要使用 [PNGJ] (http://code.google.com/p/pngj/) 库从 PNG 输入流中解码位图和元数据。问题是解码元数据会推进流,然后我不能使用 位图 = BitmapFactory.decodeStream().

我自己创建位图是可以的,但是如果我需要使用插值来缩放位图,我宁愿使用 BitmapFactory。要使用它,每次我必须使用 PNGJ 获取元数据和使用 BitmapFactory 获取位图时,我都必须创建 InputStream 的副本。从单个 PNGJ 调用(至少对于最常见的 ARGB_8888 格式)返回元数据和位图会很好。

简而言之,我必须复制要由 Java 库使用的流,这看起来很浪费。返回位图将是一种解决方案。

    // register an auxilary chunk name 
    PngChunk.factoryRegister(ThumbNailProvider.chunkID, chunkPROP.class); 

    // reader for the stream
    PngReader pngr = new PngReader(inStream, "debug label PNG reader");
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    PngWriter pngw = new PngWriter(outputStream, pngr.imgInfo);

    // copy pre-data chunks
    pngw.copyChunksFirst(pngr, ChunkCopyBehaviour.COPY_ALL_SAFE);

    // copy image data
    for (int row = 0; row < pngr.imgInfo.rows; row++) {
        ImageLine l1 = pngr.readRow(row);
        pngw.writeRow(l1, row);
    }

    // copy after-data chunks
    pngw.copyChunksLast(pngr, ChunkCopyBehaviour.COPY_ALL); 

    pngr.end(); // close inStream but not its copy
    pngw.end(); // close out stream

    // save a copy of the stream for Java Libraries;
    data.inputStream = new ByteArrayInputStream(outputStream.toByteArray());



    // read the chunk
    ChunksList chunkList = pngr.getChunksList();
    PngChunk chunk = chunkList.getById1(L2ThumbNailProvider.chunkID);
    if (chunk != null) {
    ... 
    }

【问题讨论】:

  • 如果您需要帮助优化您的代码,请发布您的代码 :)

标签: image bitmap png metadata


【解决方案1】:

这是有两个独立的流消费者的问题,比如Class1.parse(inputStream)Class2.decode(inputStream),我们希望他们消费同一个流;如果我们无法控制消费者如何吃流,它没有简单优雅的解决方案 (eg)。

简单的解决方案,但不是很优雅 - 并且可能不切实际 - 是:关闭并重新打开流(如果我们从网络流中读取,则不可行),在内存中缓冲完整的流内容,或到一个临时文件。

在您的具体情况下,我能想到的替代方案是:

1) 让 PNGJ 使用和解码数据并自己创建位图,用setPixels() 填充它的像素。除其他不便外,这还需要您进行正确的颜色转换。

2) 使用 PngReader 作为 InputFilterStream,以便它只解析元数据并将完整的流传递给消费者。目前,如果不对 PNGJ 代码进行调整,这是不可能的。我会看看,如果实现了这个功能,我会在这里发布。

【讨论】:

  • 非常感谢您的器乐回答。 InputFilterStream 仅在我们将元数据存储在位图数据之前才有效,对吗?我还可以使用 mark()/reset() 函数将流倒带一点。目前,我要么制作流的副本(效率不高),要么将其转换为 InputFilterStream,在调用 BitmapFactory.decodeFileDescriptor() 之后位置不会移动: FileInputStream fs = (FileInputStream) mIS; java.io.FileDescriptor fd = fs.getFD()
  • 抱歉,我的意思是:InputFilterStream 只有在我们将元数据存储在位图数据之前才有效,对吧?我还可以使用 mark()/reset() 函数将流倒带一点。目前,我要么复制流(效率不高),要么将其转换为文件描述符,在调用 BitmapFactory.decodeFileDescriptor() 之后位置不移动: FileInputStream fs = (FileInputStream) mIS; java.io.FileDescriptor fd = fs.getFD()
  • 如果你的流来自一个文件,那么为什么不打开它两次呢?似乎是最简单有效的方法,特别是如果您只想让 PngJ 解析元数据。请记住,PngReader 有一个 readSkippingAllRows() 方法,对于这种情况非常有效。
  • 不,它不是来自文件,而是来自服务器。 FileDescriptor 解决方案允许非破坏性地读取流。
猜你喜欢
  • 2011-01-12
  • 1970-01-01
  • 2021-01-06
  • 2016-04-29
  • 1970-01-01
  • 2017-12-09
  • 2019-07-14
  • 1970-01-01
  • 2012-02-21
相关资源
最近更新 更多