J2ME - 在PhotoShop中创建的PNG不在模拟器中显示

时间:2015-02-12 17:35:57

标签: java-me png emulation photoshop java-wireless-toolkit

我的midlet正在显示一些图像,但不是其他图像。

它们都是8位PNG,但那些没有显示的是我在PhotoShop中创建的那些。

所以我想也许我的PhotoShop(CS6)设置错了......

  

PNG-8,Selective,Diffusion,颜色:256,Dither:100%,Matte:None,Web   捕捉:0%,转换为sRGB:勾选,宽度:48,高度:48,百分比:100%,   质量:双立方。

我已尝试过其中一些设置,但无济于事。

有什么想法吗?

有一个similar problem here,但这与我的相反,因为PhotoShop在这种情况下修补了东西,而不是破坏了东西...

我的代码是......

image = Image.createImage("/img/loading1.png");

...这是我的堆栈跟踪:

java.io.EOFException
    at javax.imageio.stream.ImageInputStreamImpl.readFully(
ImageInputStreamImpl.java:353)
    at java.io.DataInputStream.readUTF(DataInputStream.java:609)
    at javax.imageio.stream.ImageInputStreamImpl.readUTF(ImageInputStreamImpl.java:332)
    at com.sun.kvem.png.PNGImageReader.parse_iTXt_chunk(PNGImageReader.java:447)
    at com.sun.kvem.png.PNGImageReader.readMetadata(PNGImageReader.java:650)
    at com.sun.kvem.png.PNGImageReader.readImage(PNGImageReader.java:1312)
    at com.sun.kvem.png.PNGImageReader.read(PNGImageReader.java:1582)
    at com.sun.kvem.midp.GraphicsBridge.loadImage(GraphicsBridge.java:2602)
    at com.sun.kvem.midp.GraphicsBridge.createImageFromData(GraphicsBridge.java:2511)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.sun.kvem.sublime.MethodExecution.process(MethodExecution.java:42)
    at com.sun.kvem.sublime.SublimeExecutor.processRequest(SublimeExecutor.java:63)
    at javax.microedition.lcdui.Image.createImage(Image.java:315)

有问题的图像确实存在 - 无论是在项目中还是在构建的jar中。

以下是相关图片: enter image description here

1 个答案:

答案 0 :(得分:3)

根据崩溃日志,J2ME中的PNG解码器在非关键块iTXt内失败: 1

> com.sun.kvem.png.PNGImageReader.readMetadata
  > com.sun.kvem.png.PNGImageReader.parse_iTXt_chunk
    > javax.imageio.stream.ImageInputStreamImpl.readUTF
      > java.io.DataInputStream.readUTF

根据libpng documentationiTXt的文本部分必须是有效的UTF8:

  

...根据压缩标志,剩余的块数据是主要的UTF-8文本,无论是zlib压缩还是非压缩。由于其长度可以从块长度确定,因此它不是以空值终止的。与其他两个文本块一样,换行符应由单个换行符(十进制10)表示,并且不鼓励所有其他控制字符(1-9,11-31和127-159)。

通常这表示读取的流不是有效的UTF8文本 - 它包含' raw'高于普通ASCII范围0..127的字节,不符合UTF8规则。

我发现样本图像不是这种情况。只有一组连续字节构成UTF8代码序列,它是有效的:

<?xpacket begin="EFBBBF" id=" ..

(粗体部分以十六进制表示法表示3个数据字节)。我首先怀疑这是错误:

  

如果BOM字符出现在数据流的中间,Unicode表示它应该被解释为&#34;零宽度不间断空格&#34; (禁止单词字形之间的换行)。在Unicode 3.2中,不推荐使用此用法以支持&#34; Word Joiner&#34;字符,U + 2060。[1]这允许U + FEFF仅用作BOM   (http://en.wikipedia.org/wiki/Byte_order_mark

..所以一个完全符合标准的UTF8读取器应检查其字节,并在遇到BOM时抛出UTFDataFormatException,而不是作为第一个值。令人惊讶的是,这似乎不是问题所在!首先,没有任何迹象表明任何readUTF来源除了仅验证UTF8代码是否在其自身的之外还做其他任何事情,无论其价值如何。有很多&#39;无效&#39; Unicode 代码点(不代表有效的Unicode字符或指令的值),但在我看来它们都被默默地忽略了。但我注意到常见的readUTF函数只实现了UTF8 / Unicode的一小部分(参见Oracle文档中的Modified UTF-8)。

所以问题出在其他地方。另一个线索是,抛出的错误是不是 UTFDataFormatException而是EOFException,表明读缓冲区已经超出了它承诺包含的字节数。

(警告:纯粹的猜想如下)

查看DataInputStream的来源,我找到了这段代码:

588       public final static String readUTF(DataInput in) throws IOException {
589           int utflen = in.readUnsignedShort();

后跟循环读取utflen 字节(不是&#34; Unicode字符&#34;)。这对iTXt块来说是错误的,因为它没有第一个单词&#39;表明它的长度。纯文本中的字节数可以从块长度(根据PNG约定,不包括长度长字的总数据长度,iTXt签名本身和最终CRC32代码)中导出。零终止关键字名称,语言和&#34;翻译关键字&#34;的长度字符串,以及表示完整纯文本压缩的两个字节。


作为解决方法,请从PNG图像中删除iTXt块。数据本身 - XMP元数据 - 很可能根本不适合您的目的(但请随时阅读what benefits Adobe thinks it has)。如果你的工作流程没有使用它,它只是一个无用的未压缩文本块,在你的样本图像中占用总共981个字节的814个字节 - 高达83%!

您可以使用外部实用程序删除无关的数据块;例如,流行的pngcrush的命令行是

pngcrush -rem alla -rem text InputFile.png OutputFile.png

(来自en.wikipedia.org/wiki/Pngcrush)。

或直接来自Photoshop:如果您保存PNG&#39;通常的方式&#39;与&#34;另存为&#34;菜单选项,元数据进入,没有复选框来摆脱它。如果你使用&#34; Save for Web&amp;装置&#34;相反,你得到一个包含许多方便选项的大型对话框,例如标有&#34;元数据&#34;的下拉列表。

选择&#34;全部&#34;我有一个更大的档案;我的Photoshop版本创建了一个大量 3K块的XMP元数据,其中包括一个2K完全空的填充程序&#39;块...
选择&#34;版权所有&#34;或&#34;无&#34;终于摆脱了所有的crud(大概是因为我没有填写任何版权信息),然后你得到一个漂亮的169字节长的PNG,其中唯一的元数据是所使用的软件称为&#34; Adob​​e ImageReady&#34 ;


1 这是具有讽刺意味的。根据PNG规范,

  

..遇到未知块(其中辅助位为1)的解码器可以安全地忽略该块并继续显示图像。
  (source

这个&#34;辅助位&#34;是块ID的第一个字节的第5位:0(大写)=临界,1(小写)=辅助,即,如果块ID的第一个字符是大写,则PNG读取器必须正确读取和解释其数据,如果不正确,则可以静默跳过。

从技术上讲,J2ME的编写者可以安全地忽略整个块。但是他们搞砸了,尝试来阅读它,现在代码崩溃了所有程序只是试图读取恰好包含iTXt块的PNG中的图像数据。