/************************************************************************* * * Source file for Windows 95/Win32. * * The function LoadTIFFinDIB in this source file let you load * a TIFF file and build a memory DIB with it and return the * HANDLE (HDIB) of the memory block containing the DIB. * * Example : * * HDIB hDIB; * hDIB = LoadTIFFinDIB("sample.tif"); * * * To build this source file you must include the TIFF library * in your project. * * 4/12/95 Philippe Tenenhaus 100423.3705@compuserve.com * ************************************************************************/ #include "tiffio.h" #define HDIB HANDLE #define IS_WIN30_DIB(lpbi) ((*(LPDWORD)(lpbi)) == sizeof(BITMAPINFOHEADER)) #define CVT(x) (((x)*255L) / ((1L << 16) - 1)) static HDIB CreateDIB(DWORD dwWidth, DWORD dwHeight, WORD wBitCount); static LPSTR FindDIBBits(LPSTR lpDIB); static WORD PaletteSize(LPSTR lpDIB); static WORD DIBNumColors(LPSTR lpDIB); static int checkcmap(int n, uint16_t *r, uint16_t *g, uint16_t *b); /************************************************************************* * * HDIB LoadTIFFinDIB(LPSTR lpFileName) * * Parameter: * * LPSTR lpDIB - File name of a tiff imag * * Return Value: * * LPSTR - HANDLE of a DIB * * Description: * * This function load a TIFF file and build a memory DIB with it * and return the HANDLE (HDIB) of the memory block containing * the DIB. * * 4/12/95 Philippe Tenenhaus 100423.3705@compuserve.com * ************************************************************************/ HDIB LoadTIFFinDIB(LPSTR lpFileName) { TIFF *tif; unsigned long imageLength; unsigned long imageWidth; unsigned int BitsPerSample; unsigned long LineSize; unsigned int SamplePerPixel; unsigned long RowsPerStrip; int PhotometricInterpretation; long nrow; unsigned long row; char *buf; LPBITMAPINFOHEADER lpDIB; HDIB hDIB; char *lpBits; HGLOBAL hStrip; int i, l; int Align; tif = TIFFOpen(lpFileName, "r"); if (!tif) goto TiffOpenError; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imageWidth); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imageLength); TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample); TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &RowsPerStrip); TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &RowsPerStrip); TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &PhotometricInterpretation); LineSize = TIFFScanlineSize(tif); // Number of byte in ine line SamplePerPixel = (int)(LineSize / imageWidth); // Align = Number of byte to add at the end of each line of the DIB Align = 4 - (LineSize % 4); if (Align == 4) Align = 0; // Create a new DIB hDIB = CreateDIB((DWORD)imageWidth, (DWORD)imageLength, (WORD)(BitsPerSample * SamplePerPixel)); lpDIB = (LPBITMAPINFOHEADER)GlobalLock(hDIB); if (!lpDIB) goto OutOfDIBMemory; if (lpDIB) lpBits = FindDIBBits((LPSTR)lpDIB); else lpBits = NULL; // In the tiff file the lines are save from up to down // In a DIB the lines must be save from down to up if (lpBits) { lpBits = FindDIBBits((LPSTR)lpDIB); lpBits += ((imageWidth * SamplePerPixel) + Align) * (imageLength - 1); // now lpBits pointe on the bottom line hStrip = GlobalAlloc(GHND, TIFFStripSize(tif)); buf = GlobalLock(hStrip); if (!buf) goto OutOfBufMemory; // PhotometricInterpretation = 2 image is RGB // PhotometricInterpretation = 3 image have a color palette if (PhotometricInterpretation == 3) { uint16_t *red; uint16_t *green; uint16_t *blue; int16_t i; LPBITMAPINFO lpbmi; int Palette16Bits; TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue); // Is the palette 16 or 8 bits ? if (checkcmap(1 << BitsPerSample, red, green, blue) == 16) Palette16Bits = TRUE; else Palette16Bits = FALSE; lpbmi = (LPBITMAPINFO)lpDIB; // load the palette in the DIB for (i = (1 << BitsPerSample) - 1; i >= 0; i--) { if (Palette16Bits) { lpbmi->bmiColors[i].rgbRed = (BYTE)CVT(red[i]); lpbmi->bmiColors[i].rgbGreen = (BYTE)CVT(green[i]); lpbmi->bmiColors[i].rgbBlue = (BYTE)CVT(blue[i]); } else { lpbmi->bmiColors[i].rgbRed = (BYTE)red[i]; lpbmi->bmiColors[i].rgbGreen = (BYTE)green[i]; lpbmi->bmiColors[i].rgbBlue = (BYTE)blue[i]; } } } // read the tiff lines and save them in the DIB // with RGB mode, we have to change the order of the 3 samples RGB <=> BGR for (row = 0; row < imageLength; row += RowsPerStrip) { nrow = (row + RowsPerStrip > imageLength ? imageLength - row : RowsPerStrip); if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0), buf, nrow * LineSize) == -1) { goto TiffReadError; } else { for (l = 0; l < nrow; l++) { if (SamplePerPixel == 3) for (i = 0; i < (int)(imageWidth); i++) { lpBits[i * SamplePerPixel + 0] = buf[l * LineSize + i * Sample PerPixel + 2]; lpBits[i * SamplePerPixel + 1] = buf[l * LineSize + i * Sample PerPixel + 1]; lpBits[i * SamplePerPixel + 2] = buf[l * LineSize + i * Sample PerPixel + 0]; } else memcpy(lpBits, &buf[(int)(l * LineSize)], (int)imageWidth * SamplePerPixel); lpBits -= imageWidth * SamplePerPixel + Align; } } } GlobalUnlock(hStrip); GlobalFree(hStrip); GlobalUnlock(hDIB); TIFFClose(tif); } return hDIB; OutOfBufMemory: TiffReadError: GlobalUnlock(hDIB); GlobalFree(hStrip); OutOfDIBMemory: TIFFClose(tif); TiffOpenError: return (HANDLE)0; } static int checkcmap(int n, uint16_t *r, uint16_t *g, uint16_t *b) { while (n-- > 0) if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256) return (16); return (8); } /************************************************************************* * All the following functions were created by microsoft, they are * parts of the sample project "wincap" given with the SDK Win32. * * Microsoft says that : * * You have a royalty-free right to use, modify, reproduce and * distribute the Sample Files (and/or any modified version) in * any way you find useful, provided that you agree that * Microsoft has no warranty obligations or liability for any * Sample Application Files which are modified. * ************************************************************************/ HDIB CreateDIB(DWORD dwWidth, DWORD dwHeight, WORD wBitCount) { BITMAPINFOHEADER bi; // bitmap header LPBITMAPINFOHEADER lpbi; // pointer to BITMAPINFOHEADER DWORD dwLen; // size of memory block HDIB hDIB; DWORD dwBytesPerLine; // Number of bytes per scanline // Make sure bits per pixel is valid if (wBitCount <= 1) wBitCount = 1; else if (wBitCount <= 4) wBitCount = 4; else if (wBitCount <= 8) wBitCount = 8; else if (wBitCount <= 24) wBitCount = 24; else wBitCount = 4; // set default value to 4 if parameter is bogus // initialize BITMAPINFOHEADER bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = dwWidth; // fill in width from parameter bi.biHeight = dwHeight; // fill in height from parameter bi.biPlanes = 1; // must be 1 bi.biBitCount = wBitCount; // from parameter bi.biCompression = BI_RGB; bi.biSizeImage = (dwWidth * dwHeight * wBitCount) / 8; // 0; // 0's here mean "default" bi.biXPelsPerMeter = 2834; // 0; bi.biYPelsPerMeter = 2834; // 0; bi.biClrUsed = 0; bi.biClrImportant = 0; // calculate size of memory block required to store the DIB. This // block should be big enough to hold the BITMAPINFOHEADER, the color // table, and the bits dwBytesPerLine = (((wBitCount * dwWidth) + 31) / 32 * 4); dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + (dwBytesPerLine * dwHeight); // alloc memory block to store our bitmap hDIB = GlobalAlloc(GHND, dwLen); // major bummer if we couldn't get memory block if (!hDIB) { return NULL; } // lock memory and get pointer to it lpbi = (VOID FAR *)GlobalLock(hDIB); // use our bitmap info structure to fill in first part of // our DIB with the BITMAPINFOHEADER *lpbi = bi; // Since we don't know what the colortable and bits should contain, // just leave these blank. Unlock the DIB and return the HDIB. GlobalUnlock(hDIB); /* return handle to the DIB */ return hDIB; } LPSTR FAR FindDIBBits(LPSTR lpDIB) { return (lpDIB + *(LPDWORD)lpDIB + PaletteSize(lpDIB)); } WORD FAR PaletteSize(LPSTR lpDIB) { /* calculate the size required by the palette */ if (IS_WIN30_DIB(lpDIB)) return (DIBNumColors(lpDIB) * sizeof(RGBQUAD)); else return (DIBNumColors(lpDIB) * sizeof(RGBTRIPLE)); } WORD DIBNumColors(LPSTR lpDIB) { WORD wBitCount; // DIB bit count /* If this is a Windows-style DIB, the number of colors in the * color table can be less than the number of bits per pixel * allows for (i.e. lpbi->biClrUsed can be set to some value). * If this is the case, return the appropriate value. */ if (IS_WIN30_DIB(lpDIB)) { DWORD dwClrUsed; dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed; if (dwClrUsed) return (WORD)dwClrUsed; } /* Calculate the number of colors in the color table based on * the number of bits per pixel for the DIB. */ if (IS_WIN30_DIB(lpDIB)) wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount; else wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount; /* return number of colors based on bits per pixel */ switch (wBitCount) { case 1: return 2; case 4: return 16; case 8: return 256; default: return 0; } }