Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to get BW image as output - barcode.write() outputs 24 bit (Format24bppRgb) color image #44

Closed
BobTB opened this issue Oct 1, 2017 · 4 comments

Comments

@BobTB
Copy link

BobTB commented Oct 1, 2017

How can I get a black and white image from barcode.write(). What I get is 24 bit 1.03MB big full color image.

I convert it to 1bpp with this

  var x = ZXing.QrCode.Internal.ErrorCorrectionLevel.H;

           var barcodeWriter = new BarcodeWriter 
            {

                Format = barcodeFormat,
                Options = new ZXing.QrCode.QrCodeEncodingOptions
                {
                    CharacterSet = "ISO-8859-2",
                    Width = 600,
                    Height = 600,
                    ErrorCorrection = x,
                    QrVersion = 15
                }
            };

var bitmap = barcodeWriter.Write("ASDASD");
Console.Out.WriteLine(bitmap.PixelFormat);

var targetBmp = bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), pixelFormat.Format1bppIndexed);`
Console.Out.WriteLine(targetBmp.PixelFormat);

But barcodewriter first creates 24bit color 1MB big image, and then I convert it to 1 bit per pixel image which is 43Kb. Is there a parameter where I can set QR code to be just black and white? I have to create 2000 QR codes, and this is just too slow... :(

@BobTB BobTB changed the title Get BW image to clipboard, as is it outputs 32 bit one Get BW image as output - barcode.write() outputs 24 bit (Format24bppRgb) color image Oct 1, 2017
@BobTB
Copy link
Author

BobTB commented Oct 1, 2017

I timed it, one QR code takes approx. 35 msec, and the image is approx 1MB big. With 2000 of them to run, I get 70 seconds runtime. I think that getting BW 1 bit image directly will cut this time a lot.

The cloning and changing to B/W image takes 2 msec.

@BobTB BobTB changed the title Get BW image as output - barcode.write() outputs 24 bit (Format24bppRgb) color image How to get BW image as output - barcode.write() outputs 24 bit (Format24bppRgb) color image Oct 1, 2017
@micjahn
Copy link
Owner

micjahn commented Oct 2, 2017

There is no option available but you can write your own renderer. Take a look at the source code of the BitmapRenderer class. Implement your own BitmapRenderer1bpp, change the line
var bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
and this one
var bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
of the original BitmapRenderer and the different places of the pixel assignments

pixels[index++] = color.B;
pixels[index++] = color.G;
pixels[index++] = color.R;

After that you can use your custom renderer with the BitmapWriter:

  var x = ZXing.QrCode.Internal.ErrorCorrectionLevel.H;

           var barcodeWriter = new BarcodeWriter 
            {

                Format = barcodeFormat,
                Options = new ZXing.QrCode.QrCodeEncodingOptions
                {
                    CharacterSet = "ISO-8859-2",
                    Width = 600,
                    Height = 600,
                    ErrorCorrection = x,
                    QrVersion = 15
                },
                Renderer = new BitmapRenderer1bpp()
            };

var bitmap = barcodeWriter.Write("ASDASD");

@micjahn micjahn closed this as completed Oct 2, 2017
@BobTB
Copy link
Author

BobTB commented Oct 2, 2017

Great. Thank you!

@lellis1936
Copy link

lellis1936 commented Jun 1, 2018

I had a need for this as well and the class I developed is at bottom. It does not support Options or text content but otherwise seems to work fine. Suggestions for improvement are welcome. Not thoroughly tested and only tested with QR codes. Usage is:

var bcWriter = new BarcodeWriter { Renderer = new BitmapRenderer1bpp() };
BitMatrix bitmatrix = writer.encode(qrText, BarcodeFormat.QR_CODE, width, height, myHints);
Bitmap qrMonoBitmap = bcWriter.Write(bitmatrix);

Too bad there is not native support for monochrome QR because they are vastly smaller and substantially quicker to create. And of course black and white output is usually what's desired, not color.

Here's the custom class:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

using ZXing.Common;
using ZXing.OneD;

namespace ZXing.Rendering
{
    /// <summary>
    /// Renders a <see cref="BitMatrix" /> to a <see cref="Bitmap" /> image
    /// </summary>
    public class BitmapRenderer1bpp : IBarcodeRenderer<Bitmap>
    {
        static BitmapRenderer1bpp()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BitmapRenderer"/> class.
        /// </summary>
        public BitmapRenderer1bpp()
        {
        }

        /// <summary>
        /// Renders the specified matrix.
        /// </summary>
        /// <param name="matrix">The matrix.</param>
        /// <param name="format">The format.</param>
        /// <param name="content">The content.</param>
        /// <returns></returns>
        public Bitmap Render(BitMatrix matrix, BarcodeFormat format, string content)
        {
            return Render(matrix, format, content, null);
        }

        /// <summary>
        /// Renders the specified matrix.
        /// </summary>
        /// <param name="matrix">The matrix.</param>
        /// <param name="format">The format.</param>
        /// <param name="content">The content.</param>
        /// <param name="options">The options.</param>
        /// <returns></returns>
        virtual public Bitmap Render(BitMatrix matrix, BarcodeFormat format, string content, EncodingOptions options)
        {
            var width = matrix.Width;
            var height = matrix.Height;

            // create the bitmap and lock the bits because we need the stride
            // which is the width of the image and possible padding bytes
            var bmp = new Bitmap(width, height, PixelFormat.Format1bppIndexed);
            var bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
            try
            {
                var pixels = new byte[bmpData.Stride * height];

                // going through the lines of the matrix
                for (int y = 0; y < matrix.Height; y++)
                {
                    // going through the columns of the current line
                    for (var x = 0; x < matrix.Width; x++)
                    {
                        byte bitValue = (byte)(matrix[x, y] ? 0 : 1);
                        if (bitValue == 1)
                        {
                            pixels[y * bmpData.Stride + (x / 8)] |= (byte)(0x80 >> (x % 8));
                        }
                    }
                }

                //Copy the data from the byte array into BitmapData.Scan0
                Marshal.Copy(pixels, 0, bmpData.Scan0, pixels.Length);
            }
            finally
            {
                //Unlock the pixels
                bmp.UnlockBits(bmpData);
            }

            return bmp;
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants