Question

I'm observing "mirroring" effect when I process image that comes from a scanner through libtiff.net.

Here is my code:

public static byte[] GetTiffImageBytes(byte[] win32Bitmap, WinApi.BITMAPINFOHEADER infoHeader)
{
    try
    {
        using (var ms = new MemoryStream())
        {
            using (Tiff tif = Tiff.ClientOpen("InMemory", "w", ms, new TiffStream()))
            {
                if (tif == null)
                    return null;

                tif.SetField(TiffTag.IMAGEWIDTH, infoHeader.biWidth);
                tif.SetField(TiffTag.IMAGELENGTH, infoHeader.biHeight);
                tif.SetField(TiffTag.COMPRESSION, Compression.CCITTFAX4);
                tif.SetField(TiffTag.PHOTOMETRIC, Photometric.MINISBLACK);
                tif.SetField(TiffTag.ROWSPERSTRIP, infoHeader.biHeight);

                // TODO: ? Used to be resolutions?
                tif.SetField(TiffTag.XRESOLUTION, infoHeader.biWidth);
                tif.SetField(TiffTag.YRESOLUTION, infoHeader.biHeight);

                tif.SetField(TiffTag.SUBFILETYPE, 0);
                tif.SetField(TiffTag.BITSPERSAMPLE, 1);
                tif.SetField(TiffTag.FILLORDER, FillOrder.MSB2LSB);
                tif.SetField(TiffTag.ORIENTATION, Orientation.TOPLEFT);

                tif.SetField(TiffTag.SAMPLESPERPIXEL, 1);
                tif.SetField(TiffTag.T6OPTIONS, 0);
                tif.SetField(TiffTag.RESOLUTIONUNIT, ResUnit.INCH);

                tif.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);

                // Image "stride" is a lenght in bytes of one pixel row
                var stride = infoHeader.biSizeImage / infoHeader.biHeight;
                var offset = infoHeader.biSize;

                // raster stride MAY be bigger than TIFF stride (due to padding in raster bits)
                for (int i = 0; i < infoHeader.biHeight; i++)
                {
                    var res = tif.WriteScanline(win32Bitmap, offset, i, 1);
                    if (!res) return null;

                    offset += stride;
                }
            }

            return ms.GetBuffer();
        }
    }
    catch (Exception ex)
    {
        return null;
    }
}

I adapted this code from following sample: http://bitmiracle.com/libtiff/help/convert-system.drawing.bitmap-to-a-black-and-white-tiff.aspx

win32 bitmap that passed in have header (also duplicated as parameter). Basically, I copy rows of data into TIFF and I do get image but it is mirrored and looks like this: I am very new to win32 code (this bitmap is from twain driver) and not sure if it's OS related.

I call win32 via P-Invoke from Silvrlight and I get bitmap back and process inside Silverlight's version of LibTiff.net. I think I need to "mirror" scan lines when I add them to TIFF but I wonder if I need to re-invent wheel or it's already somehow included in a library?

See how image comes up when I process it using code above:

enter image description here

EDIT

Changed following line:

tif.SetField(TiffTag.ORIENTATION, Orientation.TOPLEFT);

So it says BOTTOMLEFT and it fixed it for my application. When I read and display data with LibTiff it works. BUT! It doesn't display properly in windows image viewer. Is it safer to just flip data order?

Was it helpful?

Solution

Windows bitmaps are stored with the bottom line first. Basically they use Cartesian coordinate system which puts point (0,0) in the bottom left.

So, you are probably should just adapt the for loop in you code that writes scanlines (make it write scanlines in inverse order).

Using TiffTag.ORIENTATION tag is a solution too, but the problem is: most viewers ignore this tag completely.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top