bwip-js icon indicating copy to clipboard operation
bwip-js copied to clipboard

PNG grayscale support

Open phaseOne opened this issue 4 years ago • 4 comments

The feature request

It would be fantastic if bwip-js could export grayscale (monochromatic) PNGs in place of RGB. This would offer more control when printing and when importing into applications that support CMYK. Thanks!

I'm not too familiar with the PNG data structures at the moment, but it seems the place to start adding this functionality would be in DrawingZlibPng(opts, callback) https://github.com/metafloor/bwip-js/blob/d6a5c1ed980fa37ea2826dcb94ace70ce6433715/src/drawing-zlibpng.js#L25

The issue

I'm facing a bit of a challenge when bringing barcode PNGs into Adobe InDesign for CMYK documents. Since bwip-js exports PNGs as RGB, the barcode will print as CMYK(75, 68, 67, 90) which can result in a messy barcode when there's misalignment between the plates. I'm looking for that sweet CMYK(0,0,0,100).

Workaround

Apply a Generic Gray Profile as a post-process step. You can do this pretty quickly in macOS Automator. CleanShot 2021-01-12 at 17 19 08@2x

Alternative solutions

I'd use CMYK in SVG, but that isn't completely standardized and adopted yet.

If there would be a way to get an EPS out of bwip-js, that could work as well.

phaseOne avatar Jan 13 '21 01:01 phaseOne

I need to review the source for the built-in drawing modules. There is common core code used by both the html canvas interface and node that would be impacted by this request.

metafloor avatar Jan 13 '21 17:01 metafloor

I think it best to punt on this issue for right now. Changing the built-in drawing code is problematic as it has no a priori knowledge of color depth.

Conversely, it takes very little code to post-process an RGBA PNG to grayscale. For example, using the pngjs module, you could change your callback (or Promise then) handler to do the conversion:

const PNG = require('pngjs').PNG;

bwipjs.toBuffer({ ... }, function(err, png) {
    new PNG({ colorType:0 }).parse(png).on("parsed", function() {
        this.pack().pipe(fs.createWriteStream("gray.png"));
    });
});

colorType:0 creates a grayscale image with default #ffffff substituted/alpha-blended for any transparent pixels.

Not sure your experience with javascript so if you need more details on this, let me know.

metafloor avatar Jan 14 '21 00:01 metafloor

@metafloor thanks for the pngjs suggestion and sample code! It would be nice to reduce the number of dependencies and have bwip-js generate the desired output, but I'm not constrained on resources for this application, so this is a reasonable approach for now. I'll give this a try and see if InDesign likes it. Looks like pngjs colorType: 4 is also an option for those who would like to convert to grayscale, but retain the alpha channel. Thanks again!

You're welcome to close this issue to reduce the backlog if you prefer that. I don't think this rises to a priority level for me to work on a PR at this time, but if it gets more votes maybe I'll come back to it.

I think I understand why this would be a big lift to support. Looks like you're creating the image bitmap in RGBA (either as a canvas buffer or node.js Buffer) https://github.com/metafloor/bwip-js/blob/d6a5c1ed980fa37ea2826dcb94ace70ce6433715/src/drawing-canvas.js#L36 https://github.com/metafloor/bwip-js/blob/d6a5c1ed980fa37ea2826dcb94ace70ce6433715/src/drawing-zlibpng.js#L37-L48

And further manipulation (drawing of foreground shapes, background) is done directly in the RGBA bitmap. https://github.com/metafloor/bwip-js/blob/d6a5c1ed980fa37ea2826dcb94ace70ce6433715/src/drawing-builtin.js#L301-L319

So all of that code would have to change to support a grayscale bitmap.

phaseOne avatar Jan 14 '21 01:01 phaseOne

I think you are misunderstanding the issue. The actual code to produce a gray scale png is not difficult. The issue is knowing when it is safe to do so. For example, ultracode requires colors. And many of the BWIPP options can specify RGB values. So all of those conditions would have to be checked. The drawing interfaces get the original options object passed to bwip-js, so it is just a matter of checking whether any of the color-specific BWIPP options specify a non-gray value, and whether the barcode symbol itself requires color support. The code is not difficult but does require vigilance. I don't always pay attention to what new symbols Terry has added to BWIPP. For example, I was surprised to find ultracode in the bwip-js demo one day....

metafloor avatar Jan 25 '21 18:01 metafloor