在java中将PNG图像快速加载到数组中
我想加载(和解码)PNG 图像并将它们转换为 Java 中的一维数组。显然,我可以使用 ImageIO.read() 执行此操作,然后将像素复制到数组中,但这会消耗两倍的内存(光栅+最终数组),并且涉及的处理时间比我想要的要多。
我该怎么办?最坏的情况是我可以自己实现 PNG 规范,但这似乎是一项相当复杂的任务。理想情况下,我想要一个可以“插入”的 PNG 实现。不太理想但仍然很好的是一个易于理解(与 com.sun 代码不同)的 PNG 阅读器,我可以(并且被允许)修改它。
I want to load (and decode) PNG images and convert them into a one-dimensional array in Java. I can obviously do this with ImageIO.read() and then copy the pixels into the array, but that consumes twice the memory (the raster + the final array) and it involves more processing time than I would like.
How should I go about this? Worst-case I can implement the PNG spec myself, but that seems like a rather involved task. Ideally I'd like a PNG implementation that I can "plug" into. Less ideal but still fine would be an easy to understand (unlike the com.sun code) PNG reader that I can (and would be allowed to) modify.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您想要做的是以数组形式获取像素数据,那么您可以使用 ImageIO.read() 来获取 BufferedImage,然后使用
BufferedImage.getRaster().getDataBuffer()
获取DataBuffer
。从那里,您需要检查您拥有的BufferedImage
类型,以确定如何转换DataBuffer
。例如,如果您有一个TYPE_INT_RGB
图像,那么您应该转换为DataBufferInt
,然后您可以调用DataBufferInt.getData()
来检索 < code>int[] 其中包含数据。通过这种方式获得的不是副本,而是支持 BufferedImage 的实际数组。但是,所有这些有一个很大的警告:
ImageIO.read()
通常不会为您提供您想要的图像类型。例如,您经常会得到 TYPE_CUSTOM,除了复制到您实际想要的图像类型之外,您不能用它做任何有用的事情。所以,如果您足够幸运的话,您只能通过
ImageIO.read()
获取图像数据,而无需制作第二个副本。 read() 为您提供所需格式的图像。如果您想检查 ImageIO 可用的类型,您可以调用 ImageIO.getImageReaders() 来获取所有读取器的Iterator
它声称能够读取您的流,然后您可以使用ImageReader.getImageTypes(0)
来获取读取器可以读取的图像类型的Iterator
。您可能会找到一个能够以这种方式为您提供所需图像类型的阅读器,但不要屏住呼吸。除非您的图像很大,否则复制它们实际上非常快。不过,如果您的图像很大,那么您可能不得不使用 BufferedImage.getRGB() 将原始图像数据一次一行写入磁盘(但是对其进行压缩,使用 GZIPOutputStream ),让原始图像被垃圾收集,创建所需类型的新 BufferedImage ,最后从磁盘读回行,写入使用 BufferedImage.setRGB() 将它们添加到新图像。 (几天前我写了一些东西来做到这一点,因此细节在我的脑海中相当新鲜。它的 LGPL 源是 此处。)
If what you're trying to do is get the pixel data as an array, then you can use
ImageIO.read()
to get aBufferedImage
and then useBufferedImage.getRaster().getDataBuffer()
to get theDataBuffer
. From there, you need to check what type ofBufferedImage
you have in order to determine how to cast theDataBuffer
. E.g. if you have aTYPE_INT_RGB
image, then you should cast to aDataBufferInt
and then you can callDataBufferInt.getData()
to retrieve theint[]
which contains the data. What you get this way is not a copy---it's the actual array backing theBufferedImage
.However, there is a big caveat to all of this:
ImageIO.read()
will often NOT give you the type of image you want. E.g., you'll frequently get TYPE_CUSTOM, which you can't do anything useful with except copy to the image type you actually want.So, you'll only be able to get your image data via
ImageIO.read()
without making a second copy if you're fortunate enough thatImageIO.read()
gives you the image in the format you want. If you want to check what types are available fromImageIO
, you can callImageIO.getImageReaders()
to get anIterator
over all of the readers which claim to be able to read your stream, and then you can useImageReader.getImageTypes(0)
to get anIterator
over image types which the reader can read. You might find a reader which will give you the image type you want this way, but don't hold your breath.Unless your images are huge, copying them is actually pretty fast. If your images are huge, though, you might have to resort to using
BufferedImage.getRGB()
to write the raw image data out to disk one row at a time (but do it compressed, use aGZIPOutputStream
), let the original image be garbage collected, create a newBufferedImage
of the desired type, and finally read the rows back from disk, writing them to the new image usingBufferedImage.setRGB()
. (I wrote something to do this just a few days ago, hence the details are rather fresh in my mind. The LGPL'd source for it is here.)为什么需要一维数组?更大的目的是什么?
任何建议都取决于此。
您通常可以将 PNG 解码为内存可访问的位图,(
ImageIO.read()
返回一个BufferedImage
,正是如此),然后直接访问其像素。 . 作为一维数组(使用 BufferedImage.getRaster().getDataBuffer())。Why do you want a 1D array? What is the bigger purpose?
On that hinges any recommendations.
You can usually decode a PNG to a memory-accessible bitmap, (
ImageIO.read()
returns aBufferedImage
, which is precisely that) and just access its pixels directly ... as a 1D array (usingBufferedImage.getRaster().getDataBuffer()
).使用 Java readively()
use Java readfully()