1

このコードを考えてみましょう:

public class Test1{

    public static void CreatePdf(String src) throws IOException, COSVisitorException{
    PDRectangle rec= new PDRectangle(400,400);
    PDDocument document= null;
    document = new PDDocument();
    PDPage page = new PDPage(rec);
    document.addPage(page);
    PDDocumentInformation info=document.getDocumentInformation();
 PDStream stream= new PDStream(document);
    info.setAuthor("PdfBox");
    info.setCreator("Pdf");
    info.setSubject("Stéganographie");
    info.setTitle("Stéganographie dans les documents PDF");
    info.setKeywords("Stéganographie, pdf");
    content= new PDPageContentStream(document, page, true, false );
    font= PDType1Font.HELVETICA;

String hex = "4C0061f";  // shows "La"
//Notice that we have 00 between 4C and 61 where 00 =null character


       StringBuilder sb = new StringBuilder();
        for (int count = 0; count < hex.length() - 1; count += 2)
    {
        String output = hex.substring(count, (count + 2));
        int decimal = Integer.parseInt(output, 16);
        StringBuilder ae= sb.append((char)decimal);
    }
        String tt=sb.toString();
    content.beginText();
    content.setFont(font, 12);
    content.appendRawCommands("15 385 Td\n");
   content.appendRawCommands("("+tt+")"+"Tj\n");
    content.endText();
   content.close();
    document.save("doc.pdf");
    document.close();       
    }

私の問題は、「00」がヌル文字ではなくPDFドキュメントのスペースに置き換えられるのはなぜですか? このヌル文字の幅は 0.0 ですが、PDF ドキュメントではスペースとして表示されます。したがって、 「La」ではなく「L a」が得られます。

4

2 に答える 2

1

「00」がヌル文字ではなく PDF ドキュメントのスペースに置き換えられるのはなぜですか?

PDF を調べると、テキストに使用されているフォントが次のように定義されていることがわかります。

9 0 obj
<<
/Type /Font
/Subtype /Type1
/BaseFont /Helvetica
/Encoding /WinAnsiEncoding
>>
endobj 

したがって、WinAnsiEncodingでフォントを使用します。PDF 仕様の Annex D にあるそのエンコーディングの定義を見ると、32 (10 進数) 未満のコードは何にもマップされていないことがわかります。したがって、あなたがしようとしているのは、手元のエンコーディングで未定義の文字を使用することです。したがって、動作は定義されていません。Acrobat Reader は、これらの未定義のコード ポイントに正の幅を使用しているようです。

隠し文字がまったく変位を引き起こさないようにしたい場合は、フォント ディクショナリに幅の明示的な配列を追加する必要があります。PDF 仕様のセクション 9.6.2 を参照し、非表示の文字の幅が 0 であることを確認してください。

このヌル文字の幅が 0.0 になっていることに注意してください

未定義の範囲に入るやいなや、何かが起こる可能性があり、異なるプログラムには異なる仮定があります。

PSいくつかのコード...行間

font= PDType1Font.HELVETICA;

String hex = "4C0061f";  // shows "La"

次のコードを追加しました。

InputStream afmStream = ResourceLoader.loadResource("org/apache/pdfbox/resources/afm/Helvetica.afm");
AFMParser afmParser = new AFMParser(afmStream);
afmParser.parse();
FontMetric afmMetrics = afmParser.getResult();
List<Float> newWidths = new ArrayList<Float>();
for (CharMetric charMetric : afmMetrics.getCharMetrics())
{
    if (charMetric.getCharacterCode() < 0)
        continue;
    while (charMetric.getCharacterCode() >= newWidths.size())
        newWidths.add(0f);
    newWidths.set(charMetric.getCharacterCode(), charMetric.getWx());
}
font.setFirstChar(0);
font.setLastChar(newWidths.size() - 1);
font.setWidths(newWidths);

このコードは、PDFBox に含まれる Helvetica.afm フォント メトリック リソースを読み取り、そこからFirstCharLastChar、およびWidthsエントリを作成する必要があります。ここでは問題なく動作しますが、インストールにない場合は、PDFBox jar から afm ファイルを抽出し、FileInputStream.

何らかの理由で、00 文字はまだある程度の幅があると考えているようですが、32 (10 進数) 未満の他の文字は問題なく使用できます。

String hex = "4C0461f";

隙間なく「ラ」を表示。1C と 1D に関するあなたの以前の (現在は削除された) 質問を正しく解釈すれば、これはあなたが続けるのに役立つでしょう。

PPS:コメントの質問について:

この方法のすべての欠点を教えていただけますか? なぜこのメソッドが (Lé) などのアクセント文字と一致しないのか、あなたのコードはアクセントのない文字とのみ一致しますが、アクセントがある場合、Le の代わりに L é が取得されます..欠点は何かだけ知りたいあなたのコードの:)

私はすべてを語ることはできませんが (私は実際にはフォントの問題に深く関わっているわけではないため)、本質的に、上記のアプローチはいくぶん不完全です。

冒頭で述べたように、 32 (10 進数) 未満のコードが何にもマップされないWinAnsiEncodingでフォントを使用します。FirstCharLastChar、およびWidthsエントリを追加することで、コードが 32 未満の文字に対してゼロ幅を定義しようとしました。

それにもかかわらず、これらのコードのエンコード情報 (エンコードは純粋なWinAnsiEncodingのまま) には関心がなく、フォントにこれらのコードの情報が実際に含まれているかどうかも考慮しませんでした。さらに、物事をさらに制御しにくくするために、Helveticaについて話しています。これは、PDF ブラウザが独自の情報を持ち込む必要がある標準の 14 フォントの 1 つです。明示的に与えられた情報とビューアーがもたらす情報が矛盾する場合はいつでも、PDF ビューアーは自分の情報に偏りがちになります。

特にアクセント付きの文字で問題が発生するのはなぜですか? わからない。ただし、これは、フォントが通常、アクセント付きの文字を個別のエンティティとして持ち込むのではなく、アクセント付きの文字とアクセントのない文字を組み合わせているという事実に関連していると思います. ビューワーが内部的に使用するフォントには、32 未満のコード ポイントにマッピングされたこのような結合文字に関する情報が含まれている可能性があります。したがって、32 未満の明示的なコードと、そのようなコードのフォントの暗黙的な使用が並行して発生すると、表示が奇妙になります。

基本的に、私は通常、このようなことをしないようにアドバイスします。通常の PDF ドキュメントの場合は、まったく必要ありません。

ただし、あなたの場合、ドキュメントにStéganographie dans les documents PDFというタイトルを付けたので、PDF 内の情報をどうにかして隠したいと思うことは明らかです。目に見えない、印刷できない文字を使用することは、そのための 1 つのアプローチのようです。したがって、その方向で実験しても問題ありません。しかし、PDF には、直接目に見えることなく、任意の量の情報を PDF に入れる方法が他にもたくさんあります。

したがって、特定の目的に応じて、他のアプローチが情報をより安全に隠す可能性があると思います。たとえば、PieceInfoのプライベートセクションや他の辞書のカスタムタグなどです...

于 2013-08-12T11:29:21.127 に答える
0

最終的なコード:

public class Test4 {

    public static final String src="...";

    public static void CreatePdf(String src) throws IOException, COSVisitorException{
        PDRectangle rec= new PDRectangle(400,400);
        PDDocument document=null;
        document= new PDDocument();
        PDPage page= new PDPage(rec);
        document.addPage(page);
        PDPageContentStream canvas= new PDPageContentStream(document,page,true,false);
        PDFont font= PDType1Font.HELVETICA;
        String hex = "4C1D61f";
        InputStream afmStream = ResourceLoader.loadResource("org/apache/pdfbox/resources/afm/Helvetica.afm");
        AFMParser afmParser = new AFMParser(afmStream);
        afmParser.parse();
        FontMetric afmMetrics = afmParser.getResult();
        List<Float> newWidths = new ArrayList<Float>();
        for (CharMetric charMetric : afmMetrics.getCharMetrics())
{
     if (charMetric.getCharacterCode() < 0)
         continue;
      while (charMetric.getCharacterCode() >= newWidths.size())
          newWidths.add(0f);

      newWidths.set(charMetric.getCharacterCode(), charMetric.getWx());

}

        font.setFirstChar(0);

        font.setLastChar(newWidths.size() - 1);
        font.setWidths(newWidths);



     StringBuilder sb = new StringBuilder();
        for (int count = 0; count < hex.length() - 1; count += 2)
    {
        String output = hex.substring(count, (count + 2));
        int decimal = Integer.parseInt(output, 16);
        StringBuilder ae= sb.append((char)decimal);
    }
        String tt=sb.toString();
    canvas.beginText();
    canvas.setFont(font, 12);
    canvas.appendRawCommands("15 385 Td\n");
   canvas.appendRawCommands("("+tt+")"+"Tj\n");
    canvas.endText();
   canvas.close();
    document.save("doc.pdf");
    document.close();       
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IOException, COSVisitorException {
        // TODO code application logic here
        Test4 tes= new Test4();
        tes.CreatePdf(src);
    }
}
于 2013-08-12T16:42:28.860 に答える