/****************************************************************************** * CreateBitmap [GDI32.@] * * Creates a bitmap with the specified info. * * PARAMS * width [I] bitmap width * height [I] bitmap height * planes [I] Number of color planes * bpp [I] Number of bits to identify a color * bits [I] Pointer to array containing color data * * RETURNS * Success: Handle to bitmap * Failure: 0 */ HBITMAP WINAPI CreateBitmap( INT width, INT height, UINT planes, UINT bpp, LPCVOID bits ) { BITMAP bm; bm.bmType = 0; bm.bmWidth = width; bm.bmHeight = height; bm.bmWidthBytes = BITMAP_GetWidthBytes( width, bpp ); bm.bmPlanes = planes; bm.bmBitsPixel = bpp; bm.bmBits = (LPVOID)bits; return CreateBitmapIndirect( &bm ); }
/*********************************************************************** * GetBitmapBits [GDI32.@] * * Copies bitmap bits of bitmap to buffer. * * RETURNS * Success: Number of bytes copied * Failure: 0 */ LONG WINAPI GetBitmapBits( HBITMAP hbitmap, /* [in] Handle to bitmap */ LONG count, /* [in] Number of bytes to copy */ LPVOID bits) /* [out] Pointer to buffer to receive bits */ { BITMAPOBJ *bmp = GDI_GetObjPtr( hbitmap, BITMAP_MAGIC ); LONG height, ret; if (!bmp) return 0; if (bmp->dib) /* simply copy the bits from the DIB */ { DIBSECTION *dib = bmp->dib; const char *src = dib->dsBm.bmBits; INT width_bytes = BITMAP_GetWidthBytes(dib->dsBm.bmWidth, dib->dsBm.bmBitsPixel); LONG max = width_bytes * bmp->bitmap.bmHeight; if (!bits) { ret = max; goto done; } if (count > max) count = max; ret = count; /* GetBitmapBits returns not 32-bit aligned data */ if (bmp->dib->dsBmih.biHeight >= 0) /* not top-down, need to flip contents vertically */ { src += dib->dsBm.bmWidthBytes * dib->dsBm.bmHeight; while (count > 0) { src -= dib->dsBm.bmWidthBytes; memcpy( bits, src, min( count, width_bytes ) ); bits = (char *)bits + width_bytes; count -= width_bytes; } } else { while (count > 0) { memcpy( bits, src, min( count, width_bytes ) ); src += dib->dsBm.bmWidthBytes; bits = (char *)bits + width_bytes; count -= width_bytes; } } goto done; } /* If the bits vector is null, the function should return the read size */ if(bits == NULL) { ret = bmp->bitmap.bmWidthBytes * bmp->bitmap.bmHeight; goto done; } if (count < 0) { WARN("(%d): Negative number of bytes passed???\n", count ); count = -count; } /* Only get entire lines */ height = count / bmp->bitmap.bmWidthBytes; if (height > bmp->bitmap.bmHeight) height = bmp->bitmap.bmHeight; count = height * bmp->bitmap.bmWidthBytes; if (count == 0) { WARN("Less than one entire line requested\n"); ret = 0; goto done; } TRACE("(%p, %d, %p) %dx%d %d colors fetched height: %d\n", hbitmap, count, bits, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight, 1 << bmp->bitmap.bmBitsPixel, height ); if(bmp->funcs && bmp->funcs->pGetBitmapBits) { TRACE("Calling device specific BitmapBits\n"); ret = bmp->funcs->pGetBitmapBits(hbitmap, bits, count); } else { if(!bmp->bitmap.bmBits) { TRACE("Bitmap is empty\n"); memset(bits, 0, count); ret = count; } else { memcpy(bits, bmp->bitmap.bmBits, count); ret = count; } } done: GDI_ReleaseObj( hbitmap ); return ret; }
/*********************************************************************** * EMFDRV_CreateBrushIndirect */ DWORD EMFDRV_CreateBrushIndirect( PHYSDEV dev, HBRUSH hBrush ) { DWORD index = 0; LOGBRUSH logbrush; if (!GetObjectA( hBrush, sizeof(logbrush), &logbrush )) return 0; switch (logbrush.lbStyle) { case BS_SOLID: case BS_HATCHED: case BS_NULL: { EMRCREATEBRUSHINDIRECT emr; emr.emr.iType = EMR_CREATEBRUSHINDIRECT; emr.emr.nSize = sizeof(emr); emr.ihBrush = index = EMFDRV_AddHandle( dev, hBrush ); emr.lb.lbStyle = logbrush.lbStyle; emr.lb.lbColor = logbrush.lbColor; emr.lb.lbHatch = logbrush.lbHatch; if(!EMFDRV_WriteRecord( dev, &emr.emr )) index = 0; } break; case BS_DIBPATTERN: { EMRCREATEDIBPATTERNBRUSHPT *emr; DWORD bmSize, biSize, size; BITMAPINFO *info = GlobalLock( (HGLOBAL)logbrush.lbHatch ); if (info->bmiHeader.biCompression) bmSize = info->bmiHeader.biSizeImage; else bmSize = DIB_GetDIBImageBytes(info->bmiHeader.biWidth, info->bmiHeader.biHeight, info->bmiHeader.biBitCount); biSize = bitmap_info_size(info, LOWORD(logbrush.lbColor)); size = sizeof(EMRCREATEDIBPATTERNBRUSHPT) + biSize + bmSize; emr = HeapAlloc( GetProcessHeap(), 0, size ); if(!emr) break; emr->emr.iType = EMR_CREATEDIBPATTERNBRUSHPT; emr->emr.nSize = size; emr->ihBrush = index = EMFDRV_AddHandle( dev, hBrush ); emr->iUsage = LOWORD(logbrush.lbColor); emr->offBmi = sizeof(EMRCREATEDIBPATTERNBRUSHPT); emr->cbBmi = biSize; emr->offBits = sizeof(EMRCREATEDIBPATTERNBRUSHPT) + biSize; emr->cbBits = bmSize; memcpy((char *)emr + sizeof(EMRCREATEDIBPATTERNBRUSHPT), info, biSize + bmSize ); if(!EMFDRV_WriteRecord( dev, &emr->emr )) index = 0; HeapFree( GetProcessHeap(), 0, emr ); GlobalUnlock( (HGLOBAL)logbrush.lbHatch ); } break; case BS_PATTERN: { EMRCREATEDIBPATTERNBRUSHPT *emr; BITMAPINFOHEADER *info; BITMAP bm; DWORD bmSize, biSize, size; GetObjectA((HANDLE)logbrush.lbHatch, sizeof(bm), &bm); if (bm.bmBitsPixel != 1 || bm.bmPlanes != 1) { FIXME("Trying to create a color pattern brush\n"); break; } /* BMP will be aligned to 32 bits, not 16 */ bmSize = DIB_GetDIBImageBytes(bm.bmWidth, bm.bmHeight, bm.bmBitsPixel); biSize = sizeof(BITMAPINFOHEADER); /* FIXME: There is an extra DWORD written by native before the BMI. * Not sure what its meant to contain. */ size = sizeof(EMRCREATEDIBPATTERNBRUSHPT) + biSize + bmSize + sizeof(DWORD); emr = HeapAlloc( GetProcessHeap(), 0, size ); if(!emr) break; info = (BITMAPINFOHEADER *)((LPBYTE)emr + sizeof(EMRCREATEDIBPATTERNBRUSHPT) + sizeof(DWORD)); info->biSize = sizeof(BITMAPINFOHEADER); info->biWidth = bm.bmWidth; info->biHeight = bm.bmHeight; info->biPlanes = bm.bmPlanes; info->biBitCount = bm.bmBitsPixel; info->biSizeImage = bmSize; GetBitmapBits((HANDLE)logbrush.lbHatch, bm.bmHeight * BITMAP_GetWidthBytes(bm.bmWidth, bm.bmBitsPixel), (LPBYTE)info + sizeof(BITMAPINFOHEADER)); /* Change the padding to be DIB compatible if needed */ if (bm.bmWidth & 31) EMFDRV_PadTo32((LPBYTE)info + sizeof(BITMAPINFOHEADER), bm.bmWidth, bm.bmHeight); emr->emr.iType = EMR_CREATEMONOBRUSH; emr->emr.nSize = size; emr->ihBrush = index = EMFDRV_AddHandle( dev, hBrush ); /* Presumably to reduce the size of the written EMF, MS supports an * undocumented iUsage value of 2, indicating a mono bitmap without the * 8 byte 2 entry black/white palette. Stupidly, they could have saved * over 20 bytes more by also ignoring the BITMAPINFO fields that are * irrelevant/constant for monochrome bitmaps. * FIXME: It may be that the DIB functions themselves accept this value. */ emr->iUsage = DIB_PAL_MONO; emr->offBmi = (LPBYTE)info - (LPBYTE)emr; emr->cbBmi = biSize; emr->offBits = emr->offBmi + biSize; emr->cbBits = bmSize; if(!EMFDRV_WriteRecord( dev, &emr->emr )) index = 0; HeapFree( GetProcessHeap(), 0, emr ); } break; default: FIXME("Unknown style %x\n", logbrush.lbStyle); break; } return index; }
/****************************************************************************** * CreateBitmapIndirect [GDI32.@] * * Creates a bitmap with the specified info. * * PARAMS * bmp [I] Pointer to the bitmap info describing the bitmap * * RETURNS * Success: Handle to bitmap * Failure: NULL. Use GetLastError() to determine the cause. * * NOTES * If a width or height of 0 are given, a 1x1 monochrome bitmap is returned. */ HBITMAP WINAPI CreateBitmapIndirect( const BITMAP *bmp ) { BITMAP bm; BITMAPOBJ *bmpobj; HBITMAP hbitmap; if (!bmp || bmp->bmType) { SetLastError( ERROR_INVALID_PARAMETER ); return NULL; } if (bmp->bmWidth > 0x7ffffff || bmp->bmHeight > 0x7ffffff) { SetLastError( ERROR_INVALID_PARAMETER ); return 0; } bm = *bmp; if (!bm.bmWidth || !bm.bmHeight) { return GetStockObject( DEFAULT_BITMAP ); } else { if (bm.bmHeight < 0) bm.bmHeight = -bm.bmHeight; if (bm.bmWidth < 0) bm.bmWidth = -bm.bmWidth; } if (bm.bmPlanes != 1) { FIXME("planes = %d\n", bm.bmPlanes); SetLastError( ERROR_INVALID_PARAMETER ); return NULL; } /* Windows only uses 1, 4, 8, 16, 24 and 32 bpp */ if(bm.bmBitsPixel == 1) bm.bmBitsPixel = 1; else if(bm.bmBitsPixel <= 4) bm.bmBitsPixel = 4; else if(bm.bmBitsPixel <= 8) bm.bmBitsPixel = 8; else if(bm.bmBitsPixel <= 16) bm.bmBitsPixel = 16; else if(bm.bmBitsPixel <= 24) bm.bmBitsPixel = 24; else if(bm.bmBitsPixel <= 32) bm.bmBitsPixel = 32; else { WARN("Invalid bmBitsPixel %d, returning ERROR_INVALID_PARAMETER\n", bm.bmBitsPixel); SetLastError(ERROR_INVALID_PARAMETER); return NULL; } /* Windows ignores the provided bm.bmWidthBytes */ bm.bmWidthBytes = BITMAP_GetWidthBytes( bm.bmWidth, bm.bmBitsPixel ); /* XP doesn't allow to create bitmaps larger than 128 Mb */ if (bm.bmHeight > 128 * 1024 * 1024 / bm.bmWidthBytes) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return 0; } /* Create the BITMAPOBJ */ bmpobj = GDI_AllocObject( sizeof(BITMAPOBJ), BITMAP_MAGIC, (HGDIOBJ *)&hbitmap, &bitmap_funcs ); if (!bmpobj) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return NULL; } TRACE("%dx%d, %d colors returning %p\n", bm.bmWidth, bm.bmHeight, 1 << (bm.bmPlanes * bm.bmBitsPixel), hbitmap); bmpobj->size.cx = 0; bmpobj->size.cy = 0; bmpobj->bitmap = bm; bmpobj->bitmap.bmBits = NULL; bmpobj->funcs = NULL; bmpobj->dib = NULL; bmpobj->segptr_bits = 0; bmpobj->color_table = NULL; bmpobj->nb_colors = 0; if (bm.bmBits) SetBitmapBits( hbitmap, bm.bmHeight * bm.bmWidthBytes, bm.bmBits ); GDI_ReleaseObj( hbitmap ); return hbitmap; }
INT16 MFDRV_CreateBrushIndirect(PHYSDEV dev, HBRUSH hBrush ) { DWORD size; METARECORD *mr; LOGBRUSH logbrush; METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev; BOOL r; if (!GetObjectA( hBrush, sizeof(logbrush), &logbrush )) return -1; switch(logbrush.lbStyle) { case BS_SOLID: case BS_NULL: case BS_HATCHED: { LOGBRUSH16 lb16; lb16.lbStyle = logbrush.lbStyle; lb16.lbColor = logbrush.lbColor; lb16.lbHatch = logbrush.lbHatch; size = sizeof(METARECORD) + sizeof(LOGBRUSH16) - 2; mr = HeapAlloc( GetProcessHeap(), 0, size ); mr->rdSize = size / 2; mr->rdFunction = META_CREATEBRUSHINDIRECT; memcpy( mr->rdParm, &lb16, sizeof(LOGBRUSH16)); break; } case BS_PATTERN: { BITMAP bm; BITMAPINFO *info; DWORD bmSize; COLORREF cref; GetObjectA((HANDLE)logbrush.lbHatch, sizeof(bm), &bm); if(bm.bmBitsPixel != 1 || bm.bmPlanes != 1) { FIXME("Trying to store a colour pattern brush\n"); goto done; } bmSize = DIB_GetDIBImageBytes(bm.bmWidth, bm.bmHeight, DIB_PAL_COLORS); size = sizeof(METARECORD) + sizeof(WORD) + sizeof(BITMAPINFO) + sizeof(RGBQUAD) + bmSize; mr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); if(!mr) goto done; mr->rdFunction = META_DIBCREATEPATTERNBRUSH; mr->rdSize = size / 2; mr->rdParm[0] = BS_PATTERN; mr->rdParm[1] = DIB_RGB_COLORS; info = (BITMAPINFO *)(mr->rdParm + 2); info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); info->bmiHeader.biWidth = bm.bmWidth; info->bmiHeader.biHeight = bm.bmHeight; info->bmiHeader.biPlanes = 1; info->bmiHeader.biBitCount = 1; info->bmiHeader.biSizeImage = bmSize; GetBitmapBits((HANDLE)logbrush.lbHatch, bm.bmHeight * BITMAP_GetWidthBytes (bm.bmWidth, bm.bmBitsPixel), (LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD)); /* Change the padding to be DIB compatible if needed */ if(bm.bmWidth & 31) MFDRV_PadTo32((LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD), bm.bmWidth, bm.bmHeight); /* BMP and DIB have opposite row order conventions */ MFDRV_Reverse((LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD), bm.bmWidth, bm.bmHeight); cref = GetTextColor(physDev->hdc); info->bmiColors[0].rgbRed = GetRValue(cref); info->bmiColors[0].rgbGreen = GetGValue(cref); info->bmiColors[0].rgbBlue = GetBValue(cref); info->bmiColors[0].rgbReserved = 0; cref = GetBkColor(physDev->hdc); info->bmiColors[1].rgbRed = GetRValue(cref); info->bmiColors[1].rgbGreen = GetGValue(cref); info->bmiColors[1].rgbBlue = GetBValue(cref); info->bmiColors[1].rgbReserved = 0; break; } case BS_DIBPATTERN: { BITMAPINFO *info; DWORD bmSize, biSize; info = GlobalLock16((HGLOBAL16)logbrush.lbHatch); if (info->bmiHeader.biCompression) bmSize = info->bmiHeader.biSizeImage; else bmSize = DIB_GetDIBImageBytes(info->bmiHeader.biWidth, info->bmiHeader.biHeight, info->bmiHeader.biBitCount); biSize = bitmap_info_size(info, LOWORD(logbrush.lbColor)); size = sizeof(METARECORD) + biSize + bmSize + 2; mr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); if(!mr) goto done; mr->rdFunction = META_DIBCREATEPATTERNBRUSH; mr->rdSize = size / 2; *(mr->rdParm) = logbrush.lbStyle; *(mr->rdParm + 1) = LOWORD(logbrush.lbColor); memcpy(mr->rdParm + 2, info, biSize + bmSize); break; } default: FIXME("Unkonwn brush style %x\n", logbrush.lbStyle); return 0; } r = MFDRV_WriteRecord( dev, mr, mr->rdSize * 2); HeapFree(GetProcessHeap(), 0, mr); if( !r ) return -1; done: return MFDRV_AddHandle( dev, hBrush ); }