From 91915a7c7a3a4279e08d40bf3e28927dda5e06d6 Mon Sep 17 00:00:00 2001 From: Brendan Duncan Date: Sat, 9 Nov 2024 17:33:41 -0700 Subject: [PATCH] add internal info decoding back to PSD format --- lib/src/formats/psd/psd_channel.dart | 19 ++++++++---- lib/src/formats/psd/psd_image.dart | 45 ++++++++++++++-------------- lib/src/util/input_buffer.dart | 7 +++-- 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/lib/src/formats/psd/psd_channel.dart b/lib/src/formats/psd/psd_channel.dart index 9ac30357..d63620f8 100644 --- a/lib/src/formats/psd/psd_channel.dart +++ b/lib/src/formats/psd/psd_channel.dart @@ -1,3 +1,4 @@ +import 'dart:math'; import 'dart:typed_data'; import '../../util/image_exception.dart'; @@ -19,7 +20,7 @@ class PsdChannel { int id; int? dataLength; - late Uint8List data; + Uint8List? data; PsdChannel(this.id, this.dataLength); @@ -38,6 +39,9 @@ class PsdChannel { void readPlane(InputBuffer input, int width, int height, int? bitDepth, [int? compression, Uint16List? lineLengths, int planeNum = 0]) { + if (input.length < 2) { + return; + } compression ??= input.readUint16(); switch (compression) { @@ -70,7 +74,7 @@ class PsdChannel { } if (len > input.length) { data = Uint8List(len); - data.fillRange(0, len, 255); + data!.fillRange(0, len, 255); return; } @@ -88,23 +92,27 @@ class PsdChannel { var pos = 0; var lineIndex = planeNum * height; if (lineIndex >= lineLengths.length) { - data.fillRange(0, data.length, 255); + data!.fillRange(0, data!.length, 255); return; } for (var i = 0; i < height; ++i) { final len = lineLengths[lineIndex++]; final s = input.readBytes(len); - _decodeRLE(s, data, pos); + _decodeRLE(s, data!, pos); pos += width; } } void _decodeRLE(InputBuffer src, Uint8List dst, int dstIndex) { while (!src.isEOS) { - var n = src.readInt8(); + var n = 0; + n = src.readInt8(); if (n < 0) { n = 1 - n; + if (src.isEOS) { + break; + } final b = src.readByte(); if ((dstIndex + n) > dst.length) { n = dst.length - dstIndex; @@ -117,6 +125,7 @@ class PsdChannel { if ((dstIndex + n) > dst.length) { n = dst.length - dstIndex; } + n = min(n, src.length); for (var i = 0; i < n; ++i) { dst[dstIndex++] = src.readByte(); } diff --git a/lib/src/formats/psd/psd_image.dart b/lib/src/formats/psd/psd_image.dart index 4c4de514..1cce562f 100644 --- a/lib/src/formats/psd/psd_image.dart +++ b/lib/src/formats/psd/psd_image.dart @@ -41,6 +41,15 @@ class PsdImage implements DecodeInfo { final imageResources = {}; bool hasAlpha = false; + static const resourceBlockSignature = 0x3842494d; // '8BIM' + + late InputBuffer? _input; + + //InputBuffer? _colorData; + InputBuffer? _imageResourceData; + InputBuffer? _layerAndMaskData; + InputBuffer? _imageData; + @override Color? get backgroundColor => null; @@ -53,14 +62,13 @@ class PsdImage implements DecodeInfo { } var len = _input!.readUint32(); - /*_colorData =*/ - _input!.readBytes(len); + /*_colorData =*/ _input!.readBytes(len); len = _input!.readUint32(); - /*_imageResourceData =*/ _input!.readBytes(len); + _imageResourceData = _input!.readBytes(len); len = _input!.readUint32(); - /*_layerAndMaskData =*/ _input!.readBytes(len); + _layerAndMaskData = _input!.readBytes(len); _imageData = _input!.readBytes(_input!.length); } @@ -85,16 +93,16 @@ class PsdImage implements DecodeInfo { // Image Resource Block: // Image resources are used to store non-pixel data associated with images, // such as pen tool paths. - //_readImageResources(); + _readImageResources(); - //_readLayerAndMaskData(); + _readLayerAndMaskData(); _readMergeImageData(); _input = null; //_colorData = null; - //_imageResourceData = null; - //_layerAndMaskData = null; + _imageResourceData = null; + _layerAndMaskData = null; _imageData = null; return true; @@ -408,7 +416,7 @@ class PsdImage implements DecodeInfo { // TODO support indexed and duotone images. } - /*void _readImageResources() { + void _readImageResources() { _imageResourceData!.rewind(); while (!_imageResourceData!.isEOS) { final blockSignature = _imageResourceData!.readUint32(); @@ -433,9 +441,9 @@ class PsdImage implements DecodeInfo { PsdImageResource(blockId, blockName, blockData); } } - }*/ + } - /*void _readLayerAndMaskData() { + void _readLayerAndMaskData() { _layerAndMaskData!.rewind(); var len = _layerAndMaskData!.readUint32(); if ((len & 1) != 0) { @@ -484,7 +492,7 @@ class PsdImage implements DecodeInfo { /*int kind =*/ ..readByte(); } - }*/ + } void _readMergeImageData() { _imageData!.rewind(); @@ -509,8 +517,8 @@ class PsdImage implements DecodeInfo { colorMode, depth, width, height, mergeImageChannels); } - static int _ch(List data, int si, int ns) => - ns == 1 ? data[si] : ((data[si] << 8) | data[si + 1]) >> 8; + static int _ch(List? data, int si, int ns) => + data == null ? 0 : ns == 1 ? data[si] : ((data[si] << 8) | data[si + 1]) >> 8; static Image createImageFromChannels(PsdColorMode? colorMode, int? bitDepth, int width, int height, List channelList) { @@ -596,13 +604,4 @@ class PsdImage implements DecodeInfo { return output; } - - static const resourceBlockSignature = 0x3842494d; // '8BIM' - - late InputBuffer? _input; - - //InputBuffer _colorData; - //late InputBuffer? _imageResourceData; - //late InputBuffer? _layerAndMaskData; - late InputBuffer? _imageData; } diff --git a/lib/src/util/input_buffer.dart b/lib/src/util/input_buffer.dart index bdadde20..32a27ac4 100644 --- a/lib/src/util/input_buffer.dart +++ b/lib/src/util/input_buffer.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:math'; import 'dart:typed_data'; import 'bit_utils.dart'; @@ -16,14 +17,16 @@ class InputBuffer { InputBuffer(this.buffer, {this.bigEndian = false, this.offset = 0, int? length}) : start = offset, - end = (length == null) ? buffer.length : offset + length; + end = min( + buffer.length, (length == null) ? buffer.length : offset + length); /// Create a copy of [other]. InputBuffer.from(InputBuffer other, {int offset = 0, int? length}) : buffer = other.buffer, offset = other.offset + offset, start = other.start, - end = (length == null) ? other.end : other.offset + offset + length, + end = min(other.buffer.length, + (length == null) ? other.end : other.offset + offset + length), bigEndian = other.bigEndian; /// The current read position relative to the start of the buffer.