/*++ Copyright (c) 1997 Microsoft Corporation This file contains the parts of the AWD library that are also TIFF-aware (i.e., conversion routines). Author: Brian Dewey (t-briand) 1997-7-16 --*/ #include #include #include // AWD is an OLE compound document. #include #include "awdlib.h" // Header file for this library. #include "viewrend.h" // AWD rendering library. #include "tifflibp.h" // Need this for the stolen compression routines. // ------------------------------------------------------------ // Defines #define FAX_IMAGE_WIDTH (1728) // ------------------------------------------------------------ // Global variables HANDLE hTiffDest; // Used in the internal OutputPage() // and ConvertAWDToTiff(). // ------------------------------------------------------------ // Internal prototypes BOOL CompressBitmapStrip( PBYTE pBrandBits, LPDWORD pMmrBrandBits, INT BrandHeight, INT BrandWidth, DWORD *DwordsOut, DWORD *BitsOut ); // Routine stolen from tiff library. // Used to be EncodeMmrBranding(). void ConvertWidth(const LPBYTE lpSrc, DWORD dwSrcWidth, LPBYTE lpDest, DWORD dwDestWidth, DWORD dwHeight); BOOL OutputPage(AWD_FILE *psStorages, const WCHAR *pwcsDocName); // ------------------------------------------------------------ // Routines // ConvertAWDToTiff // // This function does exactly what it says. Given the name of an AWD file, it // attempts to convert it to a tiff file. // // Parameters: // pwcsAwdFile name of the AWD file. // pwcsTiffFile name of the TIFF file. // // Returns: // TRUE on successful conversion, FALSE otherwise. // // Author: // Brian Dewey (t-briand) 1997-7-14 BOOL ConvertAWDToTiff(const WCHAR *pwcsAwdFile, WCHAR *pwcsTiffFile) { BOOL bRetVal; // Holds our return value. AWD_FILE sAWDStorages; // Holds the main storages of the AWD file. // Initialization. HeapInitialize(NULL, NULL, NULL, NULL); // Open the source. if(!OpenAWDFile(pwcsAwdFile, &sAWDStorages)) { return FALSE; } // Open the destination hTiffDest = TiffCreate(pwcsTiffFile, TIFF_COMPRESSION_MMR, FAX_IMAGE_WIDTH, 2, // Fill order 2 == LSB2MSB (I think). 1); // HIRES if(hTiffDest == NULL) { CloseAWDFile(&sAWDStorages); return FALSE; } bRetVal = EnumDocuments(&sAWDStorages, OutputPage); CloseAWDFile(&sAWDStorages); TiffClose(hTiffDest); return bRetVal; } // CompressBitmapStrip // // Stolen from Tiff library, where it's called EncodeMmrBranding(). // // Author: ??? BOOL CompressBitmapStrip( PBYTE pBrandBits, LPDWORD pMmrBrandBits, INT BrandHeight, INT BrandWidth, DWORD *DwordsOut, DWORD *BitsOut ) /*++ Routine Description: Encode an MMR branding from uncompressed branding bits. I don't have enough time to write an optimized Uncompressed -> MMR convertor, so the compromise is to use the existing Uncompressed Decoder (fast enough) and use the optimized MMR Encoder. Since we only convert few lines for Branding, it's OK. --*/ { INT a0, a1, a2, b1, b2, distance; LPBYTE prefline; BYTE pZeroline[1728/8]; INT delta = BrandWidth / BYTEBITS; INT Lines = 0; LPDWORD lpdwOut = pMmrBrandBits; BYTE BitOut = 0; #if TIFFDBG _tprintf( TEXT("encoding line #%d\n"), TiffInstance->Lines ); #endif // set first all white reference line prefline = pZeroline; ZeroMemory(pZeroline, BrandWidth/8); // loop til all lines done do { a0 = 0; a1 = GetBit( pBrandBits, 0) ? 0 : NextChangingElement(pBrandBits, 0, BrandWidth, 0 ); b1 = GetBit( prefline, 0) ? 0 : NextChangingElement(prefline, 0, BrandWidth, 0 ); while (TRUE) { b2 = (b1 >= BrandWidth) ? BrandWidth : NextChangingElement( prefline, b1, BrandWidth, GetBit(prefline, b1 )); if (b2 < a1) { // // Pass mode // //OutputBits( TiffInstance, PASSCODE_LENGTH, PASSCODE ); (*lpdwOut) += ( ((DWORD) (PASSCODE_REVERSED)) << BitOut); if ( (BitOut = BitOut + PASSCODE_LENGTH ) > 31 ) { BitOut -= 32; *(++lpdwOut) = ( (DWORD) (PASSCODE_REVERSED) ) >> (PASSCODE_LENGTH - BitOut); } #if TIFFDBG PrintRunInfo( 1, 0, PASSCODE_LENGTH, PASSCODE ); _tprintf( TEXT("\t\ta0=%d, a1=%d, a2=%d, b1=%d, b2=%d\n"), a0, a1, a2, b1, b2 ); #endif a0 = b2; } else if ((distance = a1 - b1) <= 3 && distance >= -3) { // // Vertical mode // // OutputBits( TiffInstance, VertCodes[distance+3].length, VertCodes[distance+3].code ); (*lpdwOut) += ( ( (DWORD) VertCodesReversed[distance+3].code) << BitOut); if ( (BitOut = BitOut + VertCodesReversed[distance+3].length ) > 31 ) { BitOut -= 32; *(++lpdwOut) = ( (DWORD) (VertCodesReversed[distance+3].code) ) >> (VertCodesReversed[distance+3].length - BitOut); } #if TIFFDBG PrintRunInfo( 2, a1-a0, VertCodes[distance+3].length, VertCodes[distance+3].code ); _tprintf( TEXT("\t\ta0=%d, a1=%d, a2=%d, b1=%d, b2=%d\n"), a0, a1, a2, b1, b2 ); #endif a0 = a1; } else { // // Horizontal mode // a2 = (a1 >= BrandWidth) ? BrandWidth : NextChangingElement( pBrandBits, a1, BrandWidth, GetBit( pBrandBits, a1 ) ); // OutputBits( TiffInstance, HORZCODE_LENGTH, HORZCODE ); (*lpdwOut) += ( ((DWORD) (HORZCODE_REVERSED)) << BitOut); if ( (BitOut = BitOut + HORZCODE_LENGTH ) > 31 ) { BitOut -= 32; *(++lpdwOut) = ( (DWORD) (HORZCODE_REVERSED) ) >> (HORZCODE_LENGTH - BitOut); } #if TIFFDBG PrintRunInfo( 3, 0, HORZCODE_LENGTH, HORZCODE ); _tprintf( TEXT("\t\ta0=%d, a1=%d, a2=%d, b1=%d, b2=%d\n"), a0, a1, a2, b1, b2 ); #endif if (a1 != 0 && GetBit( pBrandBits, a0 )) { //OutputRun( TiffInstance, a1-a0, BlackRunCodes ); //OutputRun( TiffInstance, a2-a1, WhiteRunCodes ); OutputRunFastReversed(a1-a0, BLACK, &lpdwOut, &BitOut); OutputRunFastReversed(a2-a1, WHITE, &lpdwOut, &BitOut); } else { //OutputRun( TiffInstance, a1-a0, WhiteRunCodes ); //OutputRun( TiffInstance, a2-a1, BlackRunCodes ); OutputRunFastReversed(a1-a0, WHITE, &lpdwOut, &BitOut); OutputRunFastReversed(a2-a1, BLACK, &lpdwOut, &BitOut); } a0 = a2; } if (a0 >= BrandWidth) { Lines++; break; } a1 = NextChangingElement( pBrandBits, a0, BrandWidth, GetBit( pBrandBits, a0 ) ); b1 = NextChangingElement( prefline, a0, BrandWidth, !GetBit( pBrandBits, a0 ) ); b1 = NextChangingElement( prefline, b1, BrandWidth, GetBit( pBrandBits, a0 ) ); } prefline = pBrandBits; pBrandBits += (BrandWidth / 8); } while (Lines < BrandHeight); *DwordsOut = (DWORD)(lpdwOut - pMmrBrandBits); *BitsOut = BitOut; return TRUE; } // ConvertWidth // // Changes the width of a bitmap. If the desired width is smaller than the current // width, this is accomplished by truncating lines. If the desired width is greater // than the current width, data will be copied up from the next line. // // Parameters: // lpSrc Bitmap source. // dwSrcWidth Its width. // lpDest Pointer to destination. // dwDestWidth Desired width of destination // dwHeight Height of image (won't change). // // Returns: // nothing. // // Author: // Brian Dewey (t-briand) 1997-7-10 void ConvertWidth(const LPBYTE lpSrc, DWORD dwSrcWidth, LPBYTE lpDest, DWORD dwDestWidth, DWORD dwHeight) { LPBYTE lpSrcCur, lpDestCur; DWORD dwCurLine; for(lpSrcCur = lpSrc, lpDestCur = lpDest, dwCurLine = 0; dwCurLine < dwHeight; lpSrcCur += dwSrcWidth, lpDestCur += dwDestWidth, dwCurLine++) { memcpy(lpDestCur, lpSrcCur, dwDestWidth); } } // OutputPage // // This is the core of the converter; it takes a single AWD page and writes it // to the TIFF file. // // Parameters: // psStorages Pointer to the AWD file from which we read. // pwcsDocName Name of the page. // // Returns: // TRUE on success, FALSE on failure. // // Author: // Brian Dewey (t-briand) 1997-7-2 BOOL OutputPage(AWD_FILE *psStorages, const WCHAR *pwcsDocName) { BITMAP bmBand; // A band of image data. LPBYTE lpOutBuf; // Output bitmap (resized). LPBYTE lpOutCur; // Used to write one line at a time. LPDWORD lpdwOutCompressed; // Compressed output. DWORD dwDwordsOut, // Number of DWORDS in compressed output... dwBitsOut = 0; // Number of bits in compressed output. DWORD dwBitsOutOld = 0; // BitsOut from the *previous* band compression. LPVOID lpViewerContext; // The viewer context; used by viewrend library. VIEWINFO sViewInfo; // Information about the image. WORD awResolution[2], // Holds X & Y resolutions wBandSize = 256; // Desired band size; will be reset by ViewerOpen. IStream *psDocument; // Our document stream. BOOL bRet = FALSE; // Return value; FALSE by default. UINT iCurPage; // Current page. const DWORD dwMagicHeight = 3000; // FIXBKD if((psDocument = OpenAWDStream(psStorages->psDocuments, pwcsDocName)) == NULL) { fwprintf(stderr, L"OutputPage:Unable to open stream '%s'.\n", pwcsDocName); return FALSE; // We failed. } // Now, open a viewer context and start reading bands of the image. if((lpViewerContext = ViewerOpen(psDocument, HRAW_DATA, awResolution, &wBandSize, &sViewInfo)) == NULL) { fprintf(stderr, "OutputPage:Unable to open viewer context.\n"); return FALSE; } iCurPage = 0; // Initialize our counter. bmBand.bmBits = malloc(wBandSize); // Allocate memory to hold the band. if(!ViewerGetBand(lpViewerContext, &bmBand)) { fprintf(stderr, "OutputPage:Unable to obtain image band.\n"); return FALSE; } // lpOutBuf = malloc(bmBand.bmHeight * (FAX_IMAGE_WIDTH / 8)); lpOutBuf = malloc(dwMagicHeight * (FAX_IMAGE_WIDTH / 8)); // Provided compression actually *compresses*, we should have more than // enough memory allocated. lpdwOutCompressed = malloc(dwMagicHeight * (FAX_IMAGE_WIDTH / 8)); if(!lpOutBuf || !lpdwOutCompressed) { // check whether we are short in memory TiffEndPage(hTiffDest); if(lpOutBuf) free(lpOutBuf); if(lpdwOutCompressed) free(lpdwOutCompressed); return FALSE; // This will stop the conversion process. } memset(lpOutBuf, '\0', dwMagicHeight * (FAX_IMAGE_WIDTH / 8)); memset(lpdwOutCompressed, '\0', dwMagicHeight * (FAX_IMAGE_WIDTH / 8)); // Main loop while(iCurPage < sViewInfo.cPage) { lpOutCur = lpOutBuf; while(bmBand.bmHeight) { // Make sure our bitmap has FAX_IMAGE_WIDTH as its width. ConvertWidth(bmBand.bmBits, bmBand.bmWidth / 8, lpOutCur, FAX_IMAGE_WIDTH / 8, bmBand.bmHeight); lpOutCur += (bmBand.bmHeight * (FAX_IMAGE_WIDTH / 8)); if(!ViewerGetBand(lpViewerContext, &bmBand)) { fprintf(stderr, "OutputPage:Unable to obtain image band.\n"); goto output_exit; // Will return FALSE by default. } } // while (wasn't that easy?) memset(lpdwOutCompressed, '\0', dwMagicHeight * (FAX_IMAGE_WIDTH / 8)); CompressBitmapStrip(lpOutBuf, lpdwOutCompressed, (ULONG)((lpOutCur - lpOutBuf) / (FAX_IMAGE_WIDTH / 8)), FAX_IMAGE_WIDTH, &dwDwordsOut, &dwBitsOut); memset(lpOutBuf, '\0', dwMagicHeight * (FAX_IMAGE_WIDTH / 8)); fprintf(stderr, "OutputPage:Compressed image to %d dwords, %d bits.\n", dwDwordsOut, dwBitsOut); if(!TiffStartPage(hTiffDest)) { fprintf(stderr, "OutputPage:Unable to open output page.\n"); return FALSE; // We can't begin a page for some reason. if(lpOutBuf) free(lpOutBuf); if(lpdwOutCompressed) free(lpdwOutCompressed); } TiffWriteRaw(hTiffDest, (LPBYTE)lpdwOutCompressed, (dwDwordsOut + 1) * sizeof(DWORD)); ((PTIFF_INSTANCE_DATA)hTiffDest)->Lines = (ULONG)((lpOutCur - lpOutBuf) / (FAX_IMAGE_WIDTH / 8)); if(sViewInfo.yRes <= 100) ((PTIFF_INSTANCE_DATA)hTiffDest)->YResolution = 98; else ((PTIFF_INSTANCE_DATA)hTiffDest)->YResolution = 196; TiffEndPage(hTiffDest); // Now, move to a new page of the data. iCurPage++; if(iCurPage < sViewInfo.cPage) { ViewerSetPage(lpViewerContext, iCurPage); if(!ViewerGetBand(lpViewerContext, &bmBand)) { fprintf(stderr, "OutputPage:Unable to obtain image band.\n"); goto output_exit; // Will return FALSE by default. } } } // Free memory. bRet = TRUE; output_exit: free(lpdwOutCompressed); free(lpOutBuf); free(bmBand.bmBits); return bRet; }