【问题标题】:J2ME - PNG created in PhotoShop not displaying in emulatorJ2ME - 在 PhotoShop 中创建的 PNG 未在模拟器中显示
【发布时间】:2015-02-12 17:35:56
【问题描述】:

我的 midlet 可以正常显示一些图像,但不能显示其他图像。

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

所以我在想我的 PhotoShop (CS6) 设置可能是错误的......

PNG-8,选择性,扩散,颜色:256,抖动:100%,哑光:无,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 中。

这是有问题的图像:

【问题讨论】:

  • 在使用前尝试使用 PNGout 或 Optipng 工具优化 png。这些工具会剔除任何不必要的数据并针对 J2ME 兼容性对其进行优化。
  • 谢谢,但知道如何使用它吗?我找到了这个教程,但我没有更聪明...advsys.net/ken/util/pngout.htm
  • 我找到了另一个推荐使用pngout.exe loading1.png loading1out.png的教程。
  • iTxt 块中似乎有一些意外的文本。使用 Photoshop 的 Save for Web,您可以选择不包含任何元数据——试试吧。
  • @Jongware 谢谢 - 删除元数据已经成功了。您想添加它作为答案,以便我接受。

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


【解决方案1】:

根据崩溃日志,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 文本 - 它包含高于不符合 UTF8 规则的纯 ASCII 范围 0..127 的“原始”字节。

我发现示例图像中的情况并非如此。只有一组连续的字节组成一个UTF8码序列,并且是有效的:

EFBBBF" id=" ..

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

如果 BOM 字符出现在数据流的中间,Unicode 表示它应该被解释为“零宽度不间断空格”(禁止字形之间的换行)。在 Unicode 3.2 中,这种用法已被弃用,取而代之的是“Word Joiner”字符 U+2060。[1]这允许 U+FEFF 仅用作 BOM。
(http://en.wikipedia.org/wiki/Byte_order_mark)

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

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

(警告:纯猜想)

查看DataInputStream的来源,我找到了这个sn-p的代码:

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

随后循环读取utflen 字节(不是“Unicode 字符”)。这对于iTXt 块来说是错误的,因为它没有“第一个单词”来指示其长度。纯文本中的字节数可以从块长度(即,根据 PNG 约定,总数据长度不包括长度长字、iTXt 签名本身和最终的 CRC32 代码)减去以零结尾的关键字名称、语言和“翻译的关键字”字符串,以及指示完整纯文本压缩的两个字节。


作为一种解决方法,从您的 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,则元数据会进入,并且没有复选框可以摆脱它。如果您改用“保存为网络和设备”,您会看到一个带有许多方便选项的大对话框,例如标有“元数据”的下拉列表。

选择“全部”我得到了一个更大的文件;我的 Photoshop 版本创建了一个 大量 3K 的 XMP 元数据块,包括一个 2K 完全空的“填充”块...
选择“Copyright”或“None”终于去掉了所有的杂物(大概是因为我没有填写任何版权信息),然后你得到一个漂亮的 169 字节长的 PNG,其中唯一的元数据是使用的软件被称为“Adobe ImageReady”。


1 这有点讽刺。根据 PNG 规范,

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-28
    • 2016-12-28
    • 1970-01-01
    • 1970-01-01
    • 2016-12-26
    • 1970-01-01
    相关资源
    最近更新 更多