decodeStream function
Decodes a stream's payload by applying its /Filter chain in order.
resolve is used to chase indirect references inside /Filter,
/DecodeParms, and /Length entries.
stopBeforeFilter stops the chain just before the named filter and
returns the partially decoded bytes - used to undo e.g. FlateDecode
wrapped around a JPEG while leaving the JPEG for a platform codec.
Implementation
Uint8List decodeStream(CosStream stream,
{CosResolver? resolve, String? stopBeforeFilter}) {
CosObject deref(CosObject? object) {
var value = object ?? CosNull.instance;
while (value is CosReference && resolve != null) {
value = resolve(value);
}
return value;
}
final filterObject = deref(stream.dictionary['Filter']);
final paramsObject =
deref(stream.dictionary['DecodeParms'] ?? stream.dictionary['DP']);
final names = <String>[];
if (filterObject is CosName) names.add(filterObject.value);
if (filterObject is CosArray) {
for (final f in filterObject.items) {
final r = deref(f);
if (r is CosName) names.add(r.value);
}
}
final params = <CosDictionary?>[];
if (paramsObject is CosDictionary) params.add(paramsObject);
if (paramsObject is CosArray) {
for (final p in paramsObject.items) {
final r = deref(p);
params.add(r is CosDictionary ? r : null);
}
}
var data = stream.rawBytes;
for (var i = 0; i < names.length; i++) {
if (names[i] == stopBeforeFilter) break;
final filter = _filters[names[i]];
if (filter == null) throw UnsupportedFilterException(names[i]);
final t0 = PdfPerf.begin();
data = filter.decode(data, i < params.length ? params[i] : null);
if (PdfPerf.enabled) _recordFilterDecode(names[i], t0, data.length);
}
if (names.isNotEmpty) PdfPerf.add(PdfPerfCount.streamsDecoded);
return data;
}