Usando GDI plus podemos conseguir resultados mucho mas aparentes, así que he escrito dos funciones simples, una para dibujar un bitmap al tamaño deseado y otra para cambiar el tamaño de un bitmap de forma que éste puede ser volcado a una imagen o guardado en un archivo con sus nuevas dimensiones.
Estas son las funciones GDI flat usadas:
delphi
// GDI+ Flat API... function GdiplusStartup(var GdiToken: DWORD; Startup, Output: PBYTE): Cardinal; stdcall external 'gdiplus'; procedure GdiplusShutdown(GdiToken: DWORD); stdcall external 'gdiplus'; function GdipCreateBitmapFromHBITMAP(hbm: HBITMAP; hpal: HPALETTE; var GBitmap: THANDLE): Cardinal; stdcall external 'gdiplus'; function GdipDisposeImage(image: THANDLE): Cardinal; stdcall external 'gdiplus'; function GdipCreateFromHDC(DC: HDC; var Graphics: Pointer): Cardinal; stdcall external 'gdiplus'; function GdipDeleteGraphics(graphics: Pointer): Cardinal; stdcall external 'gdiplus'; function GdipDrawImageRect(graphics: Pointer; Image: THANDLE; x, y, w, h: Single): Cardinal; stdcall external 'gdiplus';
La primera función, DrawImageRect:
delphi
//--------------------------------------------------------------------------- // Dibuja un Bitmap en un hDC ajustando su tamaño para que quepa entero // en las coordenadas dadas procedure DrawImageRect(DC: HDC; Bitmap: HBITMAP; X, Y, W, H: integer); var Graphics: Pointer; GBitmap: THANDLE; begin GdipCreateBitmapFromHBITMAP(Bitmap, 0, GBitmap); GdipCreateFromHDC(DC, Graphics); GdipDrawImageRect(Graphics, GBitmap, X, Y, W, H); GdipDisposeImage(GBitmap); GdipDeleteGraphics(Graphics); end;
Un ejemplo de uso:
delphi
var gdiplusToken: DWORD; GdiPlusStartupInput: array[0..1] of int64; begin // Inicializamos GDI+. GdiPlusStartupInput[0]:= 1; GdiPlusStartupInput[1]:= 0; if GdiplusStartup(gdiplusToken, @GdiPlusStartupInput, nil) <> 0 then exit; DrawImageRect(Image2.Picture.Bitmap.Canvas.Handle, Image1.Picture.Bitmap.Handle, 20, 20, 200, 150); Image2.Invalidate; // Shutdown GDI+ GdiplusShutdown(gdiplusToken); end;
La segunda función CreateResizeBitmap:
delphi
//----------------------------------------------------------------------------- // Crea y devuelve un Bitmap con unas nuevas dimensiones y la imagen ajustada a estas function CreateResizeBitmap(Bitmap: HBITMAP; H, W: integer): HBITMAP; var Graphics: Pointer; GBitmap: THANDLE; DC, dcMem: HDC; bmOld: HBITMAP; begin DC:= GetDC(0); Result:= CreateCompatibleBitmap(DC, W, H); dcMem:= CreateCompatibleDC(DC); bmOld:= SelectObject(dcMem, Result); GdipCreateFromHDC(dcMem, Graphics); GdipCreateBitmapFromHBITMAP(Bitmap, 0, GBitmap); GdipDrawImageRect(Graphics, GBitmap, 0, 0, H, W); GdipDisposeImage(GBitmap); GdipDeleteGraphics(Graphics); SelectObject(dcMem, bmOld); DeleteDC(dcMem); ReleaseDC(0, DC); end;
Como creamos un Bitmap nuevo, somos responsables de borrar ese Handle con DeleteObject. Si lo asignamos a un TBitmap la VCL se encargará de hacerlo al destruirlo pero en otro caso somos responsables de su destrucción.
Un ejemplo de uso:
delphi
var gdiplusToken: DWORD; GdiPlusStartupInput: array[0..1] of int64; begin // Inicializamos GDI+. GdiPlusStartupInput[0]:= 1; GdiPlusStartupInput[1]:= 0; if GdiplusStartup(gdiplusToken, @GdiPlusStartupInput, nil) <> 0 then exit; Image1.Picture.Bitmap.Handle:= CreateResizeBitmap(Image1.Picture.Bitmap.Handle, 100, 100); Image1.Invalidate; // Shutdown GDI+ GdiplusShutdown(gdiplusToken); end;
Podremos guardar el HBITMAP con la VCL o bien usando GDI+ como en ejemplo de este hilo.
Finalmente añadir que debemos inicializar GDI+ antes de usar las funciones y cerrarlo después. Esto se puede incluir en las funciones para automatizarlo pero si vamos a hacer uso intensivo de GDI+ no tiene sentido abrir y cerrar cada vez, por ese motivo no lo he incluido en las funciones individuales. Podemos inicializar GDI+ al inicio del programa o de la sección que lo usa y cerrar al terminar.
Saludos.