Mega Code Archive

 
Categories / Delphi / Graphic
 

Manipulate Bitmaps in a self contained static class

Title: Manipulate Bitmaps in a self contained static class Question: Static class for TBitmap manipulation. No need to create class as it is STATIC. eg. Bitmaps.Grayscale(MyBitmap). Easy to use with JPG and other formats, simply convert to TBitmap, call class function and convert the TBitmap back to original format. Answer: unit MW_Bitmaps; interface {$REGION 'Documentation'} // ================================================================================================= // UltraRAD Components // Mike Heydon // // Bitmaps - Class of static bitmap functions. All calls are callable from // the class itself and no instance of the class needs to be instantiated or // freed. Attempting to create an instance of the class will generate runtime // error. // // ================================================================================================= {$ENDREGION} uses Windows, SysUtils, Graphics; {$REGION 'Types and Classes'} type {Bitmaps Class} Bitmaps = class(TObject) strict private const C_VERSION = '1.0.1'; strict private class function IntToByte(AInteger : integer) : byte; class function ColorToTriple(AColor : TColor) : TRGBTriple; public constructor Create; class function Version : string; class procedure Blur(ABitmap : TBitmap); class procedure ChangeRGB(ABitmap : TBitmap; AIncRed,AIncGreen,AIncBlue : byte); class procedure ColorNoise(ABitmap : TBitmap; AAmount : integer = 100); class procedure Contrast(ABitmap : TBitmap; APercent : integer = 50); class procedure Darken(ABitmap : TBitmap; APercent : integer = 50); class procedure Emboss(ABitmap : TBitmap; ADepth : byte = 1); class procedure Flaxen(ABitmap : TBitmap); class procedure FlipHorizontal(ABitmap : TBitmap); class procedure FlipVertical(ABitmap : TBitmap); class procedure GrayScale(ABitmap : TBitmap); class procedure Lighten(ABitmap : TBitmap; APercent : byte = 50); class procedure MonoNegative(ABitmap : TBitmap); class procedure MonoNoise(ABitmap : TBitmap; AAmount : integer = 100); class procedure Mosaic(ABitmap : TBitmap; ASize : integer = 5); class procedure Negative(ABitmap : TBitmap); class procedure Posterize(ABitmap: TBitmap; AAmount : integer = 255); class procedure Saturation(ABitmap : TBitmap; APercent : integer = 90); class procedure Sepia(ABitmap : TBitmap; APercentDark : byte = 90); class procedure Twotone(ABitmap : TBitmap ; const ALightColor, ADarkColor : TColor; APercent : integer = 50); end; {$ENDREGION} // ------------------------------------------------------------------------------------------------- implementation {$REGION 'Bitmaps Class'} // ============================================================================= // Generate a runtime error if an attempt is made to create an instance // of the class // ============================================================================= constructor Bitmaps.Create; begin raise Exception.Create('Bitmaps.Create - Cannot create an instance, ' + 'class contains static functions only. ' + 'Usage Example : Bitmaps.Grayscale(MyBitmap)'); end; // ============================================================================= // Retrieve the class version as defined by C_VERSION // ============================================================================= class function Bitmaps.Version : string; begin Result := C_VERSION; end; class function Bitmaps.IntToByte(AInteger : integer) : byte; var iResult : byte; begin if AInteger 255 then iResult := 255 else if AInteger 0 then iResult := 0 else iResult := AInteger; Result := iResult; end; class function Bitmaps.ColorToTriple(AColor : TColor) : TRGBTriple; type TRGBStruc = record case TColor of 1 : (ColorValue: TColor); 2 : (Bytes: array [0..3] of Byte); end; var rCol : TRGBStruc; begin rCol.ColorValue := AColor; Result.rgbtRed := rCol.Bytes[0]; Result.rgbtGreen := rCol.Bytes[1]; Result.rgbtBlue := rCol.Bytes[2]; end ; // ============================================================================= // Change RGB to New in Bitmap // Increment or Decrememt the RGB colors by values. // ============================================================================= class procedure Bitmaps.ChangeRGB(ABitmap : TBitmap; AIncRed,AIncGreen,AIncBlue : byte); var iCol,iRow : integer; pRow : ^TRGBTriple; begin ABitmap.PixelFormat := pf24bit; for iRow := 0 to ABitmap.Height - 1 do begin pRow := ABitmap.ScanLine[iRow]; for iCol := 0 to ABitmap.Width -1 do begin pRow^.rgbtBlue := self.IntToByte(AIncBlue + pRow^.rgbtBlue); pRow^.rgbtGreen := self.IntToByte(AIncGreen + pRow^.rgbtGreen); pRow^.rgbtRed := self.IntToByte(AIncRed + pRow^.rgbtRed); inc(pRow); end; end; end; // ============================================================================= // Flaxen the Bitmap // ============================================================================= class procedure Bitmaps.Flaxen(ABitmap : TBitmap); var iCol,iRow : integer; pWsk1,pWsk2,pWsk3 : ^TRGBTriple; begin ABitmap.PixelFormat := pf24bit; for iRow := 0 to ABitmap.Height - 1 do begin pWsk1 := ABitmap.ScanLine[iRow]; pWsk2 := pWsk1; pWsk3 := pWsk1; inc(pWsk2); inc(pWsk3,2); for iCol := 0 to ABitmap.Width - 1 do begin pWsk1^.rgbtRed := (pWsk1^.rgbtRed + pWsk2^.rgbtGreen + pWsk3^.rgbtBlue) div 3; pWsk2^.rgbtGreen := (pWsk1^.rgbtGreen + pWsk2^.rgbtGreen + pWsk3^.rgbtBlue) div 3; pWsk2^.rgbtBlue := (pWsk1^.rgbtBlue + pWsk2^.rgbtGreen + pWsk3^.rgbtBlue) div 3; inc(pWsk1); inc(pWsk2); inc(pWsk3); end; end; end; // ============================================================================= // Add Colored Noise Speckle // ============================================================================= class procedure Bitmaps.ColorNoise(ABitmap : TBitmap; AAmount : integer = 100); var pWsk : ^byte; iCol,iRow : integer; begin ABitmap.PixelFormat := pf24bit; for iRow := 0 to ABitmap.Height - 1 do begin pWsk := ABitmap.ScanLine[iRow]; for iCol := 0 to ABitmap.Width * 3 - 1 do begin pWsk^ := self.IntToByte(pWsk^ + (Random(AAmount) - (AAmount shr 1))); inc(pWsk); end; end; end; // ============================================================================= // Change to Gray Scale // ============================================================================= class procedure Bitmaps.GrayScale(ABitmap : TBitmap); var pRow : ^TRGBTriple; iCol,iRow,iIndex : integer; begin ABitmap.PixelFormat := pf24bit; for iRow := 0 to ABitmap.Height - 1 do begin pRow := ABitmap.ScanLine[iRow]; for iCol := 0 to ABitmap.Width - 1 do begin iIndex := ((pRow^.rgbtRed * 77 + pRow^.rgbtGreen * 150 + pRow^.rgbtBlue * 29) shr 8); pRow^.rgbtBlue := iIndex; pRow^.rgbtGreen := iIndex; pRow^.rgbtRed := iIndex; inc(pRow); end; end; end; // ============================================================================= // Change Bitmap to Sepia // ============================================================================= class procedure Bitmaps.Sepia(ABitmap : TBitmap; APercentDark : byte = 90); var iDepth : byte; pRow : ^TRGBTriple; iCol,iRow : Integer; begin if APercentDark = 100 then iDepth := 0 else iDepth := 255 - trunc((APercentDark / 100.0) * 255.0); ABitmap.PixelFormat:=pf24bit; for iRow := 0 to ABitmap.Height - 1 do begin pRow := ABitmap.ScanLine[iRow]; for iCol := 0 to ABitmap.Width -1 do begin pRow^.rgbtBlue :=(pRow^.rgbtBlue + pRow^.rgbtGreen + pRow^.rgbtRed) div 3; pRow^.rgbtGreen := pRow^.rgbtBlue; pRow^.rgbtRed := pRow^.rgbtBlue; inc(pRow^.rgbtRed,iDepth * 2); inc(pRow^.rgbtGreen,iDepth); if pRow^.rgbtRed (iDepth * 2) then pRow^.rgbtRed := 255; if pRow^.rgbtGreen iDepth then pRow^.rgbtGreen := 255; inc(pRow); end; end; end; // ============================================================================= // Posterize a Bitmap // ============================================================================= class procedure Bitmaps.Posterize(ABitmap: TBitmap; AAmount: integer = 255); var iCol,iRow : integer; pWsk : ^byte; begin ABitmap.PixelFormat := pf24bit; if AAmount 0 then AAmount := 1; for iRow := 0 to ABitmap.Height - 1 do begin pWsk := ABitmap.Scanline[iRow]; for iCol := 0 to ABitmap.Width * 3 - 1 do begin pWsk^ := self.IntToByte(round(pWsk^ / AAmount) * AAmount); inc(pWsk); end; end; end; // ============================================================================= // Emboss a Bitmap // ============================================================================= class procedure Bitmaps.Emboss(ABitmap : TBitmap; ADepth : byte = 1); var x, y, i : integer; p1, p2: PByteArray; begin if ADepth 10 then aDepth := 10; if ADepth = 0 then ADepth := 1; ABitmap.PixelFormat := pf24bit; for i := 0 to ADepth do begin for y := 0 to ABitmap.Height - 2 do begin p1 := ABitmap.ScanLine[y]; p2 := ABitmap.ScanLine[y+1]; for x := 0 to ABitmap.Width do begin p1[x * 3] := (p1[x * 3] + (p2[(x + 3) * 3] xor $FF)) shr 1; p1[x * 3 + 1] := (p1[x * 3 + 1] + (p2[(x + 3) * 3 + 1] xor $FF)) shr 1; p1[x * 3 + 2] := (p1[x * 3 + 1] + (p2[(x + 3) * 3 + 1] xor $FF)) shr 1; end; end; end; end; // ============================================================================= // Add Mono Noise to Bitmap // ============================================================================= class procedure Bitmaps.MonoNoise(ABitmap : TBitmap; AAmount: integer = 100); var pRow : ^TRGBTriple; iCol,iRow,iNoise : integer; begin ABitmap.PixelFormat := pf24bit; for iRow := 0 to ABitmap.Height - 1 do begin pRow := ABitmap.ScanLine[iRow]; for iCol := 0 to ABitmap.Width - 1 do begin iNoise := Random(AAmount) - (AAmount shr 1); pRow^.rgbtBlue :=self.IntToByte(pRow^.rgbtBlue + iNoise); pRow^.rgbtGreen :=self.IntToByte(pRow^.rgbtGreen + iNoise); pRow^.rgbtRed :=self.IntToByte(pRow^.rgbtRed + iNoise); inc(pRow); end; end; end; // ============================================================================= // Blur a Bitmap // ============================================================================= class procedure Bitmaps.Blur(ABitmap : TBitmap); var pTL,pTC,pTR,pBL, pBC,pBR,pLL,pLC,pLR : ^TRGBTriple; iCol,iRow : integer; begin ABitmap.PixelFormat := pf24bit; for iRow := 1 to ABitmap.Height - 2 do begin pTL := ABitmap.ScanLine[iRow - 1]; pTC := pTL; pTR := pTL; pBL := ABitmap.ScanLine[iRow]; pBC := pBL; pBR := pBL; pLL := ABitmap.ScanLine[iRow + 1]; pLC := pLL; pLR := pLL; inc(pTC); inc(pTR,2); inc(pBC); inc(pBR,2); inc(pLC); inc(pLR,2); for iCol := 1 to (ABitmap.Width - 2) do begin pBC^.rgbtRed:= (pBC^.rgbtRed + pBL^.rgbtRed + pBR^.rgbtRed + pTC^.rgbtRed + pTL^.rgbtRed + pTR^.rgbtRed + pLL^.rgbtRed + pLC^.rgbtRed + pLR^.rgbtRed) div 9 ; pBC^.rgbtGreen:=(pBC^.rgbtGreen + pBL^.rgbtGreen + pBR^.rgbtGreen + pTC^.rgbtGreen + pTL^.rgbtGreen + pTR^.rgbtGreen + pLL^.rgbtGreen + pLC^.rgbtGreen + pLR^.rgbtGreen) div 9 ; pBC^.rgbtBlue:=(pBC^.rgbtBlue + pBL^.rgbtBlue + pBR^.rgbtBlue + pTC^.rgbtBlue + pTL^.rgbtBlue + pTR^.rgbtBlue + pLL^.rgbtBlue + pLC^.rgbtBlue + pLR^.rgbtBlue ) div 9 ; inc(pTL); inc(pTC); inc(pTR); inc(pBL); inc(pBC); inc(pBR); inc(pLL); inc(pLC); inc(pLR); end; end; end; // ============================================================================= // Mosaic // ============================================================================= class procedure Bitmaps.Mosaic(ABitmap : TBitmap ; ASize : integer = 5); var x,y,i,j : integer; p1,p2 : pByteArray; r,g,b : byte; begin if ASize 20 then ASize := 20; if ASize 2 then ASize := 2; ABitmap.PixelFormat := pf24bit; y := 0; repeat p1:= ABitMap.Scanline[y]; repeat j := 1; repeat p2 := ABitMap.Scanline[y]; x := 0; repeat r := p1[x * 3]; g := p1[x * 3 + 1]; b := p1[x * 3 + 2]; i :=1; repeat p2[x * 3]:=r; p2[x * 3 + 1] := g; p2[x * 3 + 2] := b; inc(x); inc(i); until (x = ABitMap.Width) or (i ASize); until x = ABitMap.Width; inc(j); inc(y); until (y = ABitMap.Height) or (j ASize); until (y = ABitMap.Height) or (x = ABitMap.Width); until y = ABitMap.Height; end; // ============================================================================= // Lighten Bitmap // ============================================================================= class procedure Bitmaps.Lighten(ABitmap : TBitmap; APercent : byte = 50); var pWsk : ^byte; iCol,iRow,iAmount : integer; begin if APercent = 100 then iAmount := 255 else iAmount := trunc((APercent / 100.0) * 255); ABitmap.PixelFormat := Graphics.pf24bit; for iRow := 0 to ABitmap.Height - 1 do begin pWsk := ABitmap.ScanLine[iRow]; for iCol := 0 to ABitmap.Width * 3 - 1 do begin pWsk^ := self.IntToByte(pWsk^ + ((255 - pWsk^) * iAmount) div 255); inc(pWsk); end; end; end; // ============================================================================= // Darken Bitmap // ============================================================================= class procedure Bitmaps.Darken(ABitmap : TBitmap; APercent : integer = 50); var pWsk : ^byte; iCol,iRow,iAmount : integer; begin if APercent = 100 then iAmount := 255 else iAmount := trunc((APercent / 100.0) * 255); ABitmap.Pixelformat := pf24bit; for iRow := 0 to ABitmap.Height - 1 do begin pWsk := ABitmap.ScanLine[iRow]; for iCol := 0 to ABitmap.Width * 3 - 1 do begin pWsk^ := self.IntToByte(pWsk^ - (pWsk^ * iAmount) div 255); inc(pWsk); end; end; end; // ============================================================================= // Twotone a bitmap into Light and Dark with Threshold Percent // ============================================================================= class procedure Bitmaps.Twotone(ABitmap : TBitmap ; const ALightColor, ADarkColor : TColor; APercent : integer = 50); var pRow : ^TRGBTriple; rLight,rDark : TRGBTriple; iCol,iRow,iIndex,iAmount : integer; begin rLight := self.ColorToTriple(ALightColor); rDark := self.ColorToTriple(ADarkColor); if APercent = 100 then iAmount := 255 else iAmount := trunc((APercent / 100.0) * 255); ABitmap.PixelFormat := pf24bit; for iRow := 0 to ABitmap.Height - 1 do begin pRow := ABitmap.ScanLine[iRow]; for iCol := 0 to ABitmap.Width -1 do begin iIndex := ((pRow^.rgbtRed * 77 + pRow^.rgbtGreen * 150 + pRow^.rgbtBlue * 29) shr 8); if iIndex iAmount then pRow^ := rLight else pRow^ := rDark; inc(pRow); end; end; end; // ============================================================================= // Negative of a Bitmap // ============================================================================= class procedure Bitmaps.Negative(ABitmap : TBitmap); var iCol,iRow : integer; pWsk : ^byte; begin ABitmap.PixelFormat := pf24bit; for iRow := 0 to ABitmap.Height - 1 do begin pWsk := ABitmap.ScanLine[iRow]; for iCol := 0 to (ABitmap.Width * 3) - 1 do begin pWsk^ := not pWsk^; inc(pWsk); end; end; end; class procedure Bitmaps.MonoNegative(ABitmap : TBitmap); begin self.GrayScale(ABitMap); self.Negative(ABitMap); end; // ============================================================================= // Saturation // ============================================================================= class procedure Bitmaps.Saturation(ABitmap : TBitmap; APercent : integer = 90); var pWsk : ^TRGBTriple; iGray,iCol,iRow,iAmount : integer; begin ABitmap.PixelFormat := pf24bit; if APercent = 100 then iAmount := 255 else iAmount := trunc((APercent / 100.0) * 255); for iRow := 0 to ABitmap.Height-1 do begin pWsk := ABitmap.ScanLine[iRow]; for iCol := 0 to ABitmap.Width - 1 do begin iGray := (pWsk^.rgbtBlue + pWsk^.rgbtGreen + pWsk^.rgbtRed) div 3; pWsk^.rgbtRed := self.IntToByte(iGray + (((pWsk^.rgbtRed - iGray) * iAmount) div 255)); pWsk^.rgbtGreen := self.IntToByte(iGray + (((pWsk^.rgbtGreen - iGray) * iAmount) div 255)); pWsk^.rgbtBlue := self.IntToByte(iGray + (((pWsk^.rgbtBlue - iGray) * iAmount) div 255)); inc(pWsk); end; end; end; // ============================================================================= // Change contrast of Bitmap // ============================================================================= class procedure Bitmaps.Contrast(ABitmap : TBitmap; APercent : integer = 50); var pWsk : ^byte; iCol,iRow,iAmount : integer; begin if APercent = 100 then iAmount := 255 else iAmount := trunc((APercent / 100.0) * 255); ABitmap.PixelFormat := pf24bit; for iRow := 0 to ABitmap.Height - 1 do begin pWsk := ABitmap.ScanLine[iRow]; for iCol := 0 to ABitmap.Width * 3 -1 do begin if pWsk^ 127 then pWsk^ := self.IntToByte(pWsk^ + (abs(127 - pWsk^) * iAmount) div 255) else pWsk^ := self.IntToByte(pWsk^ - (abs(127 - pWsk^) * iAmount) div 255); inc(pWsk); end; end; end; // ============================================================================= // Flip Horizontal // ============================================================================= class procedure Bitmaps.FlipHorizontal(ABitmap : TBitmap); type TByteTriple = array [0..2] of byte; var pByteL,pByteR : ^TByteTriple; aByteTemp : TByteTriple; iCol,iRow : integer; begin ABitmap.PixelFormat:=pf24bit; for iRow :=0 to ABitmap.Height - 1 do begin pByteL := ABitmap.ScanLine[iRow]; pByteR := ABitmap.ScanLine[iRow]; inc(pByteR,ABitmap.Width - 1); for iCol := 0 to (ABitmap.Width -1) div 2 do begin aByteTemp := pByteL^; pByteL^ := pByteR^; pByteR^ := aByteTemp; inc(pByteL); dec(pByteR); end; end; end; // ============================================================================= // Flip Vertical // ============================================================================= class procedure Bitmaps.FlipVertical(ABitmap : TBitmap); var pByteTop,pByteBottom : ^byte; iByteTemp : byte; iCol,iRow : integer; begin ABitmap.PixelFormat:=pf24bit; for iRow := 0 to (ABitmap.Height - 1) div 2 do begin pByteTop := ABitmap.ScanLine[iRow]; pByteBottom := ABitmap.ScanLine[ABitmap.Height - 1 - iRow]; for iCol :=0 to ABitmap.Width * 3 - 1 do begin iByteTemp := pByteTop^; pByteTop^ := pByteBottom^; pByteBottom^ := iByteTemp; inc(pByteTop); inc(pByteBottom); end; end; end; {$ENDREGION} end.