⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bitmaps.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
字号:
/*
 *  ReactOS W32 Subsystem
 *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/* $Id: bitmaps.c 28341 2007-08-14 23:22:07Z tkreuzer $ */

#include <w32k.h>

#define NDEBUG
#include <debug.h>

#define IN_RECT(r,x,y) \
( \
 (x) >= (r).left && \
 (y) >= (r).top && \
 (x) < (r).right && \
 (y) < (r).bottom \
)

HBITMAP STDCALL
IntGdiCreateBitmap(
    INT  Width,
    INT  Height,
    UINT  Planes,
    UINT  BitsPixel,
    IN OPTIONAL LPBYTE pBits)
{
   PBITMAPOBJ bmp;
   HBITMAP hBitmap;
   SIZEL Size;
   LONG WidthBytes;

   /* NOTE: Windows also doesn't store nr. of planes separately! */
   BitsPixel = BITMAPOBJ_GetRealBitsPixel(BitsPixel * Planes);

   /* Check parameters */
   if (BitsPixel == 0 || Width < 1 || Height < 1)
   {
      DPRINT1("Width = %d, Height = %d BitsPixel = %d\n", Width, Height, BitsPixel);
      SetLastWin32Error(ERROR_INVALID_PARAMETER);
      return 0;
   }

   WidthBytes = BITMAPOBJ_GetWidthBytes(Width, BitsPixel);

   Size.cx = Width;
   Size.cy = Height;

   /* Create the bitmap object. */
   hBitmap = IntCreateBitmap(Size, WidthBytes,
                             BitmapFormat(BitsPixel, BI_RGB),
                             (Height < 0 ? BMF_TOPDOWN : 0) |
                             (NULL == pBits ? 0 : BMF_NOZEROINIT), NULL);
   if (!hBitmap)
   {
      DPRINT("IntGdiCreateBitmap: returned 0\n");
      return 0;
   }

   DPRINT("IntGdiCreateBitmap:%dx%d, %d BPP colors returning %08x\n",
          Size.cx, Size.cy, BitsPixel, hBitmap);

   bmp = BITMAPOBJ_LockBitmap( hBitmap );
   if (bmp == NULL)
   {
      /* FIXME should we free the hBitmap or return it ?? */
      return 0;
   }
   
   bmp->flFlags = BITMAPOBJ_IS_APIBITMAP;

   if (NULL != pBits)
   {
      IntSetBitmapBits(bmp, bmp->SurfObj.cjBits, pBits);
   }

   BITMAPOBJ_UnlockBitmap( bmp );

   return hBitmap;
}


HBITMAP STDCALL
NtGdiCreateBitmap(
    INT  Width,
    INT  Height,
    UINT  Planes,
    UINT  BitsPixel,
    IN OPTIONAL LPBYTE pUnsafeBits)
{
   HBITMAP hBitmap;

   _SEH_TRY
   {
      if (pUnsafeBits)
      {
         UINT cjBits = BITMAPOBJ_GetWidthBytes(Width, BitsPixel) * Height;
         ProbeForRead(pUnsafeBits, cjBits, 1);
      }
      hBitmap = IntGdiCreateBitmap(Width, Height, Planes, BitsPixel, pUnsafeBits);
   }
   _SEH_HANDLE
   {
      hBitmap = 0;
   }
   _SEH_END

   return hBitmap;
}

BOOL INTERNAL_CALL
BITMAP_Cleanup(PVOID ObjectBody)
{
	PBITMAPOBJ pBmp = (PBITMAPOBJ)ObjectBody;
	if (pBmp->SurfObj.pvBits != NULL &&
		(pBmp->flFlags & BITMAPOBJ_IS_APIBITMAP))
	{
		if (pBmp->dib == NULL)
		{
			if (pBmp->SurfObj.pvBits != NULL)
			    ExFreePool(pBmp->SurfObj.pvBits);
		}
		else
		{
			if (pBmp->SurfObj.pvBits != NULL)
				EngFreeUserMem(pBmp->SurfObj.pvBits);
		}
		if (pBmp->hDIBPalette != NULL)
		{			
			NtGdiDeleteObject(pBmp->hDIBPalette);
		}
	}

	if (NULL != pBmp->BitsLock)
	{
		ExFreePoolWithTag(pBmp->BitsLock, TAG_BITMAPOBJ);
		pBmp->BitsLock = NULL;
	}

	return TRUE;
}


HBITMAP FASTCALL
IntCreateCompatibleBitmap(
	PDC Dc,
	INT Width,
	INT Height)
{
	HBITMAP Bmp;

	Bmp = NULL;

	if ((Width >= 0x10000) || (Height >= 0x10000))
	{
		DPRINT1("got bad width %d or height %d, please look for reason\n", Width, Height);
		return NULL;
	}

	/* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
	if (0 == Width || 0 == Height)
	{
		Bmp = IntGdiCreateBitmap (1, 1, 1, 1, NULL);
	}
	else
	{
		Bmp = IntGdiCreateBitmap(Width, Height, 1, Dc->w.bitsPerPixel, NULL);
	}

	return Bmp;
}

HBITMAP STDCALL
NtGdiCreateCompatibleBitmap(
	HDC hDC,
	INT Width,
	INT Height)
{
	HBITMAP Bmp;
	PDC Dc;

	Dc = DC_LockDc(hDC);

	DPRINT("NtGdiCreateCompatibleBitmap(%04x,%d,%d, bpp:%d) = \n", hDC, Width, Height, Dc->w.bitsPerPixel);

	if (NULL == Dc)
	{
		SetLastWin32Error(ERROR_INVALID_HANDLE);
		return NULL;
	}

	Bmp = IntCreateCompatibleBitmap(Dc, Width, Height);

	DPRINT ("\t\t%04x\n", Bmp);
	DC_UnlockDc(Dc);
	return Bmp;
}

BOOL STDCALL
NtGdiGetBitmapDimension(
	HBITMAP  hBitmap,
	LPSIZE  Dimension)
{
	PBITMAPOBJ  bmp;

	bmp = BITMAPOBJ_LockBitmap(hBitmap);
	if (bmp == NULL)
	{
		return FALSE;
	}

	*Dimension = bmp->dimension;

	BITMAPOBJ_UnlockBitmap(bmp);

	return  TRUE;
}

COLORREF STDCALL
NtGdiGetPixel(HDC hDC, INT XPos, INT YPos)
{
	PDC dc = NULL;
	COLORREF Result = (COLORREF)CLR_INVALID; // default to failure
	BOOL bInRect = FALSE;
	BITMAPOBJ *BitmapObject;
	SURFOBJ *SurfaceObject;
	HPALETTE Pal = 0;
	XLATEOBJ *XlateObj;
	HBITMAP hBmpTmp;

	dc = DC_LockDc (hDC);

	if ( !dc )
	{
		SetLastWin32Error(ERROR_INVALID_HANDLE);
		return Result;
	}
	if (dc->IsIC)
	{
		DC_UnlockDc(dc);
		return Result;
	}
	XPos += dc->w.DCOrgX;
	YPos += dc->w.DCOrgY;
	if ( IN_RECT(dc->CombinedClip->rclBounds,XPos,YPos) )
	{
		bInRect = TRUE;
		BitmapObject = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
		SurfaceObject = &BitmapObject->SurfObj;
		if ( BitmapObject )
		{
			if ( dc->w.hPalette != 0 )
				Pal = dc->w.hPalette;
			/* FIXME: Verify if it shouldn't be PAL_BGR! */
			XlateObj = (XLATEOBJ*)IntEngCreateXlate ( PAL_RGB, 0, NULL, Pal );
			if ( XlateObj )
			{
				// check if this DC has a DIB behind it...
				if ( SurfaceObject->pvScan0 ) // STYPE_BITMAP == SurfaceObject->iType
				{
					ASSERT ( SurfaceObject->lDelta );
					Result = XLATEOBJ_iXlate(XlateObj,
						DibFunctionsForBitmapFormat[SurfaceObject->iBitmapFormat].DIB_GetPixel ( SurfaceObject, XPos, YPos ) );
				}
				EngDeleteXlate(XlateObj);
			}
			BITMAPOBJ_UnlockBitmap(BitmapObject);
		}
	}
	DC_UnlockDc(dc);

	// if Result is still CLR_INVALID, then the "quick" method above didn't work
	if ( bInRect && Result == CLR_INVALID )
	{
		// FIXME: create a 1x1 32BPP DIB, and blit to it
		HDC hDCTmp = NtGdiCreateCompatibleDC(hDC);
		if ( hDCTmp )
		{
			static const BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER), 1, 1, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
			BITMAPINFO bi;
			RtlMoveMemory ( &(bi.bmiHeader), &bih, sizeof(bih) );
			hBmpTmp = NtGdiCreateDIBitmap ( hDC, &bi.bmiHeader, 0, NULL, &bi, DIB_RGB_COLORS );
			//HBITMAP hBmpTmp = IntGdiCreateBitmap ( 1, 1, 1, 32, NULL);
			if ( hBmpTmp )
			{
				HBITMAP hBmpOld = (HBITMAP)NtGdiSelectObject ( hDCTmp, hBmpTmp );
				if ( hBmpOld )
				{
					PBITMAPOBJ bmpobj;

					NtGdiBitBlt ( hDCTmp, 0, 0, 1, 1, hDC, XPos, YPos, SRCCOPY, 0, 0 );
					NtGdiSelectObject ( hDCTmp, hBmpOld );

					// our bitmap is no longer selected, so we can access it's stuff...
					bmpobj = BITMAPOBJ_LockBitmap ( hBmpTmp );
					if ( bmpobj )
					{
						Result = *(COLORREF*)bmpobj->SurfObj.pvScan0;
						BITMAPOBJ_UnlockBitmap ( bmpobj );
					}
				}
				NtGdiDeleteObject ( hBmpTmp );
			}
			NtGdiDeleteObjectApp ( hDCTmp );
		}
	}

	return Result;
}


LONG STDCALL
IntGetBitmapBits(
	PBITMAPOBJ bmp,
	DWORD Bytes,
	OUT PBYTE Bits)
{
	LONG ret;

	ASSERT(Bits);

	/* Don't copy more bytes than the buffer has */
	Bytes = min(Bytes, bmp->SurfObj.cjBits);

#if 0
	/* FIXME: Call DDI CopyBits here if available  */
	if(bmp->DDBitmap)
	{
		DPRINT("Calling device specific BitmapBits\n");
		if(bmp->DDBitmap->funcs->pBitmapBits)
		{
			ret = bmp->DDBitmap->funcs->pBitmapBits(hbitmap, bits, count, DDB_GET);
		}
		else
		{
			ERR_(bitmap)("BitmapBits == NULL??\n");
			ret = 0;
		}
	}
	else
#endif
	{
		RtlCopyMemory(Bits, bmp->SurfObj.pvBits, Bytes);
		ret = Bytes;
	}
	return ret;
}

LONG STDCALL
NtGdiGetBitmapBits(HBITMAP  hBitmap,
                   ULONG  Bytes,
                   OUT OPTIONAL PBYTE pUnsafeBits)
{
	PBITMAPOBJ  bmp;
	LONG  ret;

	if (pUnsafeBits != NULL && Bytes == 0)
	{
		return 0;
	}

	bmp = BITMAPOBJ_LockBitmap (hBitmap);
	if (!bmp)
	{
		SetLastWin32Error(ERROR_INVALID_HANDLE);
		return 0;
	}

	/* If the bits vector is null, the function should return the read size */
	if (pUnsafeBits == NULL)
	{
		ret = bmp->SurfObj.cjBits;
		BITMAPOBJ_UnlockBitmap (bmp);
		return ret;
	}

	/* Don't copy more bytes than the buffer has */
	Bytes = min(Bytes, bmp->SurfObj.cjBits);

	_SEH_TRY
	{
		ProbeForWrite(pUnsafeBits, Bytes, 1);
		ret = IntGetBitmapBits(bmp, Bytes, pUnsafeBits);
	}
	_SEH_HANDLE
	{
		ret = 0;
	}
	_SEH_END

	BITMAPOBJ_UnlockBitmap (bmp);

	return  ret;
}


LONG STDCALL
IntSetBitmapBits(
	PBITMAPOBJ bmp,
	DWORD  Bytes,
	IN PBYTE Bits)
{
	LONG ret;

	/* Don't copy more bytes than the buffer has */
	Bytes = min(Bytes, bmp->SurfObj.cjBits);

#if 0
	/* FIXME: call DDI specific function here if available  */
	if(bmp->DDBitmap)
	{
		DPRINT ("Calling device specific BitmapBits\n");
		if (bmp->DDBitmap->funcs->pBitmapBits)
		{
			ret = bmp->DDBitmap->funcs->pBitmapBits(hBitmap, (void *) Bits, Bytes, DDB_SET);
		}
		else
		{
			DPRINT ("BitmapBits == NULL??\n");
			ret = 0;
		}
	}
	else
#endif
	{
		RtlCopyMemory(bmp->SurfObj.pvBits, Bits, Bytes);
		ret = Bytes;
	}

	return ret;
}


LONG STDCALL
NtGdiSetBitmapBits(
	HBITMAP  hBitmap,
	DWORD  Bytes,
	IN PBYTE pUnsafeBits)
{
	LONG ret;
	PBITMAPOBJ bmp;

	if (pUnsafeBits == NULL || Bytes == 0)
	{
		return 0;
	}

	bmp = BITMAPOBJ_LockBitmap(hBitmap);
	if (bmp == NULL)
	{
		SetLastWin32Error(ERROR_INVALID_HANDLE);
		return 0;
	}

	_SEH_TRY
	{
		ProbeForRead(pUnsafeBits, Bytes, 1);
		ret = IntSetBitmapBits(bmp, Bytes, pUnsafeBits);
	}
	_SEH_HANDLE
	{
		ret = 0;
	}
	_SEH_END

	BITMAPOBJ_UnlockBitmap(bmp);

	return ret;
}

BOOL STDCALL
NtGdiSetBitmapDimension(
	HBITMAP  hBitmap,
	INT  Width,
	INT  Height,
	LPSIZE  Size)
{
	PBITMAPOBJ  bmp;

	bmp = BITMAPOBJ_LockBitmap(hBitmap);
	if (bmp == NULL)
	{
		return FALSE;
	}

	if (Size)
	{
		*Size = bmp->dimension;
	}
	bmp->dimension.cx = Width;
	bmp->dimension.cy = Height;

	BITMAPOBJ_UnlockBitmap (bmp);

	return TRUE;
}

COLORREF STDCALL
NtGdiSetPixel(
	HDC  hDC,
	INT  X,
	INT  Y,
	COLORREF  Color)
{
   
	DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n",X,Y,Color);	
	
	
	DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n",X,Y,Color);

	if (NtGdiSetPixelV(hDC,X,Y,Color))
	{
		Color = NtGdiGetPixel(hDC,X,Y);
		DPRINT("1 NtGdiSetPixel X %ld Y %ld C %ld\n",X,Y,Color);
		return Color;
	}

	Color = ((COLORREF) -1);
	DPRINT("2 NtGdiSetPixel X %ld Y %ld C %ld\n",X,Y,Color);
	return Color;
}

BOOL STDCALL
NtGdiSetPixelV(
	HDC  hDC,
	INT  X,
	INT  Y,
	COLORREF  Color)
{
	HBRUSH NewBrush = NtGdiCreateSolidBrush(Color, NULL);
	HGDIOBJ OldBrush;

	if (NewBrush == NULL)
		return(FALSE);
	OldBrush = NtGdiSelectObject(hDC, NewBrush);
	if (OldBrush == NULL)
	{
		NtGdiDeleteObject(NewBrush);
		return(FALSE);
	}
	NtGdiPatBlt(hDC, X, Y, 1, 1, PATCOPY);
	NtGdiSelectObject(hDC, OldBrush);
	NtGdiDeleteObject(NewBrush);
	return TRUE;
}

/*  Internal Functions  */

INT FASTCALL
BITMAPOBJ_GetRealBitsPixel(INT nBitsPixel)
{
	if (nBitsPixel < 0)
		return 0;
	if (nBitsPixel <= 1)
		return 1;
	if (nBitsPixel <= 2)
		return 2;
	if (nBitsPixel <= 4)
		return 4;
	if (nBitsPixel <= 8)
		return 8;
	if (nBitsPixel <= 16)
		return 16;
	if (nBitsPixel <= 24)
		return 24;
	if (nBitsPixel <= 32)
		return 32;

	return 0;
}

INT FASTCALL
BITMAPOBJ_GetWidthBytes (INT bmWidth, INT bpp)
{
#if 0
	switch(bpp)
	{
	case 1:
		return 2 * ((bmWidth+15) >> 4);

	case 24:
		bmWidth *= 3; /* fall through */
	case 8:
		return bmWidth + (bmWidth & 1);

	case 32:
		return bmWidth * 4;

	case 16:
	case 15:
		return bmWidth * 2;

	case 4:
		return 2 * ((bmWidth+3) >> 2);

	default:
		DPRINT ("stub");
	}

	return -1;
#endif

	return ((bmWidth * bpp + 15) & ~15) >> 3;
}

HBITMAP FASTCALL
BITMAPOBJ_CopyBitmap(HBITMAP  hBitmap)
{
	HBITMAP  res;
	BITMAP  bm;
	BITMAPOBJ *Bitmap, *resBitmap;
	SIZEL Size;

	if (hBitmap == NULL)
	{
		return 0;
	}

	Bitmap = GDIOBJ_LockObj(GdiHandleTable, hBitmap, GDI_OBJECT_TYPE_BITMAP);
	if (Bitmap == NULL)
	{
		return 0;
	}

	BITMAP_GetObject(Bitmap, sizeof(BITMAP), &bm);
	bm.bmBits = NULL;
	if (Bitmap->SurfObj.lDelta >= 0)
		bm.bmHeight = -bm.bmHeight;

	Size.cx = abs(bm.bmWidth);
	Size.cy = abs(bm.bmHeight);
	res = IntCreateBitmap(Size,
	                      bm.bmWidthBytes,
	                      BitmapFormat(bm.bmBitsPixel * bm.bmPlanes, BI_RGB),
	                      (bm.bmHeight < 0 ? BMF_TOPDOWN : 0) | BMF_NOZEROINIT,
	                      NULL);

	if(res)
	{
		PBYTE buf;

		resBitmap = GDIOBJ_LockObj(GdiHandleTable, res, GDI_OBJECT_TYPE_BITMAP);
		if (resBitmap)
		{
			buf = ExAllocatePoolWithTag (PagedPool, bm.bmWidthBytes * abs(bm.bmHeight), TAG_BITMAP);
			IntGetBitmapBits (Bitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
			IntSetBitmapBits (resBitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
			ExFreePool (buf);
			GDIOBJ_UnlockObjByPtr(GdiHandleTable, resBitmap);
		}
	}

	GDIOBJ_UnlockObjByPtr(GdiHandleTable, Bitmap);

	return  res;
}

INT STDCALL
BITMAP_GetObject(BITMAPOBJ * bmp, INT Count, LPVOID buffer)
{
	if ((UINT)Count < sizeof(BITMAP)) return 0;

	if(bmp->dib)
	{
		if((UINT)Count < sizeof(DIBSECTION))
		{
			Count = sizeof(BITMAP);
		}
		else
		{
			Count = sizeof(DIBSECTION);
		}
		if (buffer)
		{
			memcpy(buffer, bmp->dib, Count);
		}
		return Count;
	}
	else
	{
		Count = sizeof(BITMAP);
		if (buffer)
		{
			BITMAP Bitmap;

			Count = sizeof(BITMAP);
			Bitmap.bmType = 0;
			Bitmap.bmWidth = bmp->SurfObj.sizlBitmap.cx;
			Bitmap.bmHeight = bmp->SurfObj.sizlBitmap.cy;
			Bitmap.bmWidthBytes = abs(bmp->SurfObj.lDelta);
			Bitmap.bmPlanes = 1;
			Bitmap.bmBitsPixel = BitsPerFormat(bmp->SurfObj.iBitmapFormat);
			//Bitmap.bmBits = bmp->SurfObj.pvBits;
			Bitmap.bmBits = NULL; /* not set accoring wine test confirm in win2k */
			memcpy(buffer, &Bitmap, Count);
		}
		return Count;
	}
}
/* EOF */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -