This includes:
// Attribute igpbitmap. pixels; {obtain or set the color of the specified pixel} // igpbitmap method. setresolution (); {set resolution} igpbitmap. gethbitmap (); {create a bitmap in GDI format and return a handle} igpbitmap. gethicon; {create an icon file and return a handle} igpbitmap. lockbits (); {lock the pixel data in the memory of the object} igpbitmap. unlockbits (); {unlock lockbits}
Igpbitmap. pixels property test:
uses GdiPlus;procedure TForm1.FormPaint(Sender: TObject);var Bitmap: IGPBitmap; Graphics: IGPGraphics; i,j: Integer; Color: TGPColor;begin Bitmap := TGPBitmap.Create('C:\GdiPlusImg\Grapes.jpg'); Graphics := TGPGraphics.Create(Handle); Graphics.DrawImage(Bitmap, 10, 10, Bitmap.Width, Bitmap.Height); for i := 0 to Bitmap.Width - 1 do for j := 0 to Bitmap.Height - 1 do begin Color := Bitmap.Pixels[i,j]; Bitmap.Pixels[i,j] := TGPColor.Create(Color.R, 0, 0); end; Graphics.TranslateTransform(Bitmap.Width + 10, 0); Graphics.DrawImage(Bitmap, 10, 10, Bitmap.Width, Bitmap.Height);end;
Igpbitmap. setresolution method test:
uses GdiPlus;procedure TForm1.FormPaint(Sender: TObject);var Graphics: IGPGraphics; Bitmap: IGPBitmap;begin Bitmap := TGPBitmap.Create('C:\GdiPlusImg\Apple.gif'); Graphics := TGPGraphics.Create(Handle); Graphics.DrawImage(Bitmap, 10, 10); Graphics.TranslateTransform(Bitmap.Width + 10, 0); Bitmap.SetResolution(Bitmap.HorizontalResolution/2, Bitmap.VerticalResolution/2); Graphics.DrawImage(Bitmap, 10, 10);end;
Igpbitmap. gethbitmap method test:
Uses gdiplus; Procedure tform1.formpaint (Sender: tobject); var bitmap: igpbitmap; gdibitmap: tbitmap; begin bitmap: = tgpbitmap. create ('C: \ gdiplusimg \ bird.bmp '); gdibitmap: = tbitmap. create; // The gethbitmap parameter is the background color, used to fill the transparent part; when there is no transparent part, it will be ignored gdibitmap. handle: = bitmap. gethbitmap ($ ff00000); gdibitmap. transparentcolor: = clwhite; gdibitmap. transparent: = true; canvas. draw (10, 10, gdibitmap); gdibitmap. free; end;
Igpbitmap. gethicon method test:
uses GdiPlus;var Bitmap: IGPBitmap;procedure TForm1.FormPaint(Sender: TObject);var Image: IGPImage; Rect: TGPRect; Graphics: IGPGraphics; Attr: IGPImageAttributes;begin Image := TGPImage.Create('C:\GdiPlusImg\Apple.gif'); Bitmap := TGPBitmap.Create(16, 16); Rect.Initialize(0, 0, Bitmap.Width, Bitmap.Height); Graphics := TGPGraphics.Create(Bitmap); Attr := TGPImageAttributes.Create; Attr.SetColorKey($FFFFFFFF, $FFFFFFFF); Graphics.DrawImage(Image, Rect, 0, 0, Image.Width, Image.Height, UnitPixel, Attr); Application.Icon.Handle := Bitmap.GetHIcon;end;
Next, it is related to igpbitmap. lockbits and igpbitmap. unlockbits.
Similar functions are often seen in winapi, because the memory address in the data is dynamic under the Windows automatic management in memory, so the memory should be locked before the operation, the pointer will be given to you after the lock; The lockbits here is also like this, of course, to unlock after the operation is complete.
Here, lockbits returns not only the memory address, but a structure containing the memory address:
Tgpbitmapdata = record width: Cardinal; {pixel width; or number of records in a scanned row} Height: Cardinal; {pixel height; or number of scanned rows} stride: integer; {scan width of each row; it should be a multiple of 4} pixelformat: tgppixelformat; {pixel format information} scan0: pointer; {address of the first pixel data} Reserved: Cardinal; {reserved} end;
In the structure, only stride is confusing. It is the number of bytes occupied by each line, for example:
A row contains 11 pixels (width = 11). For a 32-bit (4 bytes per pixel) image, stride = 11*4 = 44.
However, there is still a problem of byte alignment, such:
A row contains 11 pixels (width = 11). For a 24-bit (3 bytes per pixel) image, stride = 11*3 + 3 = 36.
Why not stride = 33? Because it is 4-byte aligned.
Based on the above principle, we can manually calculate the value of Stride:
1. stride = the number of bytes occupied by each pixel (that is, the number of pixels/8) * width;
2. If stride is not a multiple of 4, stride = stride + (4-stride mod 4 );
The following example tests and verifies the above ideas:
uses GdiPlus;procedure TForm1.FormPaint(Sender: TObject);var Bitmap: IGPBitmap; Rect: TGPRect; Graphics: IGPGraphics; Data: TGPBitmapData; n: Integer;begin ChDir('C:\GdiPlusImg\'); Bitmap := TGPBitmap.Create('Grapes.jpg'); Rect.Initialize(0, 0, Bitmap.Width, Bitmap.Height); Data := Bitmap.LockBits(Rect, [ImageLockModeRead], Bitmap.PixelFormat); n := GetPixelFormatSize(Data.PixelFormat) div 8 * Data.Width; n := n + (4 - n mod 4); ShowMessageFmt('%d, %d, %d', [Data.Width, Data.Stride, n]); { 187, 564, 564 } Bitmap.UnlockBits(Data); // Bitmap := TGPBitmap.Create('Bird.bmp'); Rect.Initialize(0, 0, Bitmap.Width, Bitmap.Height); Data := Bitmap.LockBits(Rect, [ImageLockModeRead], Bitmap.PixelFormat); n := GetPixelFormatSize(Data.PixelFormat) div 8 * Data.Width; if n mod 4 0 then n := n + (4 - n mod 4); ShowMessageFmt('%d, %d, %d', [Data.Width, Data.Stride, n]); { 110, 112, 112 } Bitmap.UnlockBits(Data); // Bitmap := TGPBitmap.Create('Apple.gif'); Rect.Initialize(0, 0, Bitmap.Width, Bitmap.Height); Data := Bitmap.LockBits(Rect, [ImageLockModeRead], Bitmap.PixelFormat); n := GetPixelFormatSize(Data.PixelFormat) div 8 * Data.Width; if n mod 4 0 then n := n + (4 - n mod 4); ShowMessageFmt('%d, %d, %d', [Data.Width, Data.Stride, n]); { 120, 120, 120 } Bitmap.UnlockBits(Data); // Bitmap := TGPBitmap.Create('ImageFileSmall.jpg'); Rect.Initialize(0, 0, Bitmap.Width, Bitmap.Height); Data := Bitmap.LockBits(Rect, [ImageLockModeRead], Bitmap.PixelFormat); n := GetPixelFormatSize(Data.PixelFormat) div 8 * Data.Width; if n mod 4 0 then n := n + (4 - n mod 4); ShowMessageFmt('%d, %d, %d', [Data.Width, Data.Stride, n]); { 320, 960, 960 } Bitmap.UnlockBits(Data);end;
In the face of images in different pixel formats, the problem of byte alignment is indeed very troublesome;
However, this problem can be ignored for 32-bit images, because the data in each row of the image is exactly a multiple of 4. The following exercises all discuss this coincidence.
We also need to know that the order of the four bytes of each 32-bit image pixel in memory is bbggrraa.
Example of modifying the memory data to make the image Translucent:
Uses gdiplus; Type ppixelfour = ^ tpixelfour; tpixelfour = record B1, B2, B3, b4: byte; end; Procedure submit (Sender: tobject); var bitmap, bitmap32: igpbitmap; graphics: igpgraphics; rect: tgprect; Data: tgpbitmapdata; P: ppixelfour; brush: igphatchbrush; I: integer; begin bitmap: = tgpbitmap. create ('C: \ gdiplusimg \ grapes.jpg '); rect. initialize (0, 0, bitmap. width, bitmap. height); // get an image in 32-bit pixel format; // Like igpbitmap. the clone method can facilitate the conversion, but it does not work; // there is also an igpbitmap. the convertformat method is GDI + 1.1; // bitmap32: = tgpbitmap can only be manually used. create (bitmap. width, bitmap. height, pixelformat32bppargb); graphics: = tgpgraphics. create (bitmap32); graphics. drawimage (bitmap, rect); Data: = bitmap32.lockbits (rect, [imagelockmodewrite], bitmap32.pixelformat); P: = data. scan0; {$ pointermath on} For I: = 0 to Data. width * data. height-1 do P [I]. b4: = $80; {$ pointermath off} bitmap32.unlockbits (data); graphics: = tgpgraphics. create (handle); brush: = tgphatchbrush. create (hatchstylecross, $ ffd0d0d0, $ ffffffff); graphics. fillrectangle (brush, tgprect. create (clientrect); graphics. drawimage (bitmap32, 10, 10); end;
An example of modifying the memory data to retain only the Green Channels of images:
Uses gdiplus; Type ppixelfour = ^ tpixelfour; tpixelfour = record B1, B2, B3, b4: byte; end; Procedure submit (Sender: tobject); var bitmap, bitmap32: igpbitmap; graphics: igpgraphics; rect: tgprect; Data: tgpbitmapdata; P: ppixelfour; I: integer; begin bitmap: = tgpbitmap. create ('C: \ gdiplusimg \ grapes.jpg '); rect. initialize (0, 0, bitmap. width, bitmap. height); // get a 32-bit pixel image; bitmap32: = tgpbitmap. create (bitmap. width, bitmap. height, pixelformat32bppargb); graphics: = tgpgraphics. create (bitmap32); graphics. drawimage (bitmap, rect); Data: = bitmap32.lockbits (rect, [imagelockmodewrite], bitmap32.pixelformat); P: = data. scan0; {$ pointermath on} For I: = 0 to Data. width * data. height-1 do begin P [I]. b1: = 0; P [I]. b3: = 0; end; {$ pointermath off} bitmap32.unlockbits (data); graphics: = tgpgraphics. create (handle); graphics. drawimage (bitmap32, 10, 10); end;
Example of converting an image to grayscale by modifying memory data:
Uses gdiplus; Type ppixelfour = ^ tpixelfour; tpixelfour = record B1, B2, B3, b4: byte; end; Procedure submit (Sender: tobject); var bitmap, bitmap32: igpbitmap; graphics: igpgraphics; rect: tgprect; Data: tgpbitmapdata; P: ppixelfour; I, G: integer; begin bitmap: = tgpbitmap. create ('C: \ gdiplusimg \ grapes.jpg '); rect. initialize (0, 0, bitmap. width, bitmap. height); // get a 32-bit pixel image; bitmap32: = tgpbitmap. create (bitmap. width, bitmap. height, pixelformat32bppargb); graphics: = tgpgraphics. create (bitmap32); graphics. drawimage (bitmap, rect); Data: = bitmap32.lockbits (rect, [imagelockmodewrite], bitmap32.pixelformat); P: = data. scan0; {$ pointermath on} For I: = 0 to Data. width * data. height-1 do begin G: = (P [I]. b1 + P [I]. b2 + P [I]. b3) Div 3; p [I]. b1: = g; P [I]. b2: = g; P [I]. b3: = g; end; {$ pointermath off} bitmap32.unlockbits (data); graphics: = tgpgraphics. create (handle); graphics. drawimage (bitmap32, 10, 10); end;
In addition:
1. In fact, only color transformation is required. The above methods are not as convenient as using colormatrix;
2. The above memory operations can be done more easily with igpbitmap. pixels, but it is too slow.
3. when processing the byte offset, The igpimagebytes interface may be a solution, but it is not tested.