123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904 |
- // AARotate_Fast v1.2
- //
- // This unit is based on the VB code written by Lefteris Eleftheriades.
- // Please visit "http://www2.cs.ucy.ac.cy/~cs06ee1/", if you want to know more
- // about the background of this unit.
- //
- // v1.22 : 30 Mar 2009
- // Fixed floating point exception (occured at Transparent = true) (ver 1.20)
- // Added a parameter : Scale (ver 1.20)
- // Added a parameter : ApplySrcAlpha (ver 1.21)
- // Fixed bug at caculating transparency (ver 1.22)
- //
- // v1.1 : 23 Mar 2009
- // Added a parameter : Transparent
- //
- // v1.0 : 17 Mar 2009
- // Initial release
- //
- // written by Silhwan Hyun (hyunsh@hanafos.com)
- unit AARotate_Fast;
- interface
- uses Windows, graphics, Math, SysUtils;
- // Parameters & Result
- // SrcBitmap : The source image to be rotated.
- // Rotation : The degree by which the image should be rotated clockwise.
- // BgColor : The color of the background where the rotated bitmap does not overlap the
- // destination bitmap.
- // Transparent : Decides if the BgColor is treated as Transparent color.
- // It means BGColor is excluded at adding color elements and Alpha.
- // ApplySrcAlpha : This parameter is valid only if the PixelFormat of source image is
- // pf32bit.
- // Decides whether to apply source image's alpha channel(acually the "rgbReserved"
- // elements of TBitmap's pixel. We can load PNG file preserving alpha channel
- // data by use of GdipLoadImageFromFile and GdipCreateHBITMAPFromBitmap. See demo
- // project.) at calculating the value of destination image's transparency.
- // AutoBlend : This parameter is not effective if Transparent is true. (= considered as
- // false if Transparent is true)
- // Decides if the edges of the rotated image should be blended with the
- // background color defined by BgColor.
- // If false, the rgbReserved byte of each pixel will be set to the appropriate
- // alpha values so that the rotated image can be blended onto another image later
- // without a harsh edge.
- // Scale : The size(width and height) factor of rotated image.
- // Min : 0.1 ~ Max : 10.0 (ex: 0.5 : 50%, 1.0 : 100%, 2.0 : 200%)
- // note) Limited the scaled image is not lesser than 5 pixel in height or width
- // Result : The rotated image. Returns nil if there are errors.
- function FastAARotatedBitmap(SrcBitmap : TBitmap; Rotation : double; BgColor : integer;
- Transparent, ApplySrcAlpha, AutoBlend : boolean; Scale : double) : TBitmap;
- procedure DrawCircleBack(ABitmap : TBitmap; bgColor, lnColor : integer);
- // Draw a circle on Bitmap - see comments in implementation
- procedure DrawCircle(Bitmap: TBitmap; CenterX, CenterY, Radius,
- LineWidth, Feather: single);
- // Draw a disk on Bitmap - see comments in implementation
- procedure DrawDisk(Bitmap: TBitmap; CenterX, CenterY, Radius, Feather: single);
- implementation
- procedure DrawDisk(Bitmap: TBitmap; CenterX, CenterY, Radius, Feather: single);
- // Draw a disk on Bitmap. Bitmap must be a 256 color (pf8bit) palette bitmap,
- // and parts outside the disk will get palette index 0, parts inside will get
- // palette index 255, and in the antialiased area (feather), the pixels will
- // get values inbetween.
- // ***Parameters***
- // Bitmap:
- // The bitmap to draw on
- // CenterX, CenterY:
- // The center of the disk (float precision). Note that [0, 0] would be the
- // center of the first pixel. To draw in the exact middle of a 100x100 bitmap,
- // use CenterX = 49.5 and CenterY = 49.5
- // Radius:
- // The radius of the drawn disk in pixels (float precision)
- // Feather:
- // The feather area. Use 1 pixel for a 1-pixel antialiased area. Pixel centers
- // outside 'Radius + Feather / 2' become 0, pixel centers inside 'Radius - Feather/2'
- // become 255. Using a value of 0 will yield a bilevel image.
- // Copyright (c) 2003 Nils Haeck M.Sc. www.simdesign.nl
- var
- x, y: integer;
- LX, RX, LY, RY: integer;
- Fact: integer;
- RPF2, RMF2: single;
- P: PByteArray;
- SqY, SqDist: single;
- sqX: array of single;
- begin
- // Determine some helpful values (singles)
- RPF2 := sqr(Radius + Feather/2);
- RMF2 := sqr(Radius - Feather/2);
- // Determine bounds:
- LX := Max(floor(CenterX - RPF2), 0);
- RX := Min(ceil (CenterX + RPF2), Bitmap.Width - 1);
- LY := Max(floor(CenterY - RPF2), 0);
- RY := Min(ceil (CenterY + RPF2), Bitmap.Height - 1);
- // Optimization run: find squares of X first
- SetLength(SqX, RX - LX + 1);
- for x := LX to RX do
- SqX[x - LX] := sqr(x - CenterX);
- // Loop through Y values
- for y := LY to RY do begin
- P := Bitmap.Scanline[y];
- SqY := Sqr(y - CenterY);
- // Loop through X values
- for x := LX to RX do begin
- // determine squared distance from center for this pixel
- SqDist := SqY + SqX[x - LX];
- // inside inner circle? Most often..
- if sqdist < RMF2 then begin
- // inside the inner circle.. just give the scanline the new color
- P[x] := 255
- end else begin
- // inside outer circle?
- if sqdist < RPF2 then begin
- // We are inbetween the inner and outer bound, now mix the color
- Fact := round(((Radius - sqrt(sqdist)) * 2 / Feather) * 127.5 + 127.5);
- P[x] := Max(0, Min(Fact, 255)); // just in case limit to [0, 255]
- end else begin
- P[x] := 0;
- end;
- end;
- end;
- end;
- end;
- procedure DrawCircle(Bitmap: TBitmap; CenterX, CenterY, Radius,
- LineWidth, Feather: single);
- // Draw a circle on Bitmap. Bitmap must be a 256 color (pf8bit) palette bitmap,
- // and parts outside the circle will get palette index 0, parts inside will get
- // palette index 255, and in the antialiased area (feather), the pixels will
- // get values inbetween.
- // ***Parameters***
- // Bitmap:
- // The bitmap to draw on
- // CenterX, CenterY:
- // The center of the circle (float precision). Note that [0, 0] would be the
- // center of the first pixel. To draw in the exact middle of a 100x100 bitmap,
- // use CenterX = 49.5 and CenterY = 49.5
- // Radius:
- // The radius of the drawn circle in pixels (float precision)
- // LineWidth
- // The line width of the drawn circle in pixels (float precision)
- // Feather:
- // The feather area. Use 1 pixel for a 1-pixel antialiased area. Pixel centers
- // outside 'Radius + Feather / 2' become 0, pixel centers inside 'Radius - Feather/2'
- // become 255. Using a value of 0 will yield a bilevel image. Note that Feather
- // must be equal or smaller than LineWidth (or it will be adjusted internally)
- // Copyright (c) 2003 Nils Haeck M.Sc. www.simdesign.nl
- var
- x, y: integer;
- LX, RX, LY, RY: integer;
- Fact: integer;
- ROPF2, ROMF2, RIPF2, RIMF2: single;
- OutRad, InRad: single;
- P: PByteArray;
- SqY, SqDist: single;
- sqX: array of single;
- begin
- // Determine some helpful values (singles)
- OutRad := Radius + LineWidth/2;
- InRad := Radius - LineWidth/2;
- ROPF2 := sqr(OutRad + Feather/2);
- ROMF2 := sqr(OutRad - Feather/2);
- RIPF2 := sqr(InRad + Feather/2);
- RIMF2 := sqr(InRad - Feather/2);
- // Determine bounds:
- LX := Max(floor(CenterX - ROPF2), 0);
- RX := Min(ceil (CenterX + ROPF2), Bitmap.Width - 1);
- LY := Max(floor(CenterY - ROPF2), 0);
- RY := Min(ceil (CenterY + ROPF2), Bitmap.Height - 1);
- // Checks
- if Feather > LineWidth then Feather := LineWidth;
- // Optimization run: find squares of X first
- SetLength(SqX, RX - LX + 1);
- for x := LX to RX do
- SqX[x - LX] := sqr(x - CenterX);
- // Loop through Y values
- for y := LY to RY do begin
- P := Bitmap.Scanline[y];
- SqY := Sqr(y - CenterY);
- // Loop through X values
- for x := LX to RX do begin
- // determine squared distance from center for this pixel
- SqDist := SqY + SqX[x - LX];
- // now first check if we're completely inside (most often)
- if SqDist < RIMF2 then begin
- // We're on the disk inside everything
- P[x] := 0;
- end else begin
- // completely outside?
- if SqDist < ROPF2 then begin
- // inside outer line - feather?
- if SqDist < ROMF2 then begin
- // check if we're in inside feather area
- if SqDist < RIPF2 then begin
- // We are in the feather area of inner line, now mix the color
- Fact := round(((sqrt(sqdist) - InRad) * 2 / Feather) * 127.5 + 127.5);
- P[x] := Max(0, Min(Fact, 255)); // just in case limit to [0, 255]
- end else begin
- // on the line
- P[x] := 255;
- end;
- end else begin
- // We are in the feather area of outer line, now mix the color
- Fact := round(((OutRad - sqrt(sqdist)) * 2 / Feather) * 127.5 + 127.5);
- P[x] := Max(0, Min(Fact, 255)); // just in case limit to [0, 255]
- end;
- end else begin
- // outside everything
- P[x] := 0;
- end;
- end;
- end;
- end;
- end;
- procedure DrawCircleBack(ABitmap : TBitmap; bgColor, lnColor : integer);
- // Create a 256-color bitmap and call the DrawCircle procedure
- var
- i, y: integer;
- pal: PLogPalette;
- hpal: HPALETTE;
- ColRGB, BgrRGB: integer;
- //ACenterX, ACenterY,
- //ARadius, AFeather,
- //ALineWidth
- //: single;
- begin
- // 8 bits per pixel
- ABitmap.PixelFormat := pf8bit;
- // Create a gradient palette between foreground and background color
- GetMem(pal, sizeof(TLogPalette) + sizeof(TPaletteEntry) * 255);
- try
- pal.palVersion := $300;
- pal.palNumEntries := 256;
- ColRGB := ColorToRGB(bgColor);
- BgrRGB := ColorToRGB(clWhite);
- for i := 0 to 255 do begin
- pal.palPalEntry[i].peRed := round(i / 255 * (ColRGB AND $FF) + (255 - i) / 255 * (BgrRGB AND $FF));
- pal.palPalEntry[i].peGreen := round(i / 255 * (ColRGB shr 8 AND $FF) + (255 - i) / 255 * (BgrRGB shr 8 AND $FF));
- pal.palPalEntry[i].peBlue := round(i / 255 * (ColRGB shr 16 AND $FF) + (255 - i) / 255 * (BgrRGB shr 16 AND $FF));
- end;
- hpal := CreatePalette(pal^);
- if hpal <> 0 then
- ABitmap.Palette := hpal;
- finally
- FreeMem(pal);
- end;
- // Fill bitmap with background color
- for y := 0 to ABitmap.Height - 1 do
- FillChar(ABitmap.Scanline[y]^, ABitmap.Width, 0);
- end;
- function aar_roundup(A : Double) : longint;
- begin
- if Abs(A - trunc(A + 0.0000000005)) < 0.000000001 then
- aar_roundup := trunc(A + 0.0000000005)
- else
- aar_roundup := trunc(A + 1);
- end;
- function aar_cos(degrees : double) : double;
- var
- off : double;
- idegrees : integer;
- begin
- off := (degrees / 30 - round(degrees / 30));
- if (off < 0.0000001) and (off > -0.0000001) then
- begin
- idegrees := round(degrees);
- if (idegrees < 0) then
- idegrees := (360 - (-idegrees mod 360))
- else
- idegrees := (idegrees mod 360);
- case (idegrees) of
- 0 : result := 1.0;
- 30 : result := 0.866025403784439;
- 60 : result := 0.5;
- 90 : result := 0.0;
- 120 : result := -0.5;
- 150 : result := -0.866025403784439;
- 180 : result := -1.0;
- 210 : result := -0.866025403784439;
- 240 : result := -0.5;
- 270 : result := 0.0;
- 300 : result := 0.5;
- 330 : result := 0.866025403784439;
- 360 : result := 1.0;
- else
- result := cos(degrees * 3.14159265358979 / 180); // it shouldn't get here
- //result := cos(degrees * 3.141592 / 180); // it shouldn't get here
- end;
- end else
- result := cos(degrees * 3.14159265358979 / 180);
- //result := cos(degrees * 3.141592 / 180);
- end;
- function aar_sin(degrees : double) : double;
- begin
- result := aar_cos(degrees + 90.0);
- end;
- function byterange(a : double) : byte;
- var
- b : integer;
- begin
- b := round(a);
- if b < 0 then
- b := 0;
- if b > 255 then
- b := 255;
- result := b;
- end;
- function dorotate(src : HBITMAP; rotation : double; bgcolor : integer; transparent,
- use_src_alpha, autoblend : boolean; scale : double) : HBITMAP;
- const
- mx : array[0..3] of integer = (-1, 1, 1, -1);
- my : array[0..3] of integer = (-1, -1, 1, 1);
- var
- indminx, indminy : integer;
- indmaxx, indmaxy : integer;
- // px, py : integer;
- px, py : double;
- pcos, psin : double;
- xres, yres : double;
- width, height : integer;
- srcbmp : Bitmap;
- srcdib : array of TRGBQUAD;
- dstdib : array of TRGBQUAD;
- srcdibbmap : TBITMAPINFO;
- ldc : HDC;
- backcolor : TRGBQUAD;
- TR, TB, TG : byte;
- XX, YY : integer;
- ix, iy : integer;
- cx, cy : integer;
- tx, ty : double;
- dx, dy : double;
- DstIndex, SrcIndex : integer;
- TopL, TopR, BotL, BotR : double;
- TopL_B, TopR_B, BotL_B, BotR_B : boolean;
- Dst_rgbRed, Dst_rgbBlue, Dst_rgbGreen : double;
- screenmode : DEVMODE;
- dstbmp : HBITMAP;
- dstdibmap : TBITMAPINFO;
- autoblend_ : boolean;
- Alpha : byte;
- RAlpha : double;
- pcos2, psin2 : double;
- InRegionRatio : double;
- A : double;
- begin
- //Calculate some index values so that values can easily be looked up
- indminx := trunc(rotation / 90) mod 4;
- indminy := (indminx + 1) mod 4;
- indmaxx := (indminx + 2) mod 4;
- indmaxy := (indminx + 3) mod 4;
- //Load the source bitmaps information
- if (GetObject(src, sizeof(srcbmp), @srcbmp) = 0) then
- begin
- result := 0;
- exit;
- end;
- //Set the rotation axis default values
- px := srcbmp.bmWidth div 2; // pivot x
- py := srcbmp.bmHeight div 2; // pivot y
- // px := srcbmp.bmWidth / 2; // pivot x
- // py := srcbmp.bmHeight / 2; // pivot y
- //Calculate the cos and sin value
- pcos := aar_cos(Rotation) / abs(scale);
- psin := aar_sin(Rotation) / abs(scale);
- pcos2 := aar_cos(Rotation) * abs(scale);
- psin2 := aar_sin(Rotation) * abs(scale);
- //Calculate the x and y offset of the rotated image (half the width and height of the rotated image)
- xres := mx[indmaxx] * px * pcos2 - my[indmaxx] * py * psin2;
- yres := mx[indmaxy] * px * psin2 + my[indmaxy] * py * pcos2;
- //Get the width and height of the rotated image
- //width := aar_roundup(xres * 2);
- A := xres * 2;
- if Abs(A - trunc(A + 0.0000000005)) < 0.000000001 then
- width := trunc(A + 0.0000000005)
- else
- width := trunc(A + 1);
- //height := aar_roundup(yres * 2);
- A := yres * 2;
- if Abs(A - trunc(A + 0.0000000005)) < 0.000000001 then
- height := trunc(A + 0.0000000005)
- else
- height := trunc(A + 1);
- cx := (width - srcbmp.bmWidth) div 2;
- cy := (height - srcbmp.bmHeight) div 2;
- //Create the source dib array and the destdib array
- SetLength(srcdib, srcbmp.bmWidth * srcbmp.bmHeight);
- SetLength(dstdib, width * height);
- //Load source bits into srcdib
- srcdibbmap.bmiHeader.biSize := sizeof(srcdibbmap.bmiHeader);
- srcdibbmap.bmiHeader.biWidth := srcbmp.bmWidth;
- srcdibbmap.bmiHeader.biHeight := -srcbmp.bmHeight;
- srcdibbmap.bmiHeader.biPlanes := 1;
- srcdibbmap.bmiHeader.biBitCount := 32;
- srcdibbmap.bmiHeader.biCompression := BI_RGB;
- ldc := CreateCompatibleDC(0);
- GetDIBits(ldc, src, 0, srcbmp.bmHeight, srcdib, srcdibbmap, DIB_RGB_COLORS);
- DeleteDC(ldc);
- backcolor.rgbRed := bgcolor and $000000FF;
- backcolor.rgbGreen := (bgcolor and $0000FF00) div $00000100;
- backcolor.rgbBlue := (bgcolor and $00FF0000) div $00010000;
- TR := backcolor.rgbRed;
- TG := backcolor.rgbGreen;
- TB := backcolor.rgbBlue;
- // Surpress AutoBlend option if transparent is true;
- if transparent then autoblend_ := false else autoblend_ := autoblend;
- for XX := -cx to (width - cx - 1) do // for destination's width
- begin
- for YY := -cy to (height - cy - 1) do // for destination's height
- begin
- // Get the rotation translation (gives the SourceImage coordinate for each DestImage x,y)
- tx := (XX - px) * PCos - (YY - py) * pSin + px;
- ty := (XX - px) * pSin + (YY - py) * PCos + py;
- // Get nearest to the left pixel
- if (tx > -1) and (tx < 0) then // Consider just outer border
- ix := -1
- else
- ix := trunc(tx);
- if (ty > -1) and (ty < 0) then // Consider just outer border
- iy := -1
- else
- iy := trunc(ty);
- // Get the digits after the decimal point
- dx := Abs(tx - ix);
- dy := Abs(ty - iy);
- DstIndex := XX + cx + (YY + cy) * Width;
- SrcIndex := ix + iy * srcbmp.bmWidth;
- if (tx > -1) and (ix + 1 <= srcbmp.bmWidth) and
- (ty > -1) and (iy + 1 <= srcbmp.bmHeight) then
- begin
- // The SourcePixel color maybe a combination of upto four pixels as tx and ty
- // are not integers.
- // The intersepted (by the current calculated source pixel) area each pixel
- // involved (see .doc for more info)
- TopL := (1 - dx) * (1 - dy);
- TopR := dx * (1 - dy);
- BotL := (1 - dx) * dy;
- BotR := dx * dy;
- // The sum of (TopL + TopR + BotL + BotR) is always 1
- if (tx >= 0) and (ix + 1 < srcbmp.bmWidth) and
- (ty >= 0) and (iy + 1 < srcbmp.bmHeight) then
- begin
- // All the intersepted areas are placed within srcbmp region
- // Antialiasing: DestColor = SourceTopLeftPixel * TopLeftAreaIntersectedBySourcePixel
- // + SourceTopRightPixel * TopRightAreaIntersectedBySourcePixel
- // + bottomleft... + bottomrigth...
- if not transparent then
- begin
- dstdib[DstIndex].rgbRed := byterange(srcdib[SrcIndex].rgbRed * TopL
- + srcdib[SrcIndex+1].rgbRed * TopR
- + srcdib[SrcIndex+srcbmp.bmWidth].rgbRed * BotL
- + srcdib[SrcIndex+srcbmp.bmWidth+1].rgbRed * BotR);
- dstdib[DstIndex].rgbBlue := byterange(srcdib[SrcIndex].rgbBlue * TopL
- + srcdib[SrcIndex+1].rgbBlue * TopR
- + srcdib[SrcIndex+srcbmp.bmWidth].rgbBlue * BotL
- + srcdib[SrcIndex+srcbmp.bmWidth+1].rgbBlue * BotR);
- dstdib[DstIndex].rgbGreen := byterange(srcdib[SrcIndex].rgbGreen * TopL
- + srcdib[SrcIndex+1].rgbGreen * TopR
- + srcdib[SrcIndex+srcbmp.bmWidth].rgbGreen * BotL
- + srcdib[SrcIndex+srcbmp.bmWidth+1].rgbGreen * BotR);
- if use_src_alpha then
- dstdib[DstIndex].rgbReserved
- := byterange(srcdib[SrcIndex].rgbReserved * TopL
- + srcdib[SrcIndex+1].rgbReserved * TopR
- + srcdib[SrcIndex+srcbmp.bmWidth].rgbReserved * BotL
- + srcdib[SrcIndex+srcbmp.bmWidth+1].rgbReserved * BotR)
- else
- dstdib[DstIndex].rgbReserved := 255; // alpha value for future use
- end else
- begin // if transparent
- RAlpha := 0;
- TopL_B := true;
- TopR_B := true;
- BotL_B := true;
- BotR_B := true;
- dstdib[DstIndex].rgbRed := 0;
- dstdib[DstIndex].rgbBlue := 0;
- dstdib[DstIndex].rgbGreen := 0;
- if (srcdib[SrcIndex].rgbRed <> TR) or
- (srcdib[SrcIndex].rgbBlue <> TB) or
- (srcdib[SrcIndex].rgbGreen <> TG) then
- begin
- if use_src_alpha then
- RAlpha := TopL * srcdib[SrcIndex].rgbReserved / 255
- else
- RAlpha := TopL;
- TopL_B := false;
- dstdib[DstIndex].rgbRed := byterange(srcdib[SrcIndex].rgbRed * TopL);
- dstdib[DstIndex].rgbBlue := byterange(srcdib[SrcIndex].rgbBlue * TopL);
- dstdib[DstIndex].rgbGreen := byterange(srcdib[SrcIndex].rgbGreen * TopL);
- end;
- if TopR <> 0 then
- if (srcdib[SrcIndex+1].rgbRed <> TR) or (srcdib[SrcIndex+1].rgbBlue <> TB) or
- (srcdib[SrcIndex+1].rgbGreen <> TG) then
- begin
- if use_src_alpha then
- RAlpha := RAlpha + TopR * srcdib[SrcIndex+1].rgbReserved / 255
- else
- RAlpha := RAlpha + TopR;
- TopR_B := false;
- dstdib[DstIndex].rgbRed := dstdib[DstIndex].rgbRed
- + byterange(srcdib[SrcIndex+1].rgbRed * TopR);
- dstdib[DstIndex].rgbBlue := dstdib[DstIndex].rgbBlue
- + byterange(srcdib[SrcIndex+1].rgbBlue * TopR);
- dstdib[DstIndex].rgbGreen := dstdib[DstIndex].rgbGreen
- + byterange(srcdib[SrcIndex+1].rgbGreen * TopR);
- end;
- if BotL <> 0 then
- if (srcdib[SrcIndex+srcbmp.bmWidth].rgbRed <> TR) or
- (srcdib[SrcIndex+srcbmp.bmWidth].rgbBlue <> TB) or
- (srcdib[SrcIndex+srcbmp.bmWidth].rgbGreen <> TG) then
- begin
- if use_src_alpha then
- RAlpha := RAlpha + BotL * srcdib[SrcIndex+srcbmp.bmWidth].rgbReserved / 255
- else
- RAlpha := RAlpha + BotL;
- BotL_B := false;
- dstdib[DstIndex].rgbRed := dstdib[DstIndex].rgbRed
- + byterange(srcdib[SrcIndex+srcbmp.bmWidth].rgbRed * BotL);
- dstdib[DstIndex].rgbBlue := dstdib[DstIndex].rgbBlue
- + byterange(srcdib[SrcIndex+srcbmp.bmWidth].rgbBlue * BotL);
- dstdib[DstIndex].rgbGreen := dstdib[DstIndex].rgbGreen
- + byterange(srcdib[SrcIndex+srcbmp.bmWidth].rgbGreen * BotL);
- end;
- if BotR <> 0 then
- if (srcdib[SrcIndex+srcbmp.bmWidth+1].rgbRed <> TR) or
- (srcdib[SrcIndex+srcbmp.bmWidth+1].rgbBlue <> TB) or
- (srcdib[SrcIndex+srcbmp.bmWidth+1].rgbGreen <> TG) then
- begin
- if use_src_alpha then
- RAlpha := RAlpha + BotR * srcdib[SrcIndex+srcbmp.bmWidth+1].rgbReserved / 255
- else
- RAlpha := RAlpha + BotR;
- BotR_B := false;
- dstdib[DstIndex].rgbRed := byterange(dstdib[DstIndex].rgbRed
- + srcdib[SrcIndex+srcbmp.bmWidth+1].rgbRed * BotR);
- dstdib[DstIndex].rgbBlue := byterange(dstdib[DstIndex].rgbBlue
- + srcdib[SrcIndex+srcbmp.bmWidth+1].rgbBlue * BotR);
- dstdib[DstIndex].rgbGreen := byterange(dstdib[DstIndex].rgbGreen
- + srcdib[SrcIndex+srcbmp.bmWidth+1].rgbGreen * BotR);
- end;
- // InRegionRatio gets the ratio of the non-transparent area
- // + 0.0001 : Put to avoid floating point exception by huge number.
- InRegionRatio := 1 - (TopL * ord(TopL_B) + TopR * ord(TopR_B)
- + BotR * ord(BotR_B) + BotL * ord(BotL_B)) + 0.0001;
- dstdib[DstIndex].rgbRed := byterange(dstdib[DstIndex].rgbRed / InRegionRatio);
- dstdib[DstIndex].rgbBlue := byterange(dstdib[DstIndex].rgbBlue / InRegionRatio);
- dstdib[DstIndex].rgbGreen := byterange(dstdib[DstIndex].rgbGreen / InRegionRatio);
- dstdib[DstIndex].rgbReserved := byterange(RAlpha * 255);
- end;
- end else
- begin
- // Some elements of the intersepted areas are placed out of srcbmp region.
- // For the intersepted areas which are placed out of srcbmp region,
- // - Transparent is false AND AutoBlend is true : add background color
- // - Transparent is true OR AutoBlend is false : do nothing
- // Determine the elements which are placed out of srcbmp region.
- TopL_B := false; TopR_B := false; BotL_B := false; BotR_B := false;
- if tx < 0 then begin TopL_B := true; BotL_B := true; end;
- if ty < 0 then begin TopL_B := true; TopR_B := true; end;
- if ix = (srcbmp.bmWidth - 1) then begin TopR_B := true; BotR_B := true; end;
- if iy = (srcbmp.bmHeight - 1) then begin BotL_B := true; BotR_B := true; end;
- RAlpha := 0;
- Dst_rgbRed := 0;
- Dst_rgbBlue := 0;
- Dst_rgbGreen := 0;
-
- if TopL_B then // if Top-Left element is out of srcbmp region
- begin
- if autoblend_ then
- begin
- Dst_rgbRed := backcolor.rgbRed * TopL;
- Dst_rgbBlue := backcolor.rgbBlue * TopL;
- Dst_rgbGreen := backcolor.rgbGreen * TopL;
- end;
- end else begin // Top-Left element is within srcbmp region
- if not transparent then
- begin
- Dst_rgbRed := srcdib[SrcIndex].rgbRed * TopL;
- Dst_rgbBlue := srcdib[SrcIndex].rgbBlue * TopL;
- Dst_rgbGreen := srcdib[SrcIndex].rgbGreen * TopL;
- if use_src_alpha then
- RAlpha := TopL * srcdib[SrcIndex].rgbReserved / 255
- else
- RAlpha := TopL;
- end else
- begin // if transparent then
- if (srcdib[SrcIndex].rgbRed <> TR) or (srcdib[SrcIndex].rgbBlue <> TB) or
- (srcdib[SrcIndex].rgbGreen <> TG) then
- begin
- Dst_rgbRed := srcdib[SrcIndex].rgbRed * TopL;
- Dst_rgbBlue := srcdib[SrcIndex].rgbBlue * TopL;
- Dst_rgbGreen := srcdib[SrcIndex].rgbGreen * TopL;
- if use_src_alpha then
- RAlpha := TopL * srcdib[SrcIndex].rgbReserved / 255
- else
- RAlpha := TopL;
- end;
- end;
- end;
- if TopR_B then // if Top-Right element is out of srcbmp region
- begin
- if autoblend_ then
- begin
- Dst_rgbRed := Dst_rgbRed + backcolor.rgbRed * TopR;
- Dst_rgbBlue := Dst_rgbBlue + backcolor.rgbBlue * TopR;
- Dst_rgbGreen := Dst_rgbGreen + backcolor.rgbGreen * TopR;
- end;
- end else begin // Top-Right element is within srcbmp region
- if not transparent then
- begin
- Dst_rgbRed := Dst_rgbRed + srcdib[SrcIndex+1].rgbRed * TopR;
- Dst_rgbBlue := Dst_rgbBlue + srcdib[SrcIndex+1].rgbBlue * TopR;
- Dst_rgbGreen := Dst_rgbGreen + srcdib[SrcIndex+1].rgbGreen * TopR;
- if use_src_alpha then
- RAlpha := RAlpha + TopR * srcdib[SrcIndex+1].rgbReserved / 255
- else
- RAlpha := RAlpha + TopR;
- end else
- begin // if transparent then
- if (srcdib[SrcIndex+1].rgbRed <> TR) or (srcdib[SrcIndex+1].rgbBlue <> TB) or
- (srcdib[SrcIndex+1].rgbGreen <> TG) then
- begin
- Dst_rgbRed := Dst_rgbRed + srcdib[SrcIndex+1].rgbRed * TopR;
- Dst_rgbBlue := Dst_rgbBlue + srcdib[SrcIndex+1].rgbBlue * TopR;
- Dst_rgbGreen := Dst_rgbGreen + srcdib[SrcIndex+1].rgbGreen * TopR;
- if use_src_alpha then
- RAlpha := RAlpha + TopR * srcdib[SrcIndex+1].rgbReserved / 255
- else
- RAlpha := RAlpha + TopR;
- end;
- end;
- end;
- if BotL_B then // if Bottom-Left element is out of srcbmp region
- begin
- if autoblend_ then
- begin
- Dst_rgbRed := Dst_rgbRed + backcolor.rgbRed * BotL;
- Dst_rgbBlue := Dst_rgbBlue + backcolor.rgbBlue * BotL;
- Dst_rgbGreen := Dst_rgbGreen + backcolor.rgbGreen * BotL;
- end;
- end else begin // Bottom-Left element is within srcbmp region
- if not transparent then
- begin
- Dst_rgbRed := Dst_rgbRed + srcdib[SrcIndex+srcbmp.bmWidth].rgbRed * BotL;
- Dst_rgbBlue := Dst_rgbBlue + srcdib[SrcIndex+srcbmp.bmWidth].rgbBlue * BotL;
- Dst_rgbGreen := Dst_rgbGreen + srcdib[SrcIndex+srcbmp.bmWidth].rgbGreen * BotL;
- if use_src_alpha then
- RAlpha := RAlpha + BotL * srcdib[SrcIndex+srcbmp.bmWidth].rgbReserved / 255
- else
- RAlpha := RAlpha + BotL;
- end else
- begin // if transparent then
- if (srcdib[SrcIndex+srcbmp.bmWidth].rgbRed <> TR) or
- (srcdib[SrcIndex+srcbmp.bmWidth].rgbBlue <> TB) or
- (srcdib[SrcIndex+srcbmp.bmWidth].rgbGreen <> TG) then
- begin
- Dst_rgbRed := Dst_rgbRed + srcdib[SrcIndex+srcbmp.bmWidth].rgbRed * BotL;
- Dst_rgbBlue := Dst_rgbBlue + srcdib[SrcIndex+srcbmp.bmWidth].rgbBlue * BotL;
- Dst_rgbGreen := Dst_rgbGreen + srcdib[SrcIndex+srcbmp.bmWidth].rgbGreen * BotL;
- if use_src_alpha then
- RAlpha := RAlpha + BotL * srcdib[SrcIndex+srcbmp.bmWidth].rgbReserved / 255
- else
- RAlpha := RAlpha + BotL;
- end;
- end;
- end;
- if BotR_B then // if Bottom-Right element is out of srcbmp region
- begin
- if autoblend_ then
- begin
- Dst_rgbRed := Dst_rgbRed + backcolor.rgbRed * BotR;
- Dst_rgbBlue := Dst_rgbBlue + backcolor.rgbBlue * BotR;
- Dst_rgbGreen := Dst_rgbGreen + backcolor.rgbGreen * BotR;
- end;
- end else begin // Bottom-Right element is within srcbmp region
- if not transparent then
- begin
- Dst_rgbRed := Dst_rgbRed + srcdib[SrcIndex+srcbmp.bmWidth+1].rgbRed * BotR;
- Dst_rgbBlue := Dst_rgbBlue + srcdib[SrcIndex+srcbmp.bmWidth+1].rgbBlue * BotR;
- Dst_rgbGreen := Dst_rgbGreen + srcdib[SrcIndex+srcbmp.bmWidth+1].rgbGreen * BotR;
- if use_src_alpha then
- RAlpha := RAlpha + BotR * srcdib[SrcIndex+srcbmp.bmWidth+1].rgbReserved / 255
- else
- RAlpha := RAlpha + BotR;
- end else
- begin // if transparent then
- if (srcdib[SrcIndex+srcbmp.bmWidth+1].rgbRed <> TR) or
- (srcdib[SrcIndex+srcbmp.bmWidth+1].rgbBlue <> TB) or
- (srcdib[SrcIndex+srcbmp.bmWidth+1].rgbGreen <> TG) then
- begin
- Dst_rgbRed := Dst_rgbRed + srcdib[SrcIndex+srcbmp.bmWidth+1].rgbRed * BotR;
- Dst_rgbBlue := Dst_rgbBlue + srcdib[SrcIndex+srcbmp.bmWidth+1].rgbBlue * BotR;
- Dst_rgbGreen := Dst_rgbGreen + srcdib[SrcIndex+srcbmp.bmWidth+1].rgbGreen * BotR;
- if use_src_alpha then
- RAlpha := RAlpha + BotR * srcdib[SrcIndex+srcbmp.bmWidth+1].rgbReserved / 255
- else
- RAlpha := RAlpha + BotR;
- end;
- end;
- end;
- if transparent then begin
- // InRegionRatio gets the ratio of the area within srcbmp region.
- // + 0.0001 : Put to avoid floating point exception by huge number.
- InRegionRatio := 1 - (TopL * ord(TopL_B) + TopR * ord(TopR_B)
- + BotR * ord(BotR_B) + BotL * ord(BotL_B)) + 0.0001;
- dstdib[DstIndex].rgbRed := byterange(Dst_rgbRed / InRegionRatio);
- dstdib[DstIndex].rgbBlue := byterange(Dst_rgbBlue / InRegionRatio);
- dstdib[DstIndex].rgbGreen := byterange(Dst_rgbGreen / InRegionRatio);
- end else begin
- dstdib[DstIndex].rgbRed := byterange(Dst_rgbRed);
- dstdib[DstIndex].rgbBlue := byterange(Dst_rgbBlue);
- dstdib[DstIndex].rgbGreen := byterange(Dst_rgbGreen);
- end;
- // Set alpha value for future use
- if autoblend_ then
- dstdib[DstIndex].rgbReserved := 255
- else
- dstdib[DstIndex].rgbReserved := byterange(RAlpha * 255);
- { else if transparent then
- begin
- dstdib[DstIndex].rgbReserved := byterange(RAlpha * 255);
- end else begin
- Alpha := byterange((1 - (TopL * integer(TopL_B)
- + TopR * integer(TopR_B)
- + BotR * integer(BotR_B)
- + BotL * integer(BotL_B))) * 255);
- dstdib[DstIndex].rgbReserved := Alpha;
- end; }
- end;
- end else
- begin
- // for entirely out of srcbmp region
- // Color the destination with the background color, if (not transparent).
- if (not transparent) then
- begin
- dstdib[DstIndex].rgbRed := backcolor.rgbRed;
- dstdib[DstIndex].rgbBlue := backcolor.rgbBlue;
- dstdib[DstIndex].rgbGreen := backcolor.rgbGreen;
- end;
- dstdib[DstIndex].rgbReserved := 0; // alpha value for future use
- end;
- end; // for YY
- end; // for XX
- SetLength(srcdib, 0);
- //Get Current Display Settings
- screenmode.dmSize := sizeof(DEVMODE);
- EnumDisplaySettings(nil, $FFFFFFFF{ENUM_CURRENT_SETTINGS}, screenmode);
- //Create the final bitmap object
- dstbmp := CreateBitmap(width, height, 1, screenmode.dmBitsPerPel, nil);
- //Write the bits into the bitmap and return it
- dstdibmap.bmiHeader.biSize := sizeof(dstdibmap.bmiHeader);
- dstdibmap.bmiHeader.biWidth := width;
- dstdibmap.bmiHeader.biHeight := -height;
- dstdibmap.bmiHeader.biPlanes := 1;
- dstdibmap.bmiHeader.biBitCount := 32;
- dstdibmap.bmiHeader.biCompression := BI_RGB;
- SetDIBits(0, dstbmp, 0, height, dstdib, dstdibmap, DIB_RGB_COLORS);
- SetLength(dstdib, 0);
- result := dstbmp;
- end;
- function FastAARotatedBitmap(SrcBitmap : TBitmap;
- Rotation : double;
- BgColor : integer;
- Transparent,
- ApplySrcAlpha,
- AutoBlend : boolean;
- Scale : double) : TBitmap;
- var
- res : HBITMAP;
- mult : integer;
- //MinScale : double;
- UseAlphaChannel : boolean;
- begin
- if SrcBitmap.Empty then
- begin
- result := nil;
- exit;
- end;
- if SrcBitmap.PixelFormat = pf24bit then
- UseAlphaChannel := false
- else if SrcBitmap.PixelFormat = pf32bit then
- UseAlphaChannel := ApplySrcAlpha
- else begin
- result := nil;
- exit;
- end;
- //Get rotation between (0, 360)
- mult := trunc(Rotation / 360);
- if (Rotation >= 0) then
- Rotation := Rotation - 360.0 * mult
- else
- Rotation := Rotation - 360.0 * (mult - 1);
- //Limit the scaled image is not lesser than 5 pixel in height or width
- {
- if (SrcBitmap.Height <= 5) or (SrcBitmap.Width <= 5) then
- MinScale := 1
- else if SrcBitmap.Height > SrcBitmap.Width then
- MinScale := 5 / SrcBitmap.Width
- else
- MinScale := 5 / SrcBitmap.Height;
- //Get scale between (0.1, 10.0)
- if Scale < MinScale then
- Scale := MinScale;
- if Scale < 0.1 then
- Scale := 0.1
- else if Scale > 10.0 then
- Scale := 10.0;
- }
- res := dorotate(SrcBitmap.Handle, Rotation, BgColor, Transparent, UseAlphaChannel, AutoBlend, Scale);
- if res <> 0 then
- begin
- try
- Result := TBitmap.Create;
- Result.PixelFormat := pf32bit;
- Result.Handle := res;
- except
- Result := nil;
- end;
- end else
- Result := nil;
- end;
- end.
|