Merge pull request #16558 from Snuffleupagus/writeStream-filter-fixes

Improve handling of /Filter-entries in `writeStream`
This commit is contained in:
Jonas Jenwald 2023-06-16 13:07:41 +02:00 committed by GitHub
commit 04c31a55d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 25 deletions

View File

@ -14,7 +14,7 @@
*/ */
import { bytesToString, info, stringToBytes, warn } from "../shared/util.js"; import { bytesToString, info, stringToBytes, warn } from "../shared/util.js";
import { Dict, Name, Ref } from "./primitives.js"; import { Dict, isName, Name, Ref } from "./primitives.js";
import { import {
escapePDFName, escapePDFName,
escapeString, escapeString,
@ -49,28 +49,29 @@ async function writeStream(stream, buffer, transform) {
if (transform !== null) { if (transform !== null) {
string = transform.encryptString(string); string = transform.encryptString(string);
} }
const { dict } = stream;
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
if (typeof CompressionStream === "undefined") { if (typeof CompressionStream === "undefined") {
stream.dict.set("Length", string.length); dict.set("Length", string.length);
await writeDict(stream.dict, buffer, transform); await writeDict(dict, buffer, transform);
buffer.push(" stream\n", string, "\nendstream"); buffer.push(" stream\n", string, "\nendstream");
return; return;
} }
const filter = await stream.dict.getAsync("Filter"); const filter = await dict.getAsync("Filter");
const flateDecode = Name.get("FlateDecode"); const params = await dict.getAsync("DecodeParms");
// If the string is too small there is no real benefit const filterZero = Array.isArray(filter)
// in compressing it. ? await dict.xref.fetchIfRefAsync(filter[0])
: filter;
const isFilterZeroFlateDecode = isName(filterZero, "FlateDecode");
// If the string is too small there is no real benefit in compressing it.
// The number 256 is arbitrary, but it should be reasonable. // The number 256 is arbitrary, but it should be reasonable.
const MIN_LENGTH_FOR_COMPRESSING = 256; const MIN_LENGTH_FOR_COMPRESSING = 256;
if ( if (string.length >= MIN_LENGTH_FOR_COMPRESSING || isFilterZeroFlateDecode) {
string.length >= MIN_LENGTH_FOR_COMPRESSING ||
(Array.isArray(filter) && filter.includes(flateDecode)) ||
(filter instanceof Name && filter.name === flateDecode.name)
) {
try { try {
const byteArray = stringToBytes(string); const byteArray = stringToBytes(string);
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
@ -83,25 +84,32 @@ async function writeStream(stream, buffer, transform) {
const buf = await new Response(cs.readable).arrayBuffer(); const buf = await new Response(cs.readable).arrayBuffer();
string = bytesToString(new Uint8Array(buf)); string = bytesToString(new Uint8Array(buf));
if (Array.isArray(filter)) { let newFilter, newParams;
if (!filter.includes(flateDecode)) { if (!filter) {
filter.push(flateDecode); newFilter = Name.get("FlateDecode");
} else if (!isFilterZeroFlateDecode) {
newFilter = Array.isArray(filter)
? [Name.get("FlateDecode"), ...filter]
: [Name.get("FlateDecode"), filter];
if (params) {
newParams = Array.isArray(params)
? [null, ...params]
: [null, params];
} }
} else if (!filter) { }
stream.dict.set("Filter", flateDecode); if (newFilter) {
} else if ( dict.set("Filter", newFilter);
!(filter instanceof Name) || }
filter.name !== flateDecode.name if (newParams) {
) { dict.set("DecodeParms", newParams);
stream.dict.set("Filter", [filter, flateDecode]);
} }
} catch (ex) { } catch (ex) {
info(`writeStream - cannot compress data: "${ex}".`); info(`writeStream - cannot compress data: "${ex}".`);
} }
} }
stream.dict.set("Length", string.length); dict.set("Length", string.length);
await writeDict(stream.dict, buffer, transform); await writeDict(dict, buffer, transform);
buffer.push(" stream\n", string, "\nendstream"); buffer.push(" stream\n", string, "\nendstream");
} }

View File

@ -1979,7 +1979,7 @@ describe("api", function () {
await loadingTask.destroy(); await loadingTask.destroy();
}); });
it("write a a new annotation, save the pdf and check that the prev entry in xref stream is correct", async function () { it("write a new annotation, save the pdf and check that the prev entry in xref stream is correct", async function () {
if (isNodeJS) { if (isNodeJS) {
pending("Linked test-cases are not supported in Node.js."); pending("Linked test-cases are not supported in Node.js.");
} }