3

我正在尝试用 Java 从头开始​​编写一个简单的 RTF 文档,并且我正在尝试将 JPEG 嵌入到文档中。这是嵌入在 RTF 文档(由 WordPad 生成,将 JPEG 转换为 WMF)中的 JPEG(2x2 像素 JPEG,由左上角的三个白色像素和一个黑色像素组成)的示例:

{\pict\wmetafile8\picw53\pich53\picwgoal30\pichgoal30 
0100090000036e00000000004500000000000400000003010800050000000b0200000000050000
000c0202000200030000001e000400000007010400040000000701040045000000410b2000cc00
020002000000000002000200000000002800000002000000020000000100040000000000000000
000000000000000000000000000000000000000000ffffff00fefefe0000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
0000001202af0801010000040000002701ffff030000000000
}

我一直在阅读RTF 规范,看起来您可以指定图像是 JPEG,但由于写字板总是将图像转换为 WMF,因此我看不到嵌入 JPEG 的示例。所以我可能最终还需要从 JPEG 转码为 WMF 或其他东西....

但基本上,我正在寻找如何在给定文件 URL 的情况下生成 JPEG 的二进制或十六进制(规范,第 148 页:“这些图片可以是十六进制(默认)或二进制格式。”)形式。

谢谢!


编辑:我认为流的东西工作得很好,但仍然不明白如何对其进行编码,因为无论我在做什么,它都不是 RTF 可读的。例如,上面的图片改为:

ffd8ffe00104a464946011106006000ffdb0430211211222222223533333644357677767789b988a877adaabcccc79efdcebcccffdb04312223336336c878ccccccccccccccccccccccccccccccccccccccccccccccccccffc0011802023122021113111ffc401f001511111100000000123456789abffc40b5100213324355440017d123041151221314161351617227114328191a182342b1c11552d1f024336272829a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9faffc401f103111111111000000123456789abffc40b51102124434754401277012311452131612415176171132232818144291a1b1c19233352f0156272d1a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda0c31021131103f0fdecf09f84f4af178574cd0b42d334fd1744d16d22bd3f4fb0b74b6b5bb78902450c512091c688aaaa8a0500014514507ffd9

这个 PHP 库可以解决问题,所以我试图将相关部分移植到 Java。这是:

$imageData = file_get_contents($this->_file);
$size = filesize($this->_file);

$hexString = '';

for ($i = 0; $i < $size; $i++) {
    $hex = dechex(ord($imageData{$i}));

    if (strlen($hex) == 1) {
        $hex = '0' . $hex;
    }

    $hexString .= $hex;
}

return $hexString;

但我不知道 Java 的类似物dechex(ord($imageData{$i}))是什么。:( 我只得到了Integer.toHexString()功能,它负责处理dechex部分......

谢谢大家。:)

4

2 回答 2

2

给定任何文件的文件 URL,您可以通过执行来获取相应的字节(为简洁起见,省略了异常处理)...

int BUF_SIZE = 512;
URL fileURL = new URL("http://www.somewhere.com/someurl.jpg");
InputStream inputStream = fileURL.openStream();
byte [] smallBuffer = new byte[BUF_SIZE];
ByteArrayOutputStream largeBuffer = new ByteArrayOutputStream();
int numRead = BUF_SIZE;
while(numRead == BUF_SIZE) {
    numRead = inputStream.read(smallBuffer,0,BUF_SIZE);
    if(numRead > 0) {
        largeBuffer.write(smallBuffer,0,BUF_SIZE);
    }
}
byte [] bytes = largeBuffer.toByteArray();

我现在正在查看您的 PHP 代码片段,并意识到 RTF 是一个奇怪的规范!看起来图像的每个字节都被编码为 2 个十六进制数字(没有明显原因,图像大小加倍)。整个事情都以原始 ASCII 编码存储。所以,你会想做...

StringBuilder hexStringBuilder = new StringBuilder(bytes.length * 2);
for(byte imageByte : bytes) {
    String hexByteString = Integer.toHexString(0x000000FF & (int)imageByte);
    if(hexByteString .size() == 1) {
        hexByteString = "0" + hexByteString ;
    }
    hexStringBuilder.append(hexByteString);
}
String hexString = hexStringBuilder.toString();
byte [] hexBytes = hexString.getBytes("UTF-8"); //Could also use US-ASCII

编辑:更新代码示例以在十六进制字节上填充 0

编辑:当转换为整数时,负字节在逻辑上右移 >_<

于 2010-06-22T02:01:45.477 回答
0

https://joseluisbz.wordpress.com/2013/07/26/exploring-a-wmf-file-0x000900/

也许可以帮助您:

        String HexRTFBytes = "Representations text of bytes from Image RTF File";
        String Destiny = "The path of the output File";
        FileOutputStream wmf;
        try {
          wmf = new FileOutputStream(Destiny);
          HexRTFBytes = HexRTFBytes.replaceAll("\n", ""); //Erase New Lines
          HexRTFBytes = HexRTFBytes.replaceAll(" ", ""); //Erase Blank spaces
          int NumBytesWrite = HexRTFBytes.length();
          int WMFBytes = NumBytesWrite/2;//One byte is represented by 2 characters
          byte[] ByteWrite = new byte[WMFBytes];
          for (int i = 0; i < WMFBytes; i++){
            se = HexRTFBytes.substring(i*2,i*2+2);
            int Entero = Integer.parseInt(se,16);
            ByteWrite[i] = (byte)Entero;
          }
          wmf.write(ByteWrite);
          wmf.close();
        }
        catch (FileNotFoundException fnfe)
        {System.out.println(fnfe.toString());}
        catch (NumberFormatException fnfe)
        {System.out.println(fnfe.toString());}
        catch (EOFException eofe)
        {System.out.println(eofe.toString());}
        catch (IOException ioe)
        {System.out.println(ioe.toString());}

此代码采用一个字符串表示,并将结果存储在一个文件中。

https://joseluisbz.wordpress.com/2011/06/22/script-de-clases-rtf-para-jsp-y-php/

现在如果你想获得图像文件的表示,你可以使用这个:

    private void ByteStreamImageString(byte[] ByteStream) {
      this.Format = 0;
      this.High = 0;
      this.Wide = 0;
      this.HexImageString = "Error";
      if (ByteStream[0]== (byte)137 && ByteStream[1]== (byte)80 && ByteStream[2]== (byte)78){
        this.Format = PNG; //PNG
        this.High = this.Byte2PosInt(ByteStream[22],ByteStream[23]);
        this.Wide = this.Byte2PosInt(ByteStream[18],ByteStream[19]);
      }
      if (ByteStream[0]== (byte)255 && ByteStream[1]== (byte)216
          && ByteStream[2]== (byte)255 && ByteStream[3]== (byte)224){
        this.Format = JPG; //JPG
        int PosJPG = 2;
        while (PosJPG < ByteStream.length){
          String M = String.format("%02X%02X", ByteStream[PosJPG+0],ByteStream[PosJPG+1]);
          if (M.equals("FFC0") || M.equals("FFC1") || M.equals("FFC2") || M.equals("FFC3")){
            this.High = this.Byte2PosInt(ByteStream[PosJPG+5],ByteStream[PosJPG+6]);
            this.Wide = this.Byte2PosInt(ByteStream[PosJPG+7],ByteStream[PosJPG+8]);
          }
          if (M.equals("FFDA")) {
            break;
          }
          PosJPG = PosJPG+2+this.Byte2PosInt(ByteStream[PosJPG+2],ByteStream[PosJPG+3]);
        }
      }
      if (this.Format > 0) {
        this.HexImageString = "";
        int Salto = 0;
        for (int i=0;i < ByteStream.length; i++){
          Salto++;
          this.HexImageString += String.format("%02x", ByteStream[i]);
          if (Salto==64){
            this.HexImageString += "\n"; //To make readable
            Salto = 0;
          }
        }
      }
    }
于 2013-08-16T04:08:25.973 回答