Skip to content

Commit

Permalink
Merge pull request #891 from blikblum/fix-grayscale-png
Browse files Browse the repository at this point in the history
Fix transparent grayscale png
  • Loading branch information
blikblum authored Dec 24, 2018
2 parents eb60ed1 + acbeceb commit 2955161
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 7 deletions.
13 changes: 7 additions & 6 deletions lib/image/png.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ class PNGImage {

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

} else if (this.image.transparency.rgb) {
Expand Down Expand Up @@ -109,17 +109,18 @@ class PNGImage {
splitAlphaChannel() {
return this.image.decodePixels(pixels => {
let a, p;
const colorByteSize = (this.image.colors * this.image.bits) / 8;
const colorCount = this.image.colors;
const colorByteSize = (colorCount * this.image.bits) / 8;
const pixelCount = this.width * this.height;
const imgData = new Buffer(pixelCount * colorByteSize);
const alphaChannel = new Buffer(pixelCount);

let i = p = a = 0;
const len = pixels.length;
while (i < len) {
imgData[p++] = pixels[i++];
imgData[p++] = pixels[i++];
imgData[p++] = pixels[i++];
for (let colorIndex = 0; colorIndex < colorCount; colorIndex++) {
imgData[p++] = pixels[i++];
}
alphaChannel[a++] = pixels[i++];
}

Expand Down
Binary file added tests/images/glassware-noisy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/images/pngsuite-gray-transparent-black.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/images/pngsuite-gray-transparent-white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/images/pngsuite-rgb-transparent-white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
169 changes: 168 additions & 1 deletion tests/unit/png.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe("PNGImage", () => {
const img = new PNGImage(fs.readFileSync(fileName), "I1");
// noop data manipulation methods
img.loadIndexedAlphaChannel = () => {
if (img.image.hasAlphaChannel) {
if (img.image.transparency.indexed) {
img.alphaChannel = {};
}
};
Expand Down Expand Up @@ -59,6 +59,38 @@ describe("PNGImage", () => {
});
});

test("RGB white transparent", () => {
// ImageWidth = 32
// ImageHeight = 32
// BitDepth = 16
// ColorType = 2
// Compression = 0
// Filter = 0
// Interlace = 0

const img = createImage("./tests/images/pngsuite-rgb-transparent-white.png");

expect(img.obj.data).toMatchObject({
BitsPerComponent: 16,
ColorSpace: "DeviceRGB",
Filter: "FlateDecode",
Height: 32,
Length: 1932,
Subtype: "Image",
Type: "XObject",
Width: 32,
Mask: [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
DecodeParms: expect.any(PDFReference)
});

expect(img.obj.data.DecodeParms.data).toMatchObject({
BitsPerComponent: 16,
Colors: 3,
Columns: 32,
Predictor: 15
});
});

test("RGB with Alpha", () => {
// ImageWidth = 409
// ImageHeight = 400
Expand Down Expand Up @@ -129,6 +161,141 @@ describe("PNGImage", () => {
});
});

test("Pallete indexed transparency", () => {
// ImageWidth = 32
// ImageHeight = 32
// BitDepth = 8
// ColorType = 3
// Compression = 0
// Filter = 0
// Interlace = 0

const img = createImage("./tests/images/pngsuite-palette-transparent-white.png");

expect(img.obj.data).toMatchObject({
BitsPerComponent: 8,
ColorSpace: ["Indexed", "DeviceRGB", 244, expect.any(PDFReference)],
Filter: "FlateDecode",
Height: 32,
Length: 650,
Subtype: "Image",
Type: "XObject",
Width: 32,
DecodeParms: expect.any(PDFReference),
SMask: expect.any(PDFReference),
});

expect(img.obj.data.DecodeParms.data).toMatchObject({
BitsPerComponent: 8,
Colors: 1,
Columns: 32,
Predictor: 15
});

expect(img.obj.data.SMask.data).toMatchObject({
BitsPerComponent: 8,
ColorSpace: "DeviceGray",
Decode: [
0,
1
],
Filter: "FlateDecode",
Height: 32,
Length: 16,
Subtype: "Image",
Type: "XObject",
Width: 32,
});
});

test("Grayscale", () => {
// ImageWidth = 428
// ImageHeight = 320
// BitDepth = 8
// ColorType = 0
// Compression = 0
// Filter = 0
// Interlace = 0

const img = createImage("./tests/images/glassware-noisy.png");

expect(img.obj.data).toMatchObject({
BitsPerComponent: 8,
ColorSpace: "DeviceGray",
Filter: "FlateDecode",
Height: 428,
Length: 82633,
Subtype: "Image",
Type: "XObject",
Width: 320,
DecodeParms: expect.any(PDFReference),
});
});

test("Grayscale black transparent", () => {
// ImageWidth = 32
// ImageHeight = 32
// BitDepth = 4
// ColorType = 0
// Compression = 0
// Filter = 0
// Interlace = 0

const img = createImage("./tests/images/pngsuite-gray-transparent-black.png");

expect(img.obj.data).toMatchObject({
BitsPerComponent: 4,
ColorSpace: "DeviceGray",
Filter: "FlateDecode",
Height: 32,
Length: 328,
Subtype: "Image",
Type: "XObject",
Width: 32,
Mask: [0, 0],
DecodeParms: expect.any(PDFReference),
});

expect(img.obj.data.DecodeParms.data).toMatchObject({
BitsPerComponent: 4,
Colors: 1,
Columns: 32,
Predictor: 15
});
});

test("Grayscale white transparent", () => {
// ImageWidth = 32
// ImageHeight = 32
// BitDepth = 16
// ColorType = 0
// Compression = 0
// Filter = 0
// Interlace = 0

const img = createImage("./tests/images/pngsuite-gray-transparent-white.png");

expect(img.obj.data).toMatchObject({
BitsPerComponent: 16,
ColorSpace: "DeviceGray",
Filter: "FlateDecode",
Height: 32,
Length: 1212,
Subtype: "Image",
Type: "XObject",
Width: 32,
Mask: [255, 255],
DecodeParms: expect.any(PDFReference),
});

expect(img.obj.data.DecodeParms.data).toMatchObject({
BitsPerComponent: 16,
Colors: 1,
Columns: 32,
Predictor: 15
});
});

test("Grayscale with Alpha", () => {
// ImageWidth = 112
// ImageHeight = 112
Expand Down

0 comments on commit 2955161

Please sign in to comment.