tags:

views:

241

answers:

1

I am trying to read in a scanned image and compress it from a DIB in memory into a TIF file. I am using the libtiff library and have found a couple examples online but none of them really do as I need them to. I need to take the image from the DIB and turn it into a B&W image.

Here is the code I have modified from an online example. It does turn it black and white but it also only shows one section of the scan rather than the whole thing. Any help would be appreciated.

EDIT*: I've noticed this happens if I scan it in as a gray image, if I scan it in as black and white then the image that is returned is entirely black, I don't know if this helps at all.

// set up the image tags 
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, w);
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, h);
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1);
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
TIFFSetField(tif, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1);
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_NONE);
TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);

unsigned char * psrc = (unsigned char *)lpBits;
unsigned char * pdst = new unsigned char[(w)];

UINT32 src_index;
UINT32 dst_index;

// now go line by line to write out the image data
for (unsigned int row = 0; row < h; row++ )
{

    // initialize the scan line to zero
    memset(pdst,0,(size_t)(w));

    // moving the data from the dib to a row structure that
    // can be used by the tiff library
    for (unsigned int col = 0; col < w; col++){
        src_index = (h - row - 1) * total_width * bytecount
                                  + col * bytecount;
        dst_index = col;
        pdst[dst_index++] = psrc[src_index+2];
        pdst[dst_index++] = psrc[src_index+1];
        pdst[dst_index] = psrc[src_index];
        result++;
    }

    // now actually write the row data
    TIFFWriteScanline(tif, pdst, row, 0);
}
A: 

I may be wrong, but I think that for CCITTFAX4 encoding libtiff expects eight pixels per byte, padded to the end of the byte if the image width is not divisible by 8.

If the width of the image is 150, for example, the scanline should be 19 bytes, not 150.

There is a good example of using libtiff here, though it does not include cutting the color information off at a threshold and packing the pixels 8 per byte.

R Ubben
I just tried this, its closer, kind of. I used his code and rather than 25*8 used w*8, so as you would figure, the image is really wide, but now I can see the whole image rather than just part of it. It is distorted being so wide though. So if I could figure out how to go about packing the pixels 8 per byte, I may be able to fix this problem, I just don't know how to go about doing this.
netadptr0719
Well, not only that, but if you start with a color or greyscale image, you have to apply a threshold. So, you go through w pixels. If the average value of the pixel is 127 or less, you set the corresponding bit to 0, (black) else set it to 1. (white) You can adjust the threshold up or down, but 127 should usually work. Packing the pixels should not be difficult. Just loop through the line, use mod 8 to tell which bit to set, and or your byte to set that bit. (mod 8 result is 2, for example, or the byte with 04) When you a mod result of 7, or the byte with 128 and move to the next byte.
R Ubben
This put me in the right direction and I got it working, thank you.
netadptr0719
Great! If it comes up, be careful about widths that are not divisible by 8. I have seen a few CCITT fax4 decoders that don't meet the standard and can't handle it.
R Ubben