sharp icon indicating copy to clipboard operation
sharp copied to clipboard

TIFF output, bitdepth of 1 with LZW compression, should ignore predictor

Open MosheL opened this issue 1 year ago • 6 comments

Possible bug

Is this a possible bug in a feature of sharp, unrelated to installation?

  • [x] Running npm install sharp completes without error.
  • [x] Running node -e "require('sharp')" completes without error.
  • [x] I am using the latest version of sharp as reported by npm view sharp dist-tags.latest.

What is the output of running npx envinfo --binaries --system --npmPackages=sharp --npmGlobalPackages=sharp?

System: OS: Windows 10 10.0.22621 CPU: (6) x64 Intel(R) Core(TM) i5-8600K CPU @ 3.60GHz Memory: 20.28 GB / 63.95 GB Binaries: Node: 19.2.0 - C:\Program Files\nodejs\node.EXE npm: 9.1.3 - C:\Program Files\nodejs\npm.CMD

(tried also node 16.x and npm 8.x)

What are the steps to reproduce?

image.toColorspace('b-w').toFormat('tiff', { bitdepth: 1 }) // works, exports a 1-bit tiff file
image.toColorspace('b-w').toFormat('tiff', { bitdepth: 1, compression: 'lzw' }) // works, but exports a 24-bit file.

What is the expected behaviour?

the second row will export a 1-bit (or 2 or 4) bit TIFF file.

Thanks for all ! I like the package and it works good and fast.

MosheL avatar Dec 12 '22 15:12 MosheL

Hi, I had to add predictor: 'none' to the second example to prevent the following error:

Horizontal differencing "Predictor" not supported with 1-bit samples

await sharp(input)
  .toColorspace("b-w")
  .toFormat("tiff", { bitdepth: 1 })
  .toFile("out1.tiff");

await sharp(input)
  .toColorspace("b-w")
  .toFormat("tiff", { bitdepth: 1, compression: "lzw", predictor: "none" })
  .toFile("out2.tiff");

Then, with this input, the output was as expected (latest version, using Linux):

$ ls *.tiff
 759008 out1.tiff
  77446 out2.tiff

$ tiffinfo out1.tiff 
TIFF Directory at offset 0x758734 (b93ce)
  Image Width: 2725 Image Length: 2225
  Resolution: 25.4, 25.4 pixels/inch
  Bits/Sample: 1
  Sample Format: unsigned integer
  Compression Scheme: None
  Photometric Interpretation: min-is-black
  Orientation: row 0 top, col 0 lhs
  Samples/Pixel: 1
  Rows/Strip: 256
  Planar Configuration: single image plane

$ tiffinfo out2.tiff 
TIFF Directory at offset 0x77172 (12d74)
  Image Width: 2725 Image Length: 2225
  Resolution: 25.4, 25.4 pixels/inch
  Bits/Sample: 1
  Sample Format: unsigned integer
  Compression Scheme: LZW
  Photometric Interpretation: min-is-black
  Orientation: row 0 top, col 0 lhs
  Samples/Pixel: 1
  Rows/Strip: 256
  Planar Configuration: single image plane

If you're still having problems, please provide complete, standalone code with input image that allows someone else to reproduce.

lovell avatar Dec 13 '22 09:12 lovell

Thanks for response.

For me, you solve the problem. Thanks. maybe this need to be documented somewhere for the next developer.

MosheL avatar Dec 13 '22 16:12 MosheL

The error message is relatively self-explanatory, but this might be something we should address upstream in libvips so it ignores the predictor for 1 bpp images.

lovell avatar Dec 13 '22 16:12 lovell

there is no error message. the code in the example is working byt responded with a 24-bit. an error can be good.

thanks.

MosheL avatar Dec 13 '22 16:12 MosheL

When specifying { bitdepth: 1, compression: 'lzw' } I always receive an error message plus a partial output that might look like 24-bit but has been truncated.

If you don't see the error message, please can you provide a sample image and complete, standalone code that includes appropriate error handling, which might allow someone else to reproduce.

lovell avatar Dec 13 '22 17:12 lovell

You are right, but not always.

When I am using a image without alpha channel, it working as you descibe in your comment. but if not, it not working as my bug is described.

I was used sharp-bmp here. sharp-bmp is working by exporting a 4-channel picture. When I was used a 1-bpp PNG image it was works (or more, but without Alpha channel).

here is a working example code, as I added .removeAlpha() before saving.

const sharp = require("sharp")
const fs = require("fs/promises")
const bmp = require('sharp-bmp');

async function a() {
	const buffer = await fs.readFile('./1.bmp');
	var bitmap = bmp.decode(buffer);

	//image = await sharp(buffer);
	image = await sharp(bitmap.data, {
		raw: {
			width: bitmap.width,
			height: bitmap.height,
			channels: 4,
		},
	})
	///image = await sharp(buffer);
	const md = await image.metadata();
	bpp = md.paletteBitDepth || 4;
	console.log(bpp);

	await image.toColorspace('b-w').removeAlpha().toFormat('tiff', { bitdepth: 1, compression: "lzw", predictor: "none" })
		.toFile(`./1.tiff`);

	image = await sharp(bitmap.data, {
		raw: {
			width: bitmap.width,
			height: bitmap.height,
			channels: 4,
		},
	})

	await image.toColorspace('b-w').toFormat('tiff', { bitdepth: 1 })
		.toFile(`./2.tiff`);
}
a()

MosheL avatar Jan 01 '23 09:01 MosheL