//--------------------------------------------------------------------------// //--------------------------------------------------------------------------// void CAGSymImage::LoadDIB(const BITMAPINFOHEADER* pHdr, const BYTE* pBits) { Free(); if (pHdr->biCompression == BI_RGB && (pHdr->biBitCount == 1 || pHdr->biBitCount == 4 || pHdr->biBitCount == 8 || pHdr->biBitCount == 24)) { BITMAPINFOHEADER bi; bi = *pHdr; bi.biCompression = BI_RGB; if (!bi.biSizeImage) bi.biSizeImage = DibSizeImage(&bi); if (!bi.biClrUsed) bi.biClrUsed = DibNumColors(&bi); if (m_pDIB = (BITMAPINFOHEADER*)malloc(DibSize(&bi))) { *m_pDIB = bi; if (bi.biClrUsed) memcpy((void*)DibColors(m_pDIB), (void*)DibColors(pHdr), DibPaletteSize(pHdr)); BYTE* pNewBits = (BYTE*)DibPtr(m_pDIB); const BYTE* pSrcBits; if (pBits) pSrcBits = pBits; else pSrcBits = (BYTE*)(DibColors(pHdr) + bi.biClrUsed); memcpy(pNewBits, pSrcBits, bi.biSizeImage); } } }
BOOL W32CheckDibColorIndices(LPBITMAPINFOHEADER lpbmi) { WORD i, nColors; LPWORD lpw = (LPWORD)DibColors(lpbmi); nColors = DibNumColors(lpbmi); if (lpbmi->biClrImportant) { nColors = min(nColors, (WORD)lpbmi->biClrImportant); } for (i = 0; i < nColors; ++i) { if (*lpw++ != i) { return FALSE; } } LOGDEBUG(LOG_ALWAYS, ("\nUndocumented Dib.Drv behaviour used\n")); return TRUE; }
HGLOBAL CPng::PNGToDIB(png_structp png_ptr, png_infop info_ptr) { //Read the image png_read_info(png_ptr, info_ptr); int nBitDepth = 0; int nColorType = 0; png_uint_32 width = 0; png_uint_32 height = 0; png_get_IHDR(png_ptr, info_ptr, &width, &height, &nBitDepth, &nColorType, NULL, NULL, NULL); IMAGE img; img.width = (LONG)width; img.height = (LONG)height; //Determine the type of format if (nColorType==PNG_COLOR_TYPE_RGB || nColorType==PNG_COLOR_TYPE_RGB_ALPHA) { img.pixdepth = 24; // nBitDepth 8, 16 img.palnum = 0; } else { switch(nBitDepth) // bit depths 1, 2, 4, 8, 16 { case 2: img.pixdepth = 4; break; case 16: img.pixdepth = 8; break; default: img.pixdepth = nBitDepth; } img.palnum = 1 << img.pixdepth; } //Allocate the image struct that will be used to transport file info if (!AllocImageStruct(&img)) { longjmp(png_ptr->jmpbuf, 1); } //Not sure if we can take advantage of this info in a BMP, thus remove it. if (nColorType & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png_ptr); //Set user transform function to deal with a Bitdepth of 2 if (nBitDepth == 2) { png_set_user_transform_info(png_ptr, NULL, 4, 1); png_set_read_user_transform_fn(png_ptr, ConvertTo4BitsPerPix); } //Tell libpng to strip 16 bit/color files down to 8 bits/color if (nBitDepth == 16) png_set_strip_16(png_ptr); if (nColorType==PNG_COLOR_TYPE_RGB || nColorType==PNG_COLOR_TYPE_RGB_ALPHA) { png_set_bgr(png_ptr); } png_read_update_info(png_ptr, info_ptr); //If palette, get it and fill our img struct if (img.palnum > 0) { if (nColorType == PNG_COLOR_TYPE_PALETTE) { png_colorp palette; int num_palette; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); if (num_palette > (int)img.palnum) num_palette = img.palnum; memset(img.palette, 0, img.palnum * sizeof(png_color)); memcpy(img.palette, palette, num_palette * sizeof(png_color)); } else { int depth = (nBitDepth == 16)? 8 : nBitDepth ; png_build_grayscale_palette(depth, img.palette); } } png_read_image(png_ptr, img.rowptr); png_infop end_info = NULL; png_read_end(png_ptr, end_info); // Alloc the buffer to be big enough to hold all the bits DWORD dwLen = (DWORD)sizeof(BITMAPINFOHEADER) + (img.palnum * sizeof(RGBQUAD)) + img.imgbytes; // Allocate enough memory to hold the entire DIB HGLOBAL hMemory = ::GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, dwLen); if (!hMemory) return NULL; //Begin filling out DIB info BITMAPINFOHEADER* pDib = (BITMAPINFOHEADER*)::GlobalLock(hMemory); if (!pDib) { ::GlobalFree(hMemory); return NULL; } ::ZeroMemory(pDib, dwLen); pDib->biSize = sizeof(BITMAPINFOHEADER); pDib->biWidth = (DWORD)img.width; pDib->biHeight = (DWORD)img.height; pDib->biPlanes = 1; pDib->biCompression = BI_RGB; pDib->biXPelsPerMeter = 3937; // 100 pixels/inch pDib->biYPelsPerMeter = 3937; pDib->biSizeImage = img.imgbytes; pDib->biBitCount = img.pixdepth; pDib->biClrUsed = img.palnum; if (pDib->biBitCount >= 16) pDib->biBitCount = 24; if (pDib->biClrUsed) { RGBQUAD* pRgb = DibColors(pDib); BYTE rgbq[RGBQUAD_SIZE]; PALETTE* pal; UINT nIndex; memset(rgbq, 0, sizeof(rgbq)); for (pal = img.palette, nIndex = img.palnum ; nIndex > 0 ; nIndex--, pal++) { rgbq[RGBQ_RED] = pal->red; rgbq[RGBQ_GREEN] = pal->green; rgbq[RGBQ_BLUE] = pal->blue; rgbq[RGBQ_RESERVED] = 0; memcpy((LPVOID)pRgb, rgbq, sizeof(RGBQUAD)); pRgb++; } } memcpy(DibPtr(pDib), img.bmpbits, DibSizeImage(pDib)); FreeImageStruct(&img); ::GlobalUnlock(hMemory); return hMemory; }
PDIB DibReadBitmapInfo(int fh) { DWORD off; HANDLE hbi = NULL; int size; int i; int nNumColors; RGBQUAD FAR *pRgb; BITMAPINFOHEADER bi; BITMAPCOREHEADER bc; BITMAPFILEHEADER bf; PDIB pdib; if (fh == -1) return NULL; off = lseek(fh,0L,SEEK_CUR); if (sizeof(bf) != read(fh,(LPSTR)&bf,sizeof(bf))) return FALSE; /* * do we have a RC HEADER? */ if (bf.bfType != BFT_BITMAP) { bf.bfOffBits = 0L; lseek(fh,off,SEEK_SET); } if (sizeof(bi) != read(fh,(LPSTR)&bi,sizeof(bi))) return FALSE; /* * what type of bitmap info is this? */ switch (size = (int)bi.biSize) { default: case sizeof(BITMAPINFOHEADER): break; case sizeof(BITMAPCOREHEADER): bc = *(BITMAPCOREHEADER*)&bi; bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = (DWORD)bc.bcWidth; bi.biHeight = (DWORD)bc.bcHeight; bi.biPlanes = (UINT)bc.bcPlanes; bi.biBitCount = (UINT)bc.bcBitCount; bi.biCompression = BI_RGB; bi.biSizeImage = 0; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrUsed = 0; bi.biClrImportant = 0; lseek(fh,(LONG)sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER),SEEK_CUR); break; } nNumColors = DibNumColors(&bi); if (bi.biSizeImage == 0) bi.biSizeImage = DibSizeImage(&bi); if (bi.biClrUsed == 0) bi.biClrUsed = DibNumColors(&bi); pdib = (PDIB) malloc((LONG)bi.biSize + nNumColors * sizeof(RGBQUAD)); if (!pdib) return NULL; *pdib = bi; pRgb = DibColors(pdib); if (nNumColors == 0) { printf("Bitmap has no palette (24 bit)\n", NUM_COLORS, nNumColors); return NULL; } if (nNumColors != NUM_COLORS) { printf("Expecting %d color bitmap; found %d colors\n", NUM_COLORS, nNumColors); return NULL; } if (size == sizeof(BITMAPCOREHEADER)) { /* * convert a old color table (3 byte entries) to a new * color table (4 byte entries) */ read(fh,(LPVOID)pRgb,nNumColors * sizeof(RGBTRIPLE)); for (i=nNumColors-1; i>=0; i--) { RGBQUAD rgb; rgb.rgbRed = ((RGBTRIPLE FAR *)pRgb)[i].rgbtRed; rgb.rgbBlue = ((RGBTRIPLE FAR *)pRgb)[i].rgbtBlue; rgb.rgbGreen = ((RGBTRIPLE FAR *)pRgb)[i].rgbtGreen; rgb.rgbReserved = (BYTE)0; pRgb[i] = rgb; } } else { read(fh,(LPVOID)pRgb,nNumColors * sizeof(RGBQUAD)); } if (bf.bfOffBits != 0L) lseek(fh,off + bf.bfOffBits,SEEK_SET); return pdib; }
HDC W32HandleDibDrv (PVPVOID vpbmi16) { HDC hdcMem = NULL; HBITMAP hbm = NULL; PVOID pvBits, pvIntelBits; STACKBMI32 bmi32; LPBITMAPINFO lpbmi32; DWORD dwClrUsed,nSize,nAlignmentSpace; PBITMAPINFOHEADER16 pbmi16; INT nbmiSize,nBytesWritten; HANDLE hfile=NULL,hsec=NULL; ULONG RetVal,OriginalSelLimit,SelectorLimit,OriginalFlags; PARM16 Parm16; CHAR pchTempFile[MAX_PATH]; BOOL bRet = FALSE; PVPVOID vpBase16 = (PVPVOID) ((ULONG) vpbmi16 & 0xffff0000); if ((hdcMem = W32FindAndLockDibInfo((USHORT)HIWORD(vpbmi16))) != (HDC)NULL) { return hdcMem; } // First create a memory device context compatible to // the app's current screen if ((hdcMem = CreateCompatibleDC (NULL)) == NULL) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateCompatibleDC failed\n")); return NULL; } // Copy bmi16 to bmi32. DIB.DRV only supports DIB_RGB_COLORS lpbmi32 = CopyBMI16ToBMI32( vpbmi16, (LPBITMAPINFO)&bmi32, (WORD) DIB_RGB_COLORS); // this hack for Director 4.0 does essentially what WFW does // if this bitmap is 0 sized, just return an hDC for something simple if(bmi32.bmiHeader.biSizeImage == 0 && (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_DIBDRVIMAGESIZEZERO)) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv:Zero biSizeImage, returning memory DC!\n")); return hdcMem; } try { // Copy the wholething into a temp file. First get a temp file name if ((nSize = GetTempPath (MAX_PATH, pchTempFile)) == 0 || nSize >= MAX_PATH) goto hdd_err; if (GetTempFileName (pchTempFile, "DIB", 0, pchTempFile) == 0) goto hdd_err; if ((hfile = CreateFile (pchTempFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, (FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE), NULL)) == INVALID_HANDLE_VALUE) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateFile failed\n")); goto hdd_err; } // call back to get the size of the global object // associated with vpbmi16 Parm16.WndProc.wParam = HIWORD(vpbmi16); CallBack16(RET_GETDIBSIZE, &Parm16, 0, (PVPVOID)&SelectorLimit); Parm16.WndProc.wParam = HIWORD(vpbmi16); if (SelectorLimit == 0xffffffff || SelectorLimit == 0) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv Invalid Selector %x\n",HIWORD(vpbmi16))); goto hdd_err; } SelectorLimit++; OriginalSelLimit = SelectorLimit; CallBack16(RET_GETDIBFLAGS, &Parm16, 0, (PVPVOID)&OriginalFlags); if (OriginalFlags == 0x4) { //GA_DGROUP LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv GA_DGROUP Not Handled\n")); goto hdd_err; } GETVDMPTR(vpBase16, SelectorLimit, pbmi16); nbmiSize = GetBMI16Size(vpbmi16, (WORD) DIB_RGB_COLORS, &dwClrUsed); // Under NT CreateDIBSection will fail if the offset to the bits // is not dword aligned. So we may have to add some space at the top // of the section to get the offset correctly aligned. nAlignmentSpace = (nbmiSize+LOWORD(vpbmi16)) % 4; if (nAlignmentSpace) { if (WriteFile (hfile, pbmi16, nAlignmentSpace, &nBytesWritten, NULL) == FALSE || nBytesWritten != (INT) nAlignmentSpace) goto hdd_err; } // // detect a clinical case of bitedit screwing around dib.drv // // code below is using dib macros declared in wdib.h // namely: // DibNumColors - yields max number of colors in dib // DibColors - yields pointer to a dib color table // // Function W32CheckDibColorIndices checks to see if DIB color // table looks like a number (defined usually by biClrImportant) // of WORD indices in a sequential order (0, 1, 2, ...) // if this is the case, app is trying to use undocumented feature // of DIB.DRV that turns color matching off in this case. // Since we cannot enforce that rule, we approximate it by filling // color table by a number of known (and always same) entries // When blitting occurs, no color matching will be performed (when // both target and destination are of this very nature). // For no reason at all we fill color table with vga colors. // Sequential indices could have worked just as well. // // Modifications are made to memory pointed to by lpbmi32 if (W32CheckDibColorIndices((LPBITMAPINFOHEADER)lpbmi32)) { INT i, nColors; LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER)lpbmi32; LPRGBQUAD lprgbq = (LPRGBQUAD)DibColors(lpbmi); nColors = DibNumColors(lpbmi); lpbmi->biClrImportant = nColors; switch (lpbmi->biBitCount) { case 1: lprgbq[0] = rgbVGA[0]; lprgbq[1] = rgbVGA[0x0f]; break; case 4: RtlCopyMemory(lprgbq, rgbVGA, sizeof(rgbVGA)); break; case 8: RtlCopyMemory(lprgbq, rgbVGA, 8*sizeof(RGBQUAD)); RtlCopyMemory(lprgbq+248, rgbVGA+8, 8*sizeof(RGBQUAD)); RtlCopyMemory(lprgbq+8, rgb4, 2*sizeof(RGBQUAD)); RtlCopyMemory(lprgbq+246, rgb4+2, 2*sizeof(RGBQUAD)); for (i = 10; i < 246; ++i) { lprgbq[i].rgbBlue = i; lprgbq[i].rgbGreen= 0; lprgbq[i].rgbRed = 0; lprgbq[i].rgbReserved = 0; } break; default: // this should never happen break; } } if (WriteFile (hfile, pbmi16, SelectorLimit, &nBytesWritten, NULL) == FALSE || nBytesWritten != (INT) SelectorLimit) goto hdd_err; if (SelectorLimit < 64*1024) { if (SetFilePointer (hfile, 64*1024+nAlignmentSpace, NULL, FILE_BEGIN) == -1) goto hdd_err; if (SetEndOfFile (hfile) == FALSE) goto hdd_err; SelectorLimit = 64*1024; } if ((hsec = CreateFileMapping (hfile, NULL, PAGE_READWRITE | SEC_COMMIT, 0, SelectorLimit+nAlignmentSpace, NULL)) == NULL) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateFileMapping Failed\n")); goto hdd_err; } // Now create the DIB section if ((hbm = CreateDIBSection (hdcMem, lpbmi32, DIB_RGB_COLORS, &pvBits, hsec, nAlignmentSpace + LOWORD(vpbmi16) + nbmiSize )) == NULL) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateDibSection Failed\n")); goto hdd_err; } FREEVDMPTR(pbmi16); if((pvBits = MapViewOfFile(hsec, FILE_MAP_WRITE, 0, 0, SelectorLimit+nAlignmentSpace)) == NULL) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv MapViewOfFile Failed\n")); goto hdd_err; } pvBits = (PVOID) ((ULONG)pvBits + nAlignmentSpace); SelectObject (hdcMem, hbm); GdiSetBatchLimit(1); #ifndef i386 if (!NT_SUCCESS(VdmAddVirtualMemory((ULONG)pvBits, (ULONG)SelectorLimit, (PULONG)&pvIntelBits))) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv VdmAddVirtualMemory failed\n")); goto hdd_err; } // On risc platforms, the intel base + the intel linear address // of the DIB section is not equal to the DIB section's process // address. This is because of the VdmAddVirtualMemory call // above. So here we zap the correct address into the flataddress // array. if (!VdmAddDescriptorMapping(HIWORD(vpbmi16), (USHORT) ((SelectorLimit+65535)/65536), (ULONG) pvIntelBits, (ULONG) pvBits)) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv VdmAddDescriptorMapping failed\n")); goto hdd_err; } #else pvIntelBits = pvBits; #endif // Finally set the selectors to the new DIB Parm16.WndProc.wParam = HIWORD(vpbmi16); Parm16.WndProc.lParam = (LONG)pvIntelBits; Parm16.WndProc.wMsg = 0x10; // GA_NOCOMPACT Parm16.WndProc.hwnd = 1; // set so it's not randomly 0 CallBack16(RET_SETDIBSEL, &Parm16, 0, (PVPVOID)&RetVal); if (!RetVal) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv Callback set_sel_for_dib failed\n")); goto hdd_err; } // Store all the relevant information so that DeleteDC could // free all the resources later. if (W32AddDibInfo(hdcMem, hfile, hsec, nAlignmentSpace, pvBits, pvIntelBits, hbm, OriginalSelLimit, (USHORT)OriginalFlags, (USHORT)((HIWORD(vpbmi16)))) == FALSE) goto hdd_err; // Finally spit out the dump for debugging LOGDEBUG(6,("\t\tWOW::W32HandleDibDrv hdc=%04x nAlignment=%04x\n\t\tNewDib=%x OldDib=%04x:%04x DibSize=%x DibFlags=%x\n",hdcMem,nAlignmentSpace,pvBits,HIWORD(vpbmi16),LOWORD(vpbmi16),OriginalSelLimit,(USHORT)OriginalFlags)); bRet = TRUE; hdd_err:; } finally { if (!bRet) { if (hdcMem) { DeleteDC (hdcMem); hdcMem = NULL; } if (hfile) CloseHandle (hfile); if (hsec) CloseHandle (hsec); if (hbm) CloseHandle (hbm); } } return hdcMem; }