Skip to content
This repository was archived by the owner on Apr 12, 2021. It is now read-only.

Commit 2955161

Browse files
authored
Merge pull request foliojs#891 from blikblum/fix-grayscale-png
Fix transparent grayscale png
2 parents eb60ed1 + acbeceb commit 2955161

7 files changed

Lines changed: 175 additions & 7 deletions

lib/image/png.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ class PNGImage {
4949

5050
// For PNG color types 0, 2 and 3, the transparency data is stored in
5151
// a dedicated PNG chunk.
52-
if (this.image.transparency.grayscale) {
52+
if (this.image.transparency.grayscale != null) {
5353
// Use Color Key Masking (spec section 4.8.5)
5454
// An array with N elements, where N is two times the number of color components.
55-
const val = this.image.transparency.greyscale;
55+
const val = this.image.transparency.grayscale;
5656
return this.obj.data['Mask'] = [val, val];
5757

5858
} else if (this.image.transparency.rgb) {
@@ -109,17 +109,18 @@ class PNGImage {
109109
splitAlphaChannel() {
110110
return this.image.decodePixels(pixels => {
111111
let a, p;
112-
const colorByteSize = (this.image.colors * this.image.bits) / 8;
112+
const colorCount = this.image.colors;
113+
const colorByteSize = (colorCount * this.image.bits) / 8;
113114
const pixelCount = this.width * this.height;
114115
const imgData = new Buffer(pixelCount * colorByteSize);
115116
const alphaChannel = new Buffer(pixelCount);
116117

117118
let i = p = a = 0;
118119
const len = pixels.length;
119120
while (i < len) {
120-
imgData[p++] = pixels[i++];
121-
imgData[p++] = pixels[i++];
122-
imgData[p++] = pixels[i++];
121+
for (let colorIndex = 0; colorIndex < colorCount; colorIndex++) {
122+
imgData[p++] = pixels[i++];
123+
}
123124
alphaChannel[a++] = pixels[i++];
124125
}
125126

tests/images/glassware-noisy.png

80.9 KB
Loading
429 Bytes
Loading
1.28 KB
Loading
1.46 KB
Loading
1.99 KB
Loading

tests/unit/png.spec.js

Lines changed: 168 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ describe("PNGImage", () => {
1010
const img = new PNGImage(fs.readFileSync(fileName), "I1");
1111
// noop data manipulation methods
1212
img.loadIndexedAlphaChannel = () => {
13-
if (img.image.hasAlphaChannel) {
13+
if (img.image.transparency.indexed) {
1414
img.alphaChannel = {};
1515
}
1616
};
@@ -59,6 +59,38 @@ describe("PNGImage", () => {
5959
});
6060
});
6161

62+
test("RGB white transparent", () => {
63+
// ImageWidth = 32
64+
// ImageHeight = 32
65+
// BitDepth = 16
66+
// ColorType = 2
67+
// Compression = 0
68+
// Filter = 0
69+
// Interlace = 0
70+
71+
const img = createImage("./tests/images/pngsuite-rgb-transparent-white.png");
72+
73+
expect(img.obj.data).toMatchObject({
74+
BitsPerComponent: 16,
75+
ColorSpace: "DeviceRGB",
76+
Filter: "FlateDecode",
77+
Height: 32,
78+
Length: 1932,
79+
Subtype: "Image",
80+
Type: "XObject",
81+
Width: 32,
82+
Mask: [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
83+
DecodeParms: expect.any(PDFReference)
84+
});
85+
86+
expect(img.obj.data.DecodeParms.data).toMatchObject({
87+
BitsPerComponent: 16,
88+
Colors: 3,
89+
Columns: 32,
90+
Predictor: 15
91+
});
92+
});
93+
6294
test("RGB with Alpha", () => {
6395
// ImageWidth = 409
6496
// ImageHeight = 400
@@ -129,6 +161,141 @@ describe("PNGImage", () => {
129161
});
130162
});
131163

164+
test("Pallete indexed transparency", () => {
165+
// ImageWidth = 32
166+
// ImageHeight = 32
167+
// BitDepth = 8
168+
// ColorType = 3
169+
// Compression = 0
170+
// Filter = 0
171+
// Interlace = 0
172+
173+
const img = createImage("./tests/images/pngsuite-palette-transparent-white.png");
174+
175+
expect(img.obj.data).toMatchObject({
176+
BitsPerComponent: 8,
177+
ColorSpace: ["Indexed", "DeviceRGB", 244, expect.any(PDFReference)],
178+
Filter: "FlateDecode",
179+
Height: 32,
180+
Length: 650,
181+
Subtype: "Image",
182+
Type: "XObject",
183+
Width: 32,
184+
DecodeParms: expect.any(PDFReference),
185+
SMask: expect.any(PDFReference),
186+
});
187+
188+
expect(img.obj.data.DecodeParms.data).toMatchObject({
189+
BitsPerComponent: 8,
190+
Colors: 1,
191+
Columns: 32,
192+
Predictor: 15
193+
});
194+
195+
expect(img.obj.data.SMask.data).toMatchObject({
196+
BitsPerComponent: 8,
197+
ColorSpace: "DeviceGray",
198+
Decode: [
199+
0,
200+
1
201+
],
202+
Filter: "FlateDecode",
203+
Height: 32,
204+
Length: 16,
205+
Subtype: "Image",
206+
Type: "XObject",
207+
Width: 32,
208+
});
209+
});
210+
211+
test("Grayscale", () => {
212+
// ImageWidth = 428
213+
// ImageHeight = 320
214+
// BitDepth = 8
215+
// ColorType = 0
216+
// Compression = 0
217+
// Filter = 0
218+
// Interlace = 0
219+
220+
const img = createImage("./tests/images/glassware-noisy.png");
221+
222+
expect(img.obj.data).toMatchObject({
223+
BitsPerComponent: 8,
224+
ColorSpace: "DeviceGray",
225+
Filter: "FlateDecode",
226+
Height: 428,
227+
Length: 82633,
228+
Subtype: "Image",
229+
Type: "XObject",
230+
Width: 320,
231+
DecodeParms: expect.any(PDFReference),
232+
});
233+
});
234+
235+
test("Grayscale black transparent", () => {
236+
// ImageWidth = 32
237+
// ImageHeight = 32
238+
// BitDepth = 4
239+
// ColorType = 0
240+
// Compression = 0
241+
// Filter = 0
242+
// Interlace = 0
243+
244+
const img = createImage("./tests/images/pngsuite-gray-transparent-black.png");
245+
246+
expect(img.obj.data).toMatchObject({
247+
BitsPerComponent: 4,
248+
ColorSpace: "DeviceGray",
249+
Filter: "FlateDecode",
250+
Height: 32,
251+
Length: 328,
252+
Subtype: "Image",
253+
Type: "XObject",
254+
Width: 32,
255+
Mask: [0, 0],
256+
DecodeParms: expect.any(PDFReference),
257+
});
258+
259+
expect(img.obj.data.DecodeParms.data).toMatchObject({
260+
BitsPerComponent: 4,
261+
Colors: 1,
262+
Columns: 32,
263+
Predictor: 15
264+
});
265+
});
266+
267+
test("Grayscale white transparent", () => {
268+
// ImageWidth = 32
269+
// ImageHeight = 32
270+
// BitDepth = 16
271+
// ColorType = 0
272+
// Compression = 0
273+
// Filter = 0
274+
// Interlace = 0
275+
276+
const img = createImage("./tests/images/pngsuite-gray-transparent-white.png");
277+
278+
expect(img.obj.data).toMatchObject({
279+
BitsPerComponent: 16,
280+
ColorSpace: "DeviceGray",
281+
Filter: "FlateDecode",
282+
Height: 32,
283+
Length: 1212,
284+
Subtype: "Image",
285+
Type: "XObject",
286+
Width: 32,
287+
Mask: [255, 255],
288+
DecodeParms: expect.any(PDFReference),
289+
});
290+
291+
expect(img.obj.data.DecodeParms.data).toMatchObject({
292+
BitsPerComponent: 16,
293+
Colors: 1,
294+
Columns: 32,
295+
Predictor: 15
296+
});
297+
});
298+
132299
test("Grayscale with Alpha", () => {
133300
// ImageWidth = 112
134301
// ImageHeight = 112

0 commit comments

Comments
 (0)