Trước tiên: một lần PDF được ký kết, bạn không nên thay đổi bất kỳ byte của PDF mà, bởi vì bạn làm mất hiệu lực chữ ký nếu bạn làm.
Quan sát thứ hai: dấu thứ tự byte là không một phần của tiêu đề PDF (PDF luôn bắt đầu bằng %PDF-1.
). Trong ngữ cảnh này, nó là giá trị của thuộc tính begin
trong hướng dẫn xử lý siêu dữ liệu XMP. Tôi không biết của bất kỳ khách hàng Java có một vấn đề với chuỗi byte đó bất cứ nơi nào trong một tập tin. Nếu họ có một vấn đề với nó, có một vấn đề với khách hàng đó, không phải với tập tin.
Byte Order Mark là chỉ báo về sự hiện diện của các ký tự UTF-8. Trong bối cảnh của XMP, chúng tôi có một luồng bên trong tệp PDF chứa tệp XML văn bản rõ ràng có thể được phần mềm tiêu thụ không phải là "nhận thức PDF". Ví dụ:
2 0 obj
<</Type/Metadata/Subtype/XML/Length 3492>>stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.1.0-jc003">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:pdf="http://ns.adobe.com/pdf/1.3/"
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
dc:format="application/pdf"
pdf:Keywords="Metadata, iText, PDF"
pdf:Producer="iText® 5.5.4-SNAPSHOT ©2000-2014 iText Group NV (AGPL-version); modified using iText® 5.5.4-SNAPSHOT ©2000-2014 iText Group NV (AGPL-version)"
xmp:CreateDate="2014-11-07T16:36:55+01:00"
xmp:CreatorTool="My program using iText"
xmp:ModifyDate="2014-11-07T16:36:56+01:00"
xmp:MetadataDate="2014-11-07T16:36:56+01:00">
<dc:description>
<rdf:Alt>
<rdf:li xml:lang="x-default">This example shows how to add metadata</rdf:li>
</rdf:Alt>
</dc:description>
<dc:creator>
<rdf:Seq>
<rdf:li>Bruno Lowagie</rdf:li>
</rdf:Seq>
</dc:creator>
<dc:subject>
<rdf:Bag>
<rdf:li>Metadata</rdf:li>
<rdf:li>iText</rdf:li>
<rdf:li>PDF</rdf:li>
</rdf:Bag>
</dc:subject>
<dc:title>
<rdf:Alt>
<rdf:li xml:lang="x-default">Hello World example</rdf:li>
</rdf:Alt>
</dc:title>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>
endstream
phần mềm phi PDF-aware như vậy sẽ tìm kiếm các chuỗi W5M0MpCehiHzreSzNTczkc9d
, mà là một chuỗi đó là khó có khả năng xuất hiện một cách tình cờ trong một dòng dữ liệu.
Thuộc tính begin
có để cho biết rằng các ký tự trong luồng sử dụng mã hóa UTF-8. Họ ở đó vì thực hành tốt cho họ ở đó, nhưng họ không bắt buộc (ISO-16684-1).
Bạn có thể lấy các siêu dữ liệu theo cách bạn làm (byte[] metadata = reader.Metadata;
), loại bỏ các byte, và thay đổi dòng với một trường hợp PdfStamper
như thế này:
stamper.XmpMetadata = metadata;
Sau khi bạn đã thay đổi siêu dữ liệu, bạn có thể đăng các PDF.
Lưu ý rằng một khía cạnh của câu hỏi khiến tôi ngạc nhiên. Bạn viết:
// metadata[0], metadata[1], metadata[2] contain the BOM
Thật là lạ khi ba byte đầu tiên của siêu dữ liệu XMP chứa BOM. Siêu dữ liệu XMP giả sử bắt đầu bằng <?xpacket
. Nếu không, bạn đang làm điều đúng bằng cách loại bỏ các byte đó.
Lưu ý: PDF có thể chứa siêu dữ liệu XMP ở các cấp khác nhau. Ngay bây giờ, bạn đang kiểm tra một trong những phổ biến nhất: siêu dữ liệu cấp tài liệu. Bạn có thể gặp phải các tệp PDF có siêu dữ liệu XMP cấp trang, với XMP bên trong một hình ảnh, v.v ...
Tôi vừa kiểm tra và iTextSharp không thêm BOM. Hoặc các tệp PDF gốc đã có chúng trước khi ký hoặc bạn thêm BOM vào một thời điểm nào đó. – divanov
Siêu dữ liệu (được nhúng ở đâu đó trong tệp PDF) thường có BOM và điều đó là ok. * Vấn đề là các máy khách Java dường như có một số vấn đề với các tệp đó * - mà Java Clients? – mkl
@mkl: đầu tiên, InputStream đọc mảng byte, sau đó XMLPullParse (android) ném XmlPullParserException khi phân tích cú pháp xml. Sử dụng BOMInputStream loại bỏ BOM khỏi String, vì vậy XMLPullParser có thể đọc nó trong mọi trường hợp. Nhưng yêu cầu của tôi là có tệp gốc mà không có BOM. – lukasz