.ai import: a file whose PDF part can't be read opens from its editing data

Squashed from #5051 onto main.
This commit is contained in:
dotCooCoo
2026-11-02 12:04:04 +07:00
committed by bflatastic
parent 54436b0aa2
commit 100730d4d3
43 changed files with 476 additions and 42 deletions
+27 -10
View File
@@ -190,7 +190,19 @@ pub fn ai(private: &[u8], page: &str) -> Vec<u8> {
/// [`ai`] with more entries in the page dictionary (`/ArtBox [0 0 200 100]`).
pub fn ai_with(private: &[u8], page: &str, entries: &str) -> Vec<u8> {
with_private(private, page, "AIPrivateData", entries)
with_private(private, page, "AIPrivateData", entries, "")
}
/// [`ai`] with more entries in the dictionary of the page's content stream
/// (`/DecodeParms << /Predictor 12 /Columns 0 >>`).
pub fn ai_with_content(private: &[u8], page: &str, content: &str) -> Vec<u8> {
with_private(private, page, "AIPrivateData", "", content)
}
/// [`ai`] with more `entries` in the page dictionary, as [`ai_with`], and more in its content
/// stream's dictionary, as [`ai_with_content`].
pub fn ai_with_entries_and_content(private: &[u8], page: &str, entries: &str, content: &str) -> Vec<u8> {
with_private(private, page, "AIPrivateData", entries, content)
}
/// A PDF saved with Illustrator's editing data: [`ai`]'s file with the two streams under
@@ -198,15 +210,20 @@ pub fn ai_with(private: &[u8], page: &str, entries: &str) -> Vec<u8> {
/// #868, and nothing else of that file is used; ExifTool's PDF tag table lists them too
/// (<https://exiftool.org/TagNames/PDF.html>).
pub fn pdf(private: &[u8], page: &str) -> Vec<u8> {
with_private(private, page, "AIPDFPrivateData", "")
with_private(private, page, "AIPDFPrivateData", "", "")
}
/// The file of [`ai`] and [`pdf`], with `private` in the streams `{key}1` and `{key}2` and
/// `entries` more in the page dictionary.
fn with_private(private: &[u8], page: &str, key: &str, entries: &str) -> Vec<u8> {
/// [`pdf`] with more entries in the dictionary of the page's content stream, as [`ai_with_content`].
pub fn pdf_with_content(private: &[u8], page: &str, content: &str) -> Vec<u8> {
with_private(private, page, "AIPDFPrivateData", "", content)
}
/// The file of [`ai`] and [`pdf`], with `private` in the streams `{key}1` and `{key}2`, `entries`
/// more in the page dictionary and `content` more in its content stream's dictionary.
fn with_private(private: &[u8], page: &str, key: &str, entries: &str, content: &str) -> Vec<u8> {
let (first, second) = private.split_at(private.len() / 2);
let stream = |part: &[u8]| {
let mut s = format!("<< /Length {} >>\nstream\n", part.len()).into_bytes();
let stream = |part: &[u8], more: &str| {
let mut s = format!("<< /Length {} {more}>>\nstream\n", part.len()).into_bytes();
s.extend_from_slice(part);
s.extend_from_slice(b"\nendstream");
s
@@ -220,9 +237,9 @@ fn with_private(private: &[u8], page: &str, key: &str, entries: &str) -> Vec<u8>
/PieceInfo << /{PIECE} << /Private << /{key}1 5 0 R /{key}2 6 0 R /NumBlock 2 >> >> >> >>"
)
.into_bytes(),
stream(page.as_bytes()),
stream(first),
stream(second),
stream(page.as_bytes(), content),
stream(first, ""),
stream(second, ""),
];
let mut out = b"%PDF-1.5\n".to_vec();
let mut offsets = vec![];