Changeset 494 for GraphicTest/Packages/bgrabitmap/bgrabitmaptypes.pas
- Timestamp:
- Dec 22, 2016, 8:49:19 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
GraphicTest/Packages/bgrabitmap/bgrabitmaptypes.pas
r472 r494 7 7 8 8 --> Include BGRABitmap and BGRABitmapTypes in the 'uses' clause. 9 If you are using LCL types, add also BGRAGraphics unit. 9 10 10 11 **************************************************************************** … … 26 27 27 28 {$mode objfpc}{$H+} 29 {$i bgrabitmap.inc} 28 30 29 31 interface 30 32 31 33 uses 32 Classes, Types, Graphics, FPImage, FPImgCanv, GraphType; 34 Classes, Types, BGRAGraphics, 35 FPImage, FPImgCanv{$IFDEF BGRABITMAP_USE_LCL}, GraphType{$ENDIF}, 36 BGRAMultiFileType; 33 37 34 38 type 35 //pointer for direct pixel access 36 PBGRAPixel = ^TBGRAPixel; 37 39 TMultiFileContainer = BGRAMultiFileType.TMultiFileContainer; 38 40 Int32or64 = {$IFDEF CPU64}Int64{$ELSE}LongInt{$ENDIF}; 39 41 UInt32or64 = {$IFDEF CPU64}UInt64{$ELSE}LongWord{$ENDIF}; 40 42 41 //Each pixel is a sequence of 4 bytes containing blue, green, red and alpha channel. 42 TBGRAPixel = packed record 43 blue, green, red, alpha: byte; 44 end; 45 46 ArrayOfTBGRAPixel = array of TBGRAPixel; 47 48 //gamma expanded values 49 TExpandedPixel = packed record 50 red, green, blue, alpha: word; 51 end; 52 53 //pixel color defined in HSL colorspace 54 THSLAPixel = packed record 55 hue, saturation, lightness, alpha: word; 56 end; 57 TGSBAPixel = THSLAPixel; 58 59 //general purpose color variable with floating point values 60 TColorF = packed array[1..4] of single; 61 62 { These types are used as parameters } 63 64 TDrawMode = (dmSet, //replace pixels 65 dmSetExceptTransparent, //draw pixels with alpha=255 66 dmLinearBlend, //blend without gamma correction 67 dmDrawWithTransparency, //normal blending with gamma correction 68 dmXor); //bitwise xor for all channels 69 TChannel = (cRed, cGreen, cBlue, cAlpha); 70 TChannels = set of TChannel; 71 72 //floodfill option 73 TFloodfillMode = (fmSet, //set pixels 74 fmDrawWithTransparency, //draw fill color with transparency 75 fmProgressive); //draw fill color with transparency according to similarity with start color 76 77 TResampleMode = (rmSimpleStretch, //low quality resample 78 rmFineResample); //use resample filters and pixel-centered coordinates 79 TResampleFilter = (rfBox, //equivalent of stretch with high quality 80 rfLinear, //linear interpolation 81 rfHalfCosine, //mix of rfLinear and rfCosine 82 rfCosine, //cosine-like interpolation 83 rfBicubic, //simple bi-cubic filter (blur) 84 rfMitchell, //downsizing interpolation 85 rfSpline, //upsizing interpolation 86 rfLanczos2, //Lanczos with radius 2 87 rfLanczos3, //Lanczos with radius 3 88 rfLanczos4, //Lanczos with radius 4 89 rfBestQuality); //mix of rfMitchell and rfSpline 90 91 TDitheringAlgorithm = (daNearestNeighbor, daFloydSteinberg); 92 TAlphaChannelPaletteOption = (acIgnore, acTransparentEntry, acFullChannelInPalette); 43 {=== Miscellaneous types ===} 44 45 type 46 {* Options when doing a floodfill (also called bucket fill) } 47 TFloodfillMode = ( 48 {** Pixels that are filled are replaced } 49 fmSet, 50 {** Pixels that are filled are drawn upon with the fill color } 51 fmDrawWithTransparency, 52 {** Pixels that are filled are drawn upon to the extent that the color underneath is similar to 53 the start color. The more different the different is, the less it is drawn upon } 54 fmProgressive); 55 56 {* Specifies how much smoothing is applied to the computation of the median } 57 TMedianOption = (moNone, moLowSmooth, moMediumSmooth, moHighSmooth); 58 {* Specifies the shape of a predefined blur } 59 TRadialBlurType = ( 60 {** Gaussian-like, pixel importance decreases progressively } 61 rbNormal, 62 {** Disk blur, pixel importance does not decrease progressively } 63 rbDisk, 64 {** Pixel are considered when they are at a certain distance } 65 rbCorona, 66 {** Gaussian-like, but 10 times smaller than ''rbNormal'' } 67 rbPrecise, 68 {** Gaussian-like but simplified to be computed faster } 69 rbFast, 70 {** Box blur, pixel importance does not decrease progressively 71 and the pixels are included when they are in a square. 72 This is much faster than ''rbFast'' however you may get 73 square shapes in the resulting image } 74 rbBox); 75 76 TEmbossOption = (eoTransparent, eoPreserveHue); 77 TEmbossOptions = set of TEmbossOption; 78 79 TTextLayout = BGRAGraphics.TTextLayout; 93 80 94 81 const 82 tlTop = BGRAGraphics.tlTop; 83 tlCenter = BGRAGraphics.tlCenter; 84 tlBottom = BGRAGraphics.tlBottom; 85 86 // checks the bounds of an image in the given clipping rectangle 87 function CheckPutImageBounds(x, y, tx, ty: integer; out minxb, minyb, maxxb, maxyb, ignoreleft: integer; const cliprect: TRect): boolean; 88 89 {==== Imported from GraphType ====} 90 //if this unit is defined, otherwise 91 //define here the types used by the library. 92 {$IFDEF BGRABITMAP_USE_LCL} 93 type 94 { Order of the lines in an image } 95 TRawImageLineOrder = GraphType.TRawImageLineOrder; 96 { Order of the bits in a byte containing pixel values } 97 TRawImageBitOrder = GraphType.TRawImageBitOrder; 98 { Order of the bytes in a group of byte containing pixel values } 99 TRawImageByteOrder = GraphType.TRawImageByteOrder; 100 { Definition of a single line 3D bevel } 101 TGraphicsBevelCut = GraphType.TGraphicsBevelCut; 102 103 const 104 riloTopToBottom = GraphType.riloTopToBottom; // The first line (line 0) is the top line 105 riloBottomToTop = GraphType.riloBottomToTop; // The first line (line 0) is the bottom line 106 107 riboBitsInOrder = GraphType.riboBitsInOrder; // Bit 0 is pixel 0 108 riboReversedBits = GraphType.riboReversedBits; // Bit 0 is pixel 7 (Bit 1 is pixel 6, ...) 109 110 riboLSBFirst = GraphType.riboLSBFirst; // least significant byte first (little endian) 111 riboMSBFirst = GraphType.riboMSBFirst; // most significant byte first (big endian) 112 113 fsSurface = GraphType.fsSurface; //type is defined as Graphics.TFillStyle 114 fsBorder = GraphType.fsBorder; 115 116 bvNone = GraphType.bvNone; 117 bvLowered = GraphType.bvLowered; 118 bvRaised = GraphType.bvRaised; 119 bvSpace = GraphType.bvSpace; 120 {$ELSE} 121 type 122 {* Order of the lines in an image } 123 TRawImageLineOrder = ( 124 {** The first line in memory (line 0) is the top line } 125 riloTopToBottom, 126 {** The first line in memory (line 0) is the bottom line } 127 riloBottomToTop); 128 129 {* Order of the bits in a byte containing pixel values } 130 TRawImageBitOrder = ( 131 {** The lowest bit is on the left. So with a monochrome picture, bit 0 would be pixel 0 } 132 riboBitsInOrder, 133 {** The lowest bit is on the right. So with a momochrome picture, bit 0 would be pixel 7 (bit 1 would be pixel 6, ...) } 134 riboReversedBits); 135 136 {* Order of the bytes in a group of byte containing pixel values } 137 TRawImageByteOrder = ( 138 {** Least significant byte first (little endian) } 139 riboLSBFirst, 140 {** most significant byte first (big endian) } 141 riboMSBFirst); 142 143 {* Definition of a single line 3D bevel } 144 TGraphicsBevelCut = 145 ( 146 {** No bevel } 147 bvNone, 148 {** Shape is lowered, light is on the bottom-right corner } 149 bvLowered, 150 {** Shape is raised, light is on the top-left corner } 151 bvRaised, 152 {** Shape is at the same level, there is no particular lighting } 153 bvSpace); 154 {$ENDIF} 155 156 {$DEFINE INCLUDE_INTERFACE} 157 {$I bgrapixel.inc} 158 159 {$DEFINE INCLUDE_INTERFACE} 160 {$I geometrytypes.inc} 161 162 {$DEFINE INCLUDE_INTERFACE} 163 {$i csscolorconst.inc} 164 165 {$DEFINE INCLUDE_SCANNER_INTERFACE } 166 {$I bgracustombitmap.inc} 167 168 {==== Integer math ====} 169 170 {* Computes the value modulo cycle, and if the ''value'' is negative, the result 171 is still positive } 172 function PositiveMod(value, cycle: Int32or64): Int32or64; inline; overload; 173 174 { Sin65536 and Cos65536 are fast routines to compute sine and cosine as integer values. 175 They use a table to store already computed values. The return value is an integer 176 ranging from 0 to 65536, so the mean value is 32768 and the half amplitude is 177 32768 instead of 1. The input has a period of 65536, so you can supply any integer 178 without applying a modulo. } 179 180 { Compute all values now } 181 procedure PrecalcSin65536; 182 183 {* Returns an integer approximation of the sine. Value ranges from 0 to 65535, 184 where 65536 corresponds to the next cycle } 185 function Sin65536(value: word): Int32or64; inline; 186 {* Returns an integer approximation of the cosine. Value ranges from 0 to 65535, 187 where 65536 corresponds to the next cycle } 188 function Cos65536(value: word): Int32or64; inline; 189 190 {* Returns the square root of the given byte, considering that 191 255 is equal to unity } 192 function ByteSqrt(value: byte): byte; inline; 193 194 {==== Types provided for fonts ====} 195 type 196 {* Quality to be used to render text } 197 TBGRAFontQuality = ( 198 {** Use the system capabilities. It is rather fast however it may be 199 not be smoothed. } 200 fqSystem, 201 {** Use the system capabilities to render with ClearType. This quality is 202 of course better than fqSystem however it may not be perfect.} 203 fqSystemClearType, 204 {** Garanties a high quality antialiasing. } 205 fqFineAntialiasing, 206 {** Fine antialiasing with ClearType in assuming an LCD display in red/green/blue order } 207 fqFineClearTypeRGB, 208 {** Fine antialiasing with ClearType in assuming an LCD display in blue/green/red order } 209 fqFineClearTypeBGR); 210 211 {* Measurements of a font } 212 TFontPixelMetric = record 213 {** The values have been computed } 214 Defined: boolean; 215 {** Position of the baseline, where most letters lie } 216 Baseline, 217 {** Position of the top of the small letters (x being one of them) } 218 xLine, 219 {** Position of the top of the UPPERCASE letters } 220 CapLine, 221 {** Position of the bottom of letters like g and p } 222 DescentLine, 223 {** Total line height including line spacing defined by the font } 224 Lineheight: integer; 225 end; 226 227 {* Vertical anchoring of the font. When text is drawn, a start coordinate 228 is necessary. Text can be positioned in different ways. This enum 229 defines what position it is regarding the font } 230 TFontVerticalAnchor = ( 231 {** The top of the font. Everything will be drawn below the start coordinate. } 232 fvaTop, 233 {** The center of the font } 234 fvaCenter, 235 {** The top of capital letters } 236 fvaCapLine, 237 {** The center of capital letters } 238 fvaCapCenter, 239 {** The top of small letters } 240 fvaXLine, 241 {** The center of small letters } 242 fvaXCenter, 243 {** The baseline, the bottom of most letters } 244 fvaBaseline, 245 {** The bottom of letters that go below the baseline } 246 fvaDescentLine, 247 {** The bottom of the font. Everything will be drawn above the start coordinate } 248 fvaBottom); 249 250 {* Definition of a function that handles work-break } 251 TWordBreakHandler = procedure(var ABeforeUTF8, AAfterUTF8: string) of object; 252 253 {* Alignment for a typewriter, that does not have any more information 254 than a square shape containing glyphs } 255 TBGRATypeWriterAlignment = (twaTopLeft, twaTop, twaTopRight, twaLeft, twaMiddle, twaRight, twaBottomLeft, twaBottom, twaBottomRight); 256 {* How a typewriter must render its content on a Canvas2d } 257 TBGRATypeWriterOutlineMode = (twoPath, twoFill, twoStroke, twoFillOverStroke, twoStrokeOverFill, twoFillThenStroke, twoStrokeThenFill); 258 259 { TBGRACustomFontRenderer } 260 {* Abstract class for all font renderers } 261 TBGRACustomFontRenderer = class 262 {** Specifies the font to use. Unless the font renderer accept otherwise, 263 the name is in human readable form, like 'Arial', 'Times New Roman', ... } 264 FontName: string; 265 266 {** Specifies the set of styles to be applied to the font. 267 These can be fsBold, fsItalic, fsStrikeOut, fsUnderline. 268 So the value [fsBold,fsItalic] means that the font must be bold and italic } 269 FontStyle: TFontStyles; 270 271 {** Specifies the quality of rendering. Default value is fqSystem } 272 FontQuality : TBGRAFontQuality; 273 274 {** Specifies the rotation of the text, for functions that support text rotation. 275 It is expressed in tenth of degrees, positive values going counter-clockwise } 276 FontOrientation: integer; 277 278 {** Specifies the height of the font without taking into account additional line spacing. 279 A negative value means that it is the full height instead } 280 FontEmHeight: integer; 281 282 {** Returns measurement for the current font in pixels } 283 function GetFontPixelMetric: TFontPixelMetric; virtual; abstract; 284 285 {** Returns the total size of the string provided using the current font. 286 Orientation is not taken into account, so that the width is along the text } 287 function TextSize(sUTF8: string): TSize; virtual; abstract; 288 289 {** Draws the UTF8 encoded string, with color ''c''. 290 If align is taLeftJustify, (''x'',''y'') is the top-left corner. 291 If align is taCenter, (''x'',''y'') is at the top and middle of the text. 292 If align is taRightJustify, (''x'',''y'') is the top-right corner. 293 The value of ''FontOrientation'' is taken into account, so that the text may be rotated } 294 procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; c: TBGRAPixel; align: TAlignment); virtual; abstract; 295 296 {** Same as above functions, except that the text is filled using texture. 297 The value of ''FontOrientation'' is taken into account, so that the text may be rotated } 298 procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; texture: IBGRAScanner; align: TAlignment); virtual; abstract; 299 300 {** Same as above, except that the orientation is specified, overriding the value of the property ''FontOrientation'' } 301 procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientationTenthDegCCW: integer; sUTF8: string; c: TBGRAPixel; align: TAlignment); virtual; abstract; 302 {** Same as above, except that the orientation is specified, overriding the value of the property ''FontOrientation'' } 303 procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientationTenthDegCCW: integer; sUTF8: string; texture: IBGRAScanner; align: TAlignment); virtual; abstract; 304 305 {** Draw the UTF8 encoded string at the coordinate (''x'',''y''), clipped inside the rectangle ''ARect''. 306 Additional style information is provided by the style parameter. 307 The color ''c'' is used to fill the text. No rotation is applied. } 308 procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; c: TBGRAPixel); virtual; abstract; 309 310 {** Same as above except a ''texture'' is used to fill the text } 311 procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; texture: IBGRAScanner); virtual; abstract; 312 313 {** Copy the path for the UTF8 encoded string into ''ADest''. 314 If ''align'' is ''taLeftJustify'', (''x'',''y'') is the top-left corner. 315 If ''align'' is ''taCenter'', (''x'',''y'') is at the top and middle of the text. 316 If ''align'' is ''taRightJustify'', (''x'',''y'') is the top-right corner. } 317 procedure CopyTextPathTo({%H-}ADest: IBGRAPath; {%H-}x, {%H-}y: single; {%H-}s: string; {%H-}align: TAlignment); virtual; //optional 318 end; 319 320 {* Output mode for the improved renderer for readability. This is used by the font renderer based on LCL in ''BGRAText'' } 321 TBGRATextOutImproveReadabilityMode = (irMask, irNormal, irClearTypeRGB, irClearTypeBGR); 322 323 {** Removes line ending and tab characters from a string (for a function 324 like ''TextOut'' that does not handle this). this works with UTF8 strings 325 as well } 326 function CleanTextOutString(s: string): string; 327 {** Remove the line ending at the specified position or return False. 328 This works with UTF8 strings however the index is the byte index } 329 function RemoveLineEnding(var s: string; indexByte: integer): boolean; 330 {** Remove the line ending at the specified position or return False. 331 The index is the character index, that may be different from the 332 byte index } 333 function RemoveLineEndingUTF8(var sUTF8: string; indexUTF8: integer): boolean; 334 {** Default word break handler, that simply divide when there is a space } 335 procedure BGRADefaultWordBreakHandler(var ABefore, AAfter: string); 336 337 {==== Images and resampling ====} 338 339 type 340 {* How the resample is to be computed } 341 TResampleMode = ( 342 {** Low quality resample by repeating pixels, stretching them } 343 rmSimpleStretch, 344 {** Use resample filters. This gives high 345 quality resampling however this the proportion changes slightly because 346 the first and last pixel are considered to occupy only half a unit as 347 they are considered as the border of the picture 348 (pixel-centered coordinates) } 349 rmFineResample); 350 351 {* List of resample filter to be used with ''rmFineResample'' } 352 TResampleFilter = ( 353 {** Equivalent of simple stretch with high quality and pixel-centered coordinates } 354 rfBox, 355 {** Linear interpolation giving slow transition between pixels } 356 rfLinear, 357 {** Mix of ''rfLinear'' and ''rfCosine'' giving medium speed stransition between pixels } 358 rfHalfCosine, 359 {** Cosine-like interpolation giving fast transition between pixels } 360 rfCosine, 361 {** Simple bi-cubic filter (blurry) } 362 rfBicubic, 363 {** Mitchell filter, good for downsizing interpolation } 364 rfMitchell, 365 {** Spline filter, good for upsizing interpolation, however slightly blurry } 366 rfSpline, 367 {** Lanczos with radius 2, blur is corrected } 368 rfLanczos2, 369 {** Lanczos with radius 3, high contrast } 370 rfLanczos3, 371 {** Lanczos with radius 4, high contrast } 372 rfLanczos4, 373 {** Best quality using rfMitchell or rfSpline } 374 rfBestQuality); 375 376 const 377 {** List of strings to represent resample filters } 95 378 ResampleFilterStr : array[TResampleFilter] of string = 96 379 ('Box','Linear','HalfCosine','Cosine','Bicubic','Mitchell','Spline', 97 380 'Lanczos2','Lanczos3','Lanczos4','BestQuality'); 98 381 99 function StrToResampleFilter(str: string): TResampleFilter; 382 {** Gives the sample filter represented by a string } 383 function StrToResampleFilter(str: string): TResampleFilter; 100 384 101 385 type 102 TBGRAImageFormat = (ifUnknown, ifJpeg, ifPng, ifGif, ifBmp, ifIco, ifPcx, ifPaintDotNet, ifLazPaint, ifOpenRaster, 103 ifPsd, ifTarga, ifTiff, ifXwd, ifXPixMap, ifBmpMioMap); 386 {* List of image formats } 387 TBGRAImageFormat = ( 388 {** Unknown format } 389 ifUnknown, 390 {** JPEG format, opaque, lossy compression } 391 ifJpeg, 392 {** PNG format, transparency, lossless compression } 393 ifPng, 394 {** GIF format, single transparent color, lossless in theory but only low number of colors allowed } 395 ifGif, 396 {** BMP format, transparency, no compression. Note that transparency is 397 not supported by all BMP readers so it is not recommended to avoid 398 storing images with transparency in this format } 399 ifBmp, 400 {** ICO format, contains different sizes of the same image } 401 ifIco, 402 {** PCX format, opaque, rudimentary lossless compression } 403 ifPcx, 404 {** Paint.NET format, layers, lossless compression } 405 ifPaintDotNet, 406 {** LazPaint format, layers, lossless compression } 407 ifLazPaint, 408 {** OpenRaster format, layers, lossless compression } 409 ifOpenRaster, 410 {** Phoxo format, layers } 411 ifPhoxo, 412 {** Photoshop format, layers, rudimentary lossless compression } 413 ifPsd, 414 {** Targa format (TGA), transparency, rudimentary lossless compression } 415 ifTarga, 416 {** TIFF format, limited support } 417 ifTiff, 418 {** X-Window capture, limited support } 419 ifXwd, 420 {** X-Pixmap, text encoded image, limited support } 421 ifXPixMap, 422 {** iGO BMP, limited support } 423 ifBmpMioMap); 424 425 {* Options when loading an image } 426 TBGRALoadingOption = ( 427 {** Do not clear RGB channels when alpha is zero (not recommended) } 428 loKeepTransparentRGB, 429 {** Consider BMP to be opaque if no alpha value is provided (for compatibility) } 430 loBmpAutoOpaque, 431 {** Load JPEG quickly however with a lower quality } 432 loJpegQuick); 433 TBGRALoadingOptions = set of TBGRALoadingOption; 104 434 105 435 var 436 {** List of stream readers for images } 106 437 DefaultBGRAImageReader: array[TBGRAImageFormat] of TFPCustomImageReaderClass; 438 {** List of stream writers for images } 107 439 DefaultBGRAImageWriter: array[TBGRAImageFormat] of TFPCustomImageWriterClass; 108 440 109 type 110 TBGRAFontQuality = (fqSystem, fqSystemClearType, fqFineAntialiasing, fqFineClearTypeRGB, fqFineClearTypeBGR); 111 // fqSystem: use system rendering. It is fast however it may be not be smoothed. 112 // fqSystemClearType: use system rendering with ClearType. This quality is of course better than fqSystem however it may not be much smoother. 113 // fqFineAntialiasing: garanties a high quality antialiasing. This is slower. 114 // fqFineClearTypeRGB: garanties a high quality antialiasing with ClearType. The order of the color in the LCD screen is supposed to be un red/green/blue order. 115 // fqFineClearTypeBGR: same as above, except the color of the LCD screen is supposed to be in blue/green/red order. 116 117 TMedianOption = (moNone, moLowSmooth, moMediumSmooth, moHighSmooth); 118 TRadialBlurType = (rbNormal, rbDisk, rbCorona, rbPrecise, rbFast, rbBox); 119 TSplineStyle = (ssInside, ssInsideWithEnds, ssCrossing, ssCrossingWithEnds, 120 ssOutside, ssRoundOutside, ssVertexToSide); 121 122 { Advanced blending modes 123 see : http://www.brighthub.com/multimedia/photography/articles/18301.aspx 124 and : http://www.pegtop.net/delphi/articles/blendmodes/ } 125 TBlendOperation = (boLinearBlend, boTransparent, //blending 126 boLighten, boScreen, boAdditive, boLinearAdd, boColorDodge, boDivide, boNiceGlow, boSoftLight, boHardLight, //lighting 127 boGlow, boReflect, boOverlay, boDarkOverlay, boDarken, boMultiply, boColorBurn, //masking 128 boDifference, boLinearDifference, boExclusion, boLinearExclusion, boSubtract, boLinearSubtract, boSubtractInverse, boLinearSubtractInverse, 129 boNegation, boLinearNegation, boXor); //negative 130 131 const 132 boGlowMask = boGlow; 133 boLinearMultiply = boMultiply; 134 boNonLinearOverlay = boDarkOverlay; 135 EmptyRect : TRect = (left:0; top:0; right:0; bottom: 0); 136 137 const 138 BlendOperationStr : array[TBlendOperation] of string = 139 ('LinearBlend', 'Transparent', 140 'Lighten', 'Screen', 'Additive', 'LinearAdd', 'ColorDodge', 'Divide', 'NiceGlow', 'SoftLight', 'HardLight', 141 'Glow', 'Reflect', 'Overlay', 'DarkOverlay', 'Darken', 'Multiply', 'ColorBurn', 142 'Difference', 'LinearDifference', 'Exclusion', 'LinearExclusion', 'Subtract', 'LinearSubtract', 'SubtractInverse', 'LinearSubtractInverse', 143 'Negation', 'LinearNegation', 'Xor'); 144 145 function StrToBlendOperation(str: string): TBlendOperation; 146 147 type 148 TGradientType = (gtLinear, gtReflected, gtDiamond, gtRadial); 149 const 150 GradientTypeStr : array[TGradientType] of string = 151 ('Linear','Reflected','Diamond','Radial'); 152 function StrToGradientType(str: string): TGradientType; 153 154 type 155 { A pen style is defined as a list of floating number. The first number is the length of the first dash, 156 the second number is the length of the first gap, the third number is the length of the second dash... 157 It must have an even number of values. } 158 TBGRAPenStyle = Array Of Single; 159 TRoundRectangleOption = (rrTopLeftSquare,rrTopRightSquare,rrBottomRightSquare,rrBottomLeftSquare, 160 rrTopLeftBevel,rrTopRightBevel,rrBottomRightBevel,rrBottomLeftBevel,rrDefault); 161 TRoundRectangleOptions = set of TRoundRectangleOption; 162 TPolygonOrder = (poNone, poFirstOnTop, poLastOnTop); //see TBGRAMultiShapeFiller in BGRAPolygon 163 164 function BGRAPenStyle(dash1, space1: single; dash2: single=0; space2: single = 0; dash3: single=0; space3: single = 0; dash4 : single = 0; space4 : single = 0): TBGRAPenStyle; 165 166 { Point, polygon and curve structures } 167 type 168 PPointF = ^TPointF; 169 TPointF = packed record 170 x, y: single; 171 end; 172 ArrayOfTPointF = array of TPointF; 173 TArcOption = (aoClosePath, aoPie, aoFillPath); 174 TArcOptions = set of TArcOption; 175 176 TCubicBezierCurve = record 177 p1,c1,c2,p2: TPointF; 178 end; 179 TQuadraticBezierCurve = record 180 p1,c,p2: TPointF; 181 end; 182 183 TArcDef = record 184 center: TPointF; 185 radius: TPointF; 186 xAngleRadCW, startAngleRadCW, endAngleRadCW: single; //see convention in BGRAPath 187 anticlockwise: boolean 188 end; 189 PArcDef = ^TArcDef; 190 191 TPoint3D = record 192 x,y,z: single; 193 end; 194 195 TBGRAArrowStyle = (asNone, asNormal, asCut, asTriangle, asHollowTriangle, asFlipped, asFlippedCut, asTail, asTailRepeat); 196 197 TBGRATypeWriterAlignment = (twaTopLeft, twaTop, twaTopRight, 198 twaLeft, twaMiddle, twaRight, 199 twaBottomLeft, twaBottom, twaBottomRight); 200 TBGRATypeWriterOutlineMode = (twoPath, twoFill, twoStroke, twoFillOverStroke, twoStrokeOverFill, twoFillThenStroke, twoStrokeThenFill); 201 202 function ConcatPointsF(const APolylines: array of ArrayOfTPointF): ArrayOfTPointF; 203 204 function Point3D(x,y,z: single): TPoint3D; 205 operator = (const v1,v2: TPoint3D): boolean; inline; 206 operator * (const v1,v2: TPoint3D): single; inline; 207 operator * (const v1: TPoint3D; const factor: single): TPoint3D; inline; 208 operator - (const v1,v2: TPoint3D): TPoint3D; inline; 209 operator - (const v: TPoint3D): TPoint3D; inline; 210 operator + (const v1,v2: TPoint3D): TPoint3D; inline; 211 procedure VectProduct3D(u,v: TPoint3D; out w: TPoint3D); 212 procedure Normalize3D(var v: TPoint3D); inline; 213 214 function BezierCurve(origin, control1, control2, destination: TPointF) : TCubicBezierCurve; overload; 215 function BezierCurve(origin, control, destination: TPointF) : TQuadraticBezierCurve; overload; 216 function BezierCurve(origin, destination: TPointF) : TQuadraticBezierCurve; overload; 217 function ArcDef(cx, cy, rx,ry, xAngleRadCW, startAngleRadCW, endAngleRadCW: single; anticlockwise: boolean) : TArcDef; 218 219 { Useful constants } 220 const 221 dmFastBlend = dmLinearBlend; 222 EmptySingle: single = -3.402823e38; //used as a separator in floating point lists 223 EmptyPointF: TPointF = (x: -3.402823e38; y: -3.402823e38); //used as a separator in TPointF lists 224 BGRAPixelTransparent: TBGRAPixel = (blue: 0; green: 0; red: 0; alpha: 0); 225 BGRAWhite: TBGRAPixel = (blue: 255; green: 255; red: 255; alpha: 255); 226 BGRABlack: TBGRAPixel = (blue: 0; green: 0; red: 0; alpha: 255); 227 228 { This color is needed for drawing black shapes on the standard TCanvas, because 229 when drawing with pure black, there is no way to know if something has been 230 drawn or if it is transparent } 231 clBlackOpaque = TColor($010000); 232 233 {$DEFINE INCLUDE_COLOR_CONST} 234 {$i csscolorconst.inc} 235 236 type 237 TBGRAColorDefinition = record 238 Name: string; 239 Color: TBGRAPixel; 240 end; 241 242 { TBGRAColorList } 243 244 TBGRAColorList = class 245 protected 246 FFinished: boolean; 247 FNbColors: integer; 248 FColors: array of TBGRAColorDefinition; 249 function GetByIndex(Index: integer): TBGRAPixel; 250 function GetByName(Name: string): TBGRAPixel; 251 function GetName(Index: integer): string; 252 public 253 constructor Create; 254 procedure Add(Name: string; const Color: TBGRAPixel); 255 procedure Finished; 256 function IndexOf(Name: string): integer; 257 function IndexOfColor(const AColor: TBGRAPixel; AMaxDiff: Word = 0): integer; 258 259 property ByName[Name: string]: TBGRAPixel read GetByName; 260 property ByIndex[Index: integer]: TBGRAPixel read GetByIndex; default; 261 property Name[Index: integer]: string read GetName; 262 property Count: integer read FNbColors; 263 end; 264 265 var 266 VGAColors, CSSColors: TBGRAColorList; 267 268 function isEmptyPointF(pt: TPointF): boolean; 269 270 type 271 TFontPixelMetric = record 272 Defined: boolean; 273 Baseline, xLine, CapLine, DescentLine, Lineheight: integer; 274 end; 275 276 { A scanner is like an image, but its content has no limit and can be calculated on the fly. 277 It must not implement reference counting. } 278 IBGRAScanner = interface 279 procedure ScanMoveTo(X,Y: Integer); 280 function ScanNextPixel: TBGRAPixel; 281 function ScanAt(X,Y: Single): TBGRAPixel; 282 function ScanAtInteger(X,Y: integer): TBGRAPixel; 283 procedure ScanPutPixels(pdest: PBGRAPixel; count: integer; mode: TDrawMode); 284 function IsScanPutPixelsDefined: boolean; 285 end; 286 287 { A path is the ability to define a contour with moveTo, lineTo... 288 It must not implement reference counting. } 289 IBGRAPath = interface 290 procedure closePath; 291 procedure moveTo(const pt: TPointF); 292 procedure lineTo(const pt: TPointF); 293 procedure polylineTo(const pts: array of TPointF); 294 procedure quadraticCurveTo(const cp,pt: TPointF); 295 procedure bezierCurveTo(const cp1,cp2,pt: TPointF); 296 procedure arc(const arcDef: TArcDef); 297 procedure copyTo(dest: IBGRAPath); 298 end; 299 300 TScanAtFunction = function (X,Y: Single): TBGRAPixel of object; 301 TScanAtIntegerFunction = function (X,Y: Integer): TBGRAPixel of object; 302 TScanNextPixelFunction = function: TBGRAPixel of object; 303 TBGRACustomGradient = class; 304 305 TBGRACustomFillInfo = class; 306 TBGRACustomFontRenderer = class; 307 308 { TBGRACustomBitmap } 309 310 TBGRACustomBitmap = class(TFPCustomImage,IBGRAScanner) // a bitmap can be used as a scanner 311 private 312 function GetFontAntialias: Boolean; 313 procedure SetFontAntialias(const AValue: Boolean); 314 protected 315 { accessors to properies } 316 function GetArrowEndRepeat: integer; virtual; abstract; 317 function GetArrowStartRepeat: integer; virtual; abstract; 318 procedure SetArrowEndRepeat(AValue: integer); virtual; abstract; 319 procedure SetArrowStartRepeat(AValue: integer); virtual; abstract; 320 function GetArrowEndOffset: single; virtual; abstract; 321 function GetArrowStartOffset: single; virtual; abstract; 322 procedure SetArrowEndOffset(AValue: single); virtual; abstract; 323 procedure SetArrowStartOffset(AValue: single); virtual; abstract; 324 function GetArrowEndSize: TPointF; virtual; abstract; 325 function GetArrowStartSize: TPointF; virtual; abstract; 326 procedure SetArrowEndSize(AValue: TPointF); virtual; abstract; 327 procedure SetArrowStartSize(AValue: TPointF); virtual; abstract; 328 function GetLineCap: TPenEndCap; virtual; abstract; 329 procedure SetLineCap(AValue: TPenEndCap); virtual; abstract; 330 function GetFontRenderer: TBGRACustomFontRenderer; virtual; abstract; 331 procedure SetFontRenderer(AValue: TBGRACustomFontRenderer); virtual; abstract; 332 function GetHeight: integer; virtual; abstract; 333 function GetWidth: integer; virtual; abstract; 334 function GetDataPtr: PBGRAPixel; virtual; abstract; 335 function GetNbPixels: integer; virtual; abstract; 336 function CheckEmpty: boolean; virtual; abstract; 337 function GetHasTransparentPixels: boolean; virtual; abstract; 338 function GetAverageColor: TColor; virtual; abstract; 339 function GetAveragePixel: TBGRAPixel; virtual; abstract; 340 procedure SetCanvasOpacity(AValue: byte); virtual; abstract; 341 function GetScanLine(y: integer): PBGRAPixel; virtual; abstract; 342 function GetRefCount: integer; virtual; abstract; 343 function GetBitmap: TBitmap; virtual; abstract; 344 function GetLineOrder: TRawImageLineOrder; virtual; abstract; 345 function GetCanvasFP: TFPImageCanvas; virtual; abstract; 346 function GetCanvasDrawModeFP: TDrawMode; virtual; abstract; 347 procedure SetCanvasDrawModeFP(const AValue: TDrawMode); virtual; abstract; 348 function GetCanvas: TCanvas; virtual; abstract; 349 function GetCanvasOpacity: byte; virtual; abstract; 350 function GetCanvasAlphaCorrection: boolean; virtual; abstract; 351 procedure SetCanvasAlphaCorrection(const AValue: boolean); virtual; abstract; 352 function GetFontHeight: integer; virtual; abstract; 353 procedure SetFontHeight(AHeight: integer); virtual; abstract; 354 function GetFontFullHeight: integer; virtual; abstract; 355 procedure SetFontFullHeight(AHeight: integer); virtual; abstract; 356 function GetPenStyle: TPenStyle; virtual; abstract; 357 procedure SetPenStyle(const AValue: TPenStyle); virtual; abstract; 358 function GetCustomPenStyle: TBGRAPenStyle; virtual; abstract; 359 procedure SetCustomPenStyle(const AValue: TBGRAPenStyle); virtual; abstract; 360 function GetClipRect: TRect; virtual; abstract; 361 procedure SetClipRect(const AValue: TRect); virtual; abstract; 362 function GetFontPixelMetric: TFontPixelMetric; virtual; abstract; 363 procedure ClearTransparentPixels; virtual; abstract; 364 procedure SetArrowStart(AStyle: TBGRAArrowStyle; ATipStyle: TPenJoinStyle = pjsMiter; ARelativePenWidth: single = 1; ATriangleBackOffset: single = 0); virtual; abstract; 365 procedure SetArrowEnd(AStyle: TBGRAArrowStyle; ATipStyle: TPenJoinStyle = pjsMiter; ARelativePenWidth: single = 1; ATriangleBackOffset: single = 0); virtual; abstract; 366 367 public 368 Caption: string; //user defined caption 369 370 {-------------------font style------------------------} 371 FontName: string; //Specifies the font to use. Unless the font renderer accept otherwise, 372 //the name is in human readable form, like 'Arial', 'Times New Roman', ... 373 374 FontStyle: TFontStyles; //Specifies the set of styles to be applied to the font. 375 //These can be fsBold, fsItalic, fsStrikeOut, fsUnderline. 376 //So the value [fsBold,fsItalic] means that the font must be bold and italic. 377 378 FontQuality : TBGRAFontQuality;//Specifies the quality of rendering. Default value is fqSystem. 379 380 FontOrientation: integer; //Specifies the rotation of the text, for functions that support text rotation. 381 //It is expressed in tenth of degrees, positive values going counter-clockwise. 382 383 //line style 384 JoinStyle: TPenJoinStyle; 385 JoinMiterLimit: single; 386 387 FillMode: TFillMode; //winding or alternate 388 LinearAntialiasing: boolean; 389 390 { The resample filter is used when resizing the bitmap, and 391 scan interpolation filter is used when the bitmap is used 392 as a scanner (IBGRAScanner) } 393 ResampleFilter, 394 ScanInterpolationFilter: TResampleFilter; 395 ScanOffset: TPoint; 396 397 constructor Create; virtual; abstract; overload; 398 constructor Create(ABitmap: TBitmap); virtual; abstract; overload; 399 constructor Create(AWidth, AHeight: integer; Color: TColor); virtual; abstract; overload; 400 constructor Create(AWidth, AHeight: integer; Color: TBGRAPixel); virtual; abstract; overload; 401 constructor Create(AFilename: string); virtual; abstract; overload; 402 constructor Create(AFilename: string; AIsUtf8Filename: boolean); virtual; abstract; overload; 403 constructor Create(AStream: TStream); virtual; abstract; overload; 404 405 function NewBitmap(AWidth, AHeight: integer): TBGRACustomBitmap; virtual; abstract; overload; 406 function NewBitmap(AWidth, AHeight: integer; Color: TBGRAPixel): TBGRACustomBitmap; virtual; abstract; overload; 407 function NewBitmap(Filename: string): TBGRACustomBitmap; virtual; abstract; overload; 408 function NewBitmap(Filename: string; AIsUtf8: boolean): TBGRACustomBitmap; virtual; abstract; overload; 409 410 //there are UTF8 functions that are different from standard function as those 411 //depend on TFPCustomImage that does not clearly handle UTF8 412 procedure LoadFromFile(const filename: string); virtual; 413 procedure LoadFromFileUTF8(const filenameUTF8: string); virtual; 414 procedure LoadFromFileUTF8(const filenameUTF8: string; AHandler: TFPCustomImageReader); virtual; 415 procedure LoadFromStream(Str: TStream); virtual; overload; 416 procedure LoadFromStream(Str: TStream; Handler: TFPCustomImageReader); virtual; overload; 417 procedure SaveToFile(const filename: string); virtual; overload; 418 procedure SaveToFile(const filename: string; Handler:TFPCustomImageWriter); virtual; overload; 419 procedure SaveToFileUTF8(const filenameUTF8: string); virtual; overload; 420 procedure SaveToFileUTF8(const filenameUTF8: string; Handler:TFPCustomImageWriter); virtual; overload; 421 procedure SaveToStreamAsPng(Str: TStream); virtual; abstract; 422 procedure SaveToStreamAs(Str: TStream; AFormat: TBGRAImageFormat); virtual; 423 procedure Assign(ARaster: TRasterImage); virtual; abstract; overload; 424 procedure Assign(MemBitmap: TBGRACustomBitmap); virtual; abstract; overload; 425 procedure Serialize(AStream: TStream); virtual; abstract; 426 procedure Deserialize(AStream: TStream); virtual; abstract; 427 428 {Pixel functions} 429 procedure SetPixel(x, y: int32or64; c: TColor); virtual; abstract; overload; 430 procedure XorPixel(x, y: int32or64; c: TBGRAPixel); virtual; abstract; overload; 431 procedure SetPixel(x, y: int32or64; c: TBGRAPixel); virtual; abstract; overload; 432 procedure DrawPixel(x, y: int32or64; c: TBGRAPixel); virtual; abstract; overload; 433 procedure DrawPixel(x, y: int32or64; c: TBGRAPixel; ADrawMode: TDrawMode); overload; 434 procedure DrawPixel(x, y: int32or64; ec: TExpandedPixel); virtual; abstract; overload; 435 procedure FastBlendPixel(x, y: int32or64; c: TBGRAPixel); virtual; abstract; 436 procedure ErasePixel(x, y: int32or64; alpha: byte); virtual; abstract; 437 procedure AlphaPixel(x, y: int32or64; alpha: byte); virtual; abstract; 438 function GetPixel(x, y: int32or64): TBGRAPixel; virtual; abstract; overload; 439 function GetPixel256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter = rfLinear; smoothBorder: boolean = true): TBGRAPixel; virtual; abstract; 440 function GetPixel(x, y: single; AResampleFilter: TResampleFilter = rfLinear; smoothBorder: boolean = true): TBGRAPixel; virtual; abstract; overload; 441 function GetPixelCycle(x, y: int32or64): TBGRAPixel; virtual; overload; 442 function GetPixelCycle(x, y: single; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; virtual; abstract; overload; 443 function GetPixelCycle(x, y: single; AResampleFilter: TResampleFilter; repeatX: boolean; repeatY: boolean): TBGRAPixel; virtual; abstract; overload; 444 function GetPixelCycle256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; virtual; abstract; overload; 445 function GetPixelCycle256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter; repeatX: boolean; repeatY: boolean): TBGRAPixel; virtual; abstract; overload; 446 447 {Line primitives} 448 procedure SetHorizLine(x, y, x2: int32or64; c: TBGRAPixel); virtual; abstract; 449 procedure XorHorizLine(x, y, x2: int32or64; c: TBGRAPixel); virtual; abstract; 450 procedure DrawHorizLine(x, y, x2: int32or64; c: TBGRAPixel); virtual; abstract; overload; 451 procedure DrawHorizLine(x, y, x2: int32or64; ec: TExpandedPixel); virtual; abstract; overload; 452 procedure DrawHorizLine(x, y, x2: int32or64; texture: IBGRAScanner); overload; 453 procedure FastBlendHorizLine(x, y, x2: int32or64; c: TBGRAPixel); virtual; abstract; 454 procedure AlphaHorizLine(x, y, x2: int32or64; alpha: byte); virtual; abstract; 455 procedure SetVertLine(x, y, y2: int32or64; c: TBGRAPixel); virtual; abstract; 456 procedure XorVertLine(x, y, y2: int32or64; c: TBGRAPixel); virtual; abstract; 457 procedure DrawVertLine(x, y, y2: int32or64; c: TBGRAPixel); virtual; abstract; 458 procedure AlphaVertLine(x, y, y2: int32or64; alpha: byte); virtual; abstract; 459 procedure FastBlendVertLine(x, y, y2: int32or64; c: TBGRAPixel); virtual; abstract; 460 procedure DrawHorizLineDiff(x, y, x2: int32or64; c, compare: TBGRAPixel; maxDiff: byte); virtual; abstract; 461 procedure HorizLine(x,y,x2: Int32or64; c: TBGRAPixel; ADrawMode: TDrawMode); overload; 462 procedure VertLine(x,y,y2: Int32or64; c: TBGRAPixel; ADrawMode: TDrawMode); 463 procedure HorizLine(x,y,x2: Int32or64; texture: IBGRAScanner; ADrawMode: TDrawMode); virtual; abstract; overload; 464 465 {Shapes} 466 procedure DrawPath(APath: IBGRAPath; c: TBGRAPixel; w: single); virtual; abstract; 467 procedure DrawPath(APath: IBGRAPath; texture: IBGRAScanner; w: single); virtual; abstract; 468 469 procedure ArrowStartAsNone; 470 procedure ArrowStartAsClassic(AFlipped: boolean = false; ACut: boolean = false; ARelativePenWidth: single = 1); 471 procedure ArrowStartAsTriangle(ABackOffset: single = 0; ARounded: boolean = false; AHollow: boolean = false; AHollowPenWidth: single = 0.5); 472 procedure ArrowStartAsTail; 473 474 procedure ArrowEndAsNone; 475 procedure ArrowEndAsClassic(AFlipped: boolean = false; ACut: boolean = false; ARelativePenWidth: single = 1); 476 procedure ArrowEndAsTriangle(ABackOffset: single = 0; ARounded: boolean = false; AHollow: boolean = false; AHollowPenWidth: single = 0.5); 477 procedure ArrowEndAsTail; 478 479 procedure DrawLine(x1, y1, x2, y2: integer; c: TBGRAPixel; DrawLastPixel: boolean; ADrawMode: TDrawMode= dmDrawWithTransparency); virtual; abstract; 480 procedure DrawLineAntialias(x1, y1, x2, y2: integer; c: TBGRAPixel; DrawLastPixel: boolean); virtual; abstract; overload; 481 procedure DrawLineAntialias(x1, y1, x2, y2: integer; c1, c2: TBGRAPixel; dashLen: integer; DrawLastPixel: boolean); virtual; abstract; overload; 482 procedure DrawLineAntialias(x1, y1, x2, y2: integer; c1, c2: TBGRAPixel; dashLen: integer; DrawLastPixel: boolean; var DashPos: integer); virtual; abstract; overload; 483 procedure DrawLineAntialias(x1, y1, x2, y2: single; c: TBGRAPixel; w: single); virtual; abstract; overload; 484 procedure DrawLineAntialias(x1, y1, x2, y2: single; texture: IBGRAScanner; w: single); virtual; abstract; overload; 485 procedure DrawLineAntialias(x1, y1, x2, y2: single; c: TBGRAPixel; w: single; Closed: boolean); virtual; abstract; overload; 486 procedure DrawLineAntialias(x1, y1, x2, y2: single; texture: IBGRAScanner; w: single; Closed: boolean); virtual; abstract; overload; 487 488 procedure DrawPolyLine(const points: array of TPoint; c: TBGRAPixel; DrawLastPixel: boolean; ADrawMode: TDrawMode=dmDrawWithTransparency); 489 procedure DrawPolyLineAntialias(const points: array of TPoint; c: TBGRAPixel; DrawLastPixel: boolean); virtual; overload; 490 procedure DrawPolyLineAntialias(const points: array of TPoint; c1, c2: TBGRAPixel; dashLen: integer; DrawLastPixel: boolean); virtual; overload; 491 procedure DrawPolyLineAntialias(const points: array of TPointF; c: TBGRAPixel; w: single); virtual; abstract; overload; 492 procedure DrawPolyLineAntialias(const points: array of TPointF; texture: IBGRAScanner; w: single); virtual; abstract; overload; 493 procedure DrawPolyLineAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; Closed: boolean); virtual; abstract; overload; 494 procedure DrawPolyLineAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; fillcolor: TBGRAPixel); virtual; abstract; overload; 495 procedure DrawPolygon(const points: array of TPoint; c: TBGRAPixel; ADrawMode: TDrawMode=dmDrawWithTransparency); 496 procedure DrawPolygonAntialias(const points: array of TPoint; c: TBGRAPixel); overload; 497 procedure DrawPolygonAntialias(const points: array of TPointF; c: TBGRAPixel; w: single); virtual; abstract; overload; 498 procedure DrawPolygonAntialias(const points: array of TPointF; texture: IBGRAScanner; w: single); virtual; abstract; overload; 499 procedure DrawPolygonAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; fillcolor: TBGRAPixel); virtual; abstract; overload; 500 501 procedure EraseLine(x1, y1, x2, y2: integer; alpha: byte; DrawLastPixel: boolean); virtual; abstract; 502 procedure EraseLineAntialias(x1, y1, x2, y2: integer; alpha: byte; DrawLastPixel: boolean); virtual; abstract; overload; 503 procedure EraseLineAntialias(x1, y1, x2, y2: single; alpha: byte; w: single); virtual; abstract; overload; 504 procedure EraseLineAntialias(x1, y1, x2, y2: single; alpha: byte; w: single; Closed: boolean); virtual; abstract; overload; 505 procedure ErasePolyLine(const points: array of TPoint; alpha: byte; DrawLastPixel: boolean); 506 procedure ErasePolyLineAntialias(const points: array of TPoint; alpha: byte; DrawLastPixel: boolean); overload; 507 procedure ErasePolyLineAntialias(const points: array of TPointF; alpha: byte; w: single); virtual; abstract; overload; 508 procedure ErasePolygonOutline(const points: array of TPoint; alpha: byte); 509 procedure ErasePolygonOutlineAntialias(const points: array of TPoint; alpha: byte); 510 511 procedure FillPath(APath: IBGRAPath; c: TBGRAPixel); virtual; abstract; 512 procedure FillPath(APath: IBGRAPath; texture: IBGRAScanner); virtual; abstract; 513 514 procedure FillTriangleLinearColor(pt1,pt2,pt3: TPointF; c1,c2,c3: TBGRAPixel); virtual; abstract; overload; 515 procedure FillTriangleLinearColorAntialias(pt1,pt2,pt3: TPointF; c1,c2,c3: TBGRAPixel); virtual; abstract; overload; 516 procedure FillTriangleLinearMapping(pt1,pt2,pt3: TPointF; texture: IBGRAScanner; tex1, tex2, tex3: TPointF; TextureInterpolation: Boolean= True); virtual; abstract; overload; 517 procedure FillTriangleLinearMappingLightness(pt1,pt2,pt3: TPointF; texture: IBGRAScanner; tex1, tex2, tex3: TPointF; light1,light2,light3: word; TextureInterpolation: Boolean= True); virtual; abstract; overload; 518 procedure FillTriangleLinearMappingAntialias(pt1,pt2,pt3: TPointF; texture: IBGRAScanner; tex1, tex2, tex3: TPointF); virtual; abstract; overload; 519 520 procedure FillQuadLinearColor(pt1,pt2,pt3,pt4: TPointF; c1,c2,c3,c4: TBGRAPixel); virtual; abstract; overload; 521 procedure FillQuadLinearColorAntialias(pt1,pt2,pt3,pt4: TPointF; c1,c2,c3,c4: TBGRAPixel); virtual; abstract; overload; 522 procedure FillQuadLinearMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; TextureInterpolation: Boolean= True); virtual; abstract; overload; 523 procedure FillQuadLinearMappingLightness(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; light1,light2,light3,light4: word; TextureInterpolation: Boolean= True); virtual; abstract; overload; 524 procedure FillQuadLinearMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); virtual; abstract; overload; 525 procedure FillQuadPerspectiveMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); virtual; abstract; overload; 526 procedure FillQuadPerspectiveMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACleanBorders: TRect); virtual; abstract; overload; 527 procedure FillQuadPerspectiveMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); virtual; abstract; overload; 528 procedure FillQuadPerspectiveMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACleanBorders: TRect); virtual; abstract; overload; 529 530 procedure FillPolyLinearColor(const points: array of TPointF; AColors: array of TBGRAPixel); virtual; abstract; overload; 531 procedure FillPolyLinearMapping(const points: array of TPointF; texture: IBGRAScanner; texCoords: array of TPointF; TextureInterpolation: Boolean); virtual; abstract; overload; 532 procedure FillPolyLinearMappingLightness(const points: array of TPointF; texture: IBGRAScanner; texCoords: array of TPointF; lightnesses: array of word; TextureInterpolation: Boolean); virtual; abstract; overload; 533 procedure FillPolyPerspectiveMapping(const points: array of TPointF; const pointsZ: array of single; texture: IBGRAScanner; texCoords: array of TPointF; TextureInterpolation: Boolean; zbuffer: psingle = nil); virtual; abstract; overload; 534 procedure FillPolyPerspectiveMappingLightness(const points: array of TPointF; const pointsZ: array of single; texture: IBGRAScanner; texCoords: array of TPointF; lightnesses: array of word; TextureInterpolation: Boolean; zbuffer: psingle = nil); virtual; abstract; overload; 535 536 procedure FillPoly(const points: array of TPointF; c: TBGRAPixel; drawmode: TDrawMode); virtual; abstract; 537 procedure FillPoly(const points: array of TPointF; texture: IBGRAScanner; drawmode: TDrawMode); virtual; abstract; 538 procedure FillPolyAntialias(const points: array of TPointF; c: TBGRAPixel); virtual; abstract; 539 procedure FillPolyAntialias(const points: array of TPointF; texture: IBGRAScanner); virtual; abstract; 540 procedure ErasePoly(const points: array of TPointF; alpha: byte); virtual; abstract; 541 procedure ErasePolyAntialias(const points: array of TPointF; alpha: byte); virtual; abstract; 542 543 procedure FillShape(shape: TBGRACustomFillInfo; c: TBGRAPixel; drawmode: TDrawMode); virtual; abstract; 544 procedure FillShape(shape: TBGRACustomFillInfo; texture: IBGRAScanner; drawmode: TDrawMode); virtual; abstract; 545 procedure FillShapeAntialias(shape: TBGRACustomFillInfo; c: TBGRAPixel); virtual; abstract; 546 procedure FillShapeAntialias(shape: TBGRACustomFillInfo; texture: IBGRAScanner); virtual; abstract; 547 procedure EraseShape(shape: TBGRACustomFillInfo; alpha: byte); virtual; abstract; 548 procedure EraseShapeAntialias(shape: TBGRACustomFillInfo; alpha: byte); virtual; abstract; 549 550 procedure EllipseAntialias(x, y, rx, ry: single; c: TBGRAPixel; w: single); virtual; abstract; 551 procedure EllipseAntialias(x, y, rx, ry: single; texture: IBGRAScanner; w: single); virtual; abstract; 552 procedure EllipseAntialias(x, y, rx, ry: single; c: TBGRAPixel; w: single; back: TBGRAPixel); virtual; abstract; 553 procedure FillEllipseAntialias(x, y, rx, ry: single; c: TBGRAPixel); virtual; abstract; 554 procedure FillEllipseAntialias(x, y, rx, ry: single; texture: IBGRAScanner); virtual; abstract; 555 procedure FillEllipseLinearColorAntialias(x, y, rx, ry: single; outercolor, innercolor: TBGRAPixel); virtual; abstract; 556 procedure EraseEllipseAntialias(x, y, rx, ry: single; alpha: byte); virtual; abstract; 557 558 procedure Rectangle(x, y, x2, y2: integer; c: TBGRAPixel; mode: TDrawMode); virtual; abstract; overload; 559 procedure Rectangle(x, y, x2, y2: integer; BorderColor, FillColor: TBGRAPixel; mode: TDrawMode); virtual; abstract; overload; 560 procedure Rectangle(x, y, x2, y2: integer; c: TColor); virtual; overload; 561 procedure Rectangle(r: TRect; c: TBGRAPixel; mode: TDrawMode); virtual; overload; 562 procedure Rectangle(r: TRect; BorderColor, FillColor: TBGRAPixel; mode: TDrawMode); virtual;overload; 563 procedure Rectangle(r: TRect; c: TColor); virtual; overload; 564 procedure RectangleAntialias(x, y, x2, y2: single; c: TBGRAPixel; w: single); virtual; overload; 565 procedure RectangleAntialias(x, y, x2, y2: single; c: TBGRAPixel; w: single; back: TBGRAPixel); virtual; abstract; overload; 566 procedure RectangleAntialias(x, y, x2, y2: single; texture: IBGRAScanner; w: single); virtual; abstract; overload; 567 568 procedure RoundRect(X1, Y1, X2, Y2: integer; DX, DY: integer; BorderColor, FillColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); virtual; abstract; overload; 569 procedure RoundRect(X1, Y1, X2, Y2: integer; DX, DY: integer; BorderColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); virtual; abstract; overload; 570 procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; c: TBGRAPixel; w: single; options: TRoundRectangleOptions = []); virtual; abstract; 571 procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; pencolor: TBGRAPixel; w: single; fillcolor: TBGRAPixel; options: TRoundRectangleOptions = []); virtual; abstract; 572 procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; penTexture: IBGRAScanner; w: single; fillTexture: IBGRAScanner; options: TRoundRectangleOptions = []); virtual; abstract; 573 procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; texture: IBGRAScanner; w: single; options: TRoundRectangleOptions = []); virtual; abstract; 574 procedure FillRoundRect(X1, Y1, X2, Y2: integer; DX, DY: integer; FillColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); virtual; 575 procedure FillRoundRectAntialias(x,y,x2,y2,rx,ry: single; c: TBGRAPixel; options: TRoundRectangleOptions = []); virtual; abstract; 576 procedure FillRoundRectAntialias(x,y,x2,y2,rx,ry: single; texture: IBGRAScanner; options: TRoundRectangleOptions = []); virtual; abstract; 577 procedure EraseRoundRectAntialias(x,y,x2,y2,rx,ry: single; alpha: byte; options: TRoundRectangleOptions = []); virtual; abstract; 578 579 procedure EllipseInRect(r: TRect; BorderColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); virtual; overload; 580 procedure EllipseInRect(r: TRect; BorderColor,FillColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); virtual; overload; 581 procedure FillEllipseInRect(r: TRect; FillColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); virtual; 582 583 procedure FillRect(r: TRect; c: TColor); virtual; overload; 584 procedure FillRect(r: TRect; c: TBGRAPixel; mode: TDrawMode); virtual; overload; 585 procedure FillRect(r: TRect; texture: IBGRAScanner; mode: TDrawMode); virtual; overload; 586 procedure FillRect(x, y, x2, y2: integer; c: TColor); virtual; overload; 587 procedure FillRect(x, y, x2, y2: integer; c: TBGRAPixel; mode: TDrawMode); virtual; abstract; overload; 588 procedure FillRect(x, y, x2, y2: integer; texture: IBGRAScanner; mode: TDrawMode); virtual; abstract; overload; 589 procedure FillRectAntialias(x, y, x2, y2: single; c: TBGRAPixel); virtual; abstract; 590 procedure FillRectAntialias(x, y, x2, y2: single; texture: IBGRAScanner); virtual; abstract; 591 procedure EraseRectAntialias(x, y, x2, y2: single; alpha: byte); virtual; abstract; 592 procedure AlphaFillRect(x, y, x2, y2: integer; alpha: byte); virtual; abstract; 593 594 procedure TextOut(x, y: single; sUTF8: string; c: TBGRAPixel; align: TAlignment); virtual; abstract; overload; 595 procedure TextOut(x, y: single; sUTF8: string; texture: IBGRAScanner; align: TAlignment); virtual; abstract; overload; 596 procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; sUTF8: string; c: TBGRAPixel; align: TAlignment); virtual; abstract; 597 procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; sUTF8: string; texture: IBGRAScanner; align: TAlignment); virtual; abstract; 598 procedure TextRect(ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; c: TBGRAPixel); virtual; abstract; overload; 599 procedure TextRect(ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; texture: IBGRAScanner); virtual; abstract; overload; 600 function TextSize(sUTF8: string): TSize; virtual; abstract; 601 602 { Draw the UTF8 encoded string, (x,y) being the top-left corner. The color c or texture is used to fill the text. 603 The value of FontOrientation is taken into account, so that the text may be rotated. } 604 procedure TextOut(x, y: single; sUTF8: string; c: TBGRAPixel); virtual; overload; 605 procedure TextOut(x, y: single; sUTF8: string; c: TColor); virtual; overload; 606 procedure TextOut(x, y: single; sUTF8: string; texture: IBGRAScanner); virtual; overload; 607 608 { Draw the UTF8 encoded string in the rectangle ARect. Text is wrapped if necessary. 609 The position depends on the specified horizontal alignment halign and vertical alignement valign. 610 The color c or texture is used to fill the text. No rotation is applied. } 611 procedure TextRect(ARect: TRect; sUTF8: string; halign: TAlignment; valign: TTextLayout; c: TBGRAPixel); virtual; overload; 612 procedure TextRect(ARect: TRect; sUTF8: string; halign: TAlignment; valign: TTextLayout; texture: IBGRAScanner); virtual; overload; 613 614 {Spline} 615 function ComputeClosedSpline(const APoints: array of TPointF; AStyle: TSplineStyle): ArrayOfTPointF; virtual; abstract; 616 function ComputeOpenedSpline(const APoints: array of TPointF; AStyle: TSplineStyle): ArrayOfTPointF; virtual; abstract; 617 function ComputeBezierCurve(const curve: TCubicBezierCurve): ArrayOfTPointF; virtual; abstract; 618 function ComputeBezierCurve(const curve: TQuadraticBezierCurve): ArrayOfTPointF; virtual; abstract; 619 function ComputeBezierSpline(const spline: array of TCubicBezierCurve): ArrayOfTPointF; virtual; abstract; 620 function ComputeBezierSpline(const spline: array of TQuadraticBezierCurve): ArrayOfTPointF; virtual; abstract; 621 622 function ComputeWidePolyline(const points: array of TPointF; w: single): ArrayOfTPointF; virtual; abstract; 623 function ComputeWidePolyline(const points: array of TPointF; w: single; Closed: boolean): ArrayOfTPointF; virtual; abstract; 624 function ComputeWidePolygon(const points: array of TPointF; w: single): ArrayOfTPointF; virtual; abstract; 625 626 function ComputeEllipse(x,y,rx,ry: single): ArrayOfTPointF; deprecated; 627 function ComputeEllipse(x,y,rx,ry,w: single): ArrayOfTPointF; deprecated; 628 function ComputeEllipseContour(x,y,rx,ry: single; quality: single = 1): ArrayOfTPointF; virtual; abstract; 629 function ComputeEllipseBorder(x,y,rx,ry,w: single; quality: single = 1): ArrayOfTPointF; virtual; abstract; 630 function ComputeArc65536(x,y,rx,ry: single; start65536,end65536: word; quality: single = 1): ArrayOfTPointF; virtual; abstract; 631 function ComputeArcRad(x,y,rx,ry: single; startRad,endRad: single; quality: single = 1): ArrayOfTPointF; virtual; abstract; 632 function ComputeRoundRect(x1,y1,x2,y2,rx,ry: single; quality: single = 1): ArrayOfTPointF; virtual; abstract; 633 function ComputeRoundRect(x1,y1,x2,y2,rx,ry: single; options: TRoundRectangleOptions; quality: single = 1): ArrayOfTPointF; virtual; abstract; 634 function ComputePie65536(x,y,rx,ry: single; start65536,end65536: word; quality: single = 1): ArrayOfTPointF; virtual; abstract; 635 function ComputePieRad(x,y,rx,ry: single; startRad,endRad: single; quality: single = 1): ArrayOfTPointF; virtual; abstract; 636 637 {Filling} 638 procedure FillTransparent; virtual; 639 procedure NoClip; virtual; abstract; 640 procedure ApplyGlobalOpacity(alpha: byte); virtual; abstract; 641 procedure Fill(c: TColor); virtual; overload; 642 procedure Fill(c: TBGRAPixel); virtual; overload; 643 procedure Fill(texture: IBGRAScanner; mode: TDrawMode); virtual; abstract; overload; 644 procedure Fill(texture: IBGRAScanner); virtual; abstract; overload; 645 procedure Fill(c: TBGRAPixel; start, Count: integer); virtual; abstract; overload; 646 procedure DrawPixels(c: TBGRAPixel; start, Count: integer); virtual; abstract; 647 procedure AlphaFill(alpha: byte); virtual; overload; 648 procedure AlphaFill(alpha: byte; start, Count: integer); virtual; abstract; overload; 649 procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; color: TBGRAPixel); virtual; overload; 650 procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; texture: IBGRAScanner); virtual; overload; 651 procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; color: TBGRAPixel; ADrawMode: TDrawMode); virtual; abstract; overload; 652 procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; texture: IBGRAScanner; ADrawMode: TDrawMode); virtual; abstract; overload; 653 procedure FillClearTypeMask(x,y: integer; xThird: integer; AMask: TBGRACustomBitmap; color: TBGRAPixel; ARGBOrder: boolean = true); virtual; abstract; overload; 654 procedure FillClearTypeMask(x,y: integer; xThird: integer; AMask: TBGRACustomBitmap; texture: IBGRAScanner; ARGBOrder: boolean = true); virtual; abstract; overload; 655 procedure ReplaceColor(before, after: TColor); virtual; abstract; overload; 656 procedure ReplaceColor(before, after: TBGRAPixel); virtual; abstract; overload; 657 procedure ReplaceTransparent(after: TBGRAPixel); virtual; abstract; overload; 658 procedure FloodFill(X, Y: integer; Color: TBGRAPixel; 659 mode: TFloodfillMode; Tolerance: byte = 0); virtual; 660 procedure ParallelFloodFill(X, Y: integer; Dest: TBGRACustomBitmap; Color: TBGRAPixel; 661 mode: TFloodfillMode; Tolerance: byte = 0); virtual; abstract; 662 procedure GradientFill(x, y, x2, y2: integer; c1, c2: TBGRAPixel; 663 gtype: TGradientType; o1, o2: TPointF; mode: TDrawMode; 664 gammaColorCorrection: boolean = True; Sinus: Boolean=False); virtual; abstract; 665 procedure GradientFill(x, y, x2, y2: integer; gradient: TBGRACustomGradient; 666 gtype: TGradientType; o1, o2: TPointF; mode: TDrawMode; 667 Sinus: Boolean=False); virtual; abstract; 668 function CreateBrushTexture(ABrushStyle: TBrushStyle; APatternColor, ABackgroundColor: TBGRAPixel; 669 AWidth: integer = 8; AHeight: integer = 8; APenWidth: single = 1): TBGRACustomBitmap; virtual; abstract; 670 671 {Canvas drawing functions} 672 procedure DataDrawTransparent(ACanvas: TCanvas; Rect: TRect; 673 AData: Pointer; ALineOrder: TRawImageLineOrder; AWidth, AHeight: integer); virtual; abstract; 674 procedure DataDrawOpaque(ACanvas: TCanvas; Rect: TRect; AData: Pointer; 675 ALineOrder: TRawImageLineOrder; AWidth, AHeight: integer); virtual; abstract; 676 procedure GetImageFromCanvas(CanvasSource: TCanvas; x, y: integer); virtual; abstract; 677 procedure Draw(ACanvas: TCanvas; x, y: integer; Opaque: boolean = True); virtual; abstract; 678 procedure Draw(ACanvas: TCanvas; Rect: TRect; Opaque: boolean = True); virtual; abstract; 679 procedure DrawPart(ARect: TRect; Canvas: TCanvas; x, y: integer; Opaque: boolean); virtual; 680 function GetPart(ARect: TRect): TBGRACustomBitmap; virtual; abstract; 681 function GetPtrBitmap(Top,Bottom: Integer): TBGRACustomBitmap; virtual; abstract; 682 procedure InvalidateBitmap; virtual; abstract; //call if you modify with Scanline 683 procedure LoadFromBitmapIfNeeded; virtual; abstract; //call to ensure that bitmap data is up to date 684 685 {BGRA bitmap functions} 686 procedure CrossFade(ARect: TRect; Source1, Source2: IBGRAScanner; AFadePosition: byte; mode: TDrawMode = dmDrawWithTransparency); virtual; abstract; 687 procedure CrossFade(ARect: TRect; Source1, Source2: IBGRAScanner; AFadeMask: IBGRAScanner; mode: TDrawMode = dmDrawWithTransparency); virtual; abstract; 688 procedure PutImage(x, y: integer; Source: TBGRACustomBitmap; mode: TDrawMode; AOpacity: byte = 255); virtual; abstract; 689 procedure StretchPutImage(ARect: TRect; Source: TBGRACustomBitmap; mode: TDrawMode; AOpacity: byte = 255); virtual; abstract; 690 procedure PutImageSubpixel(x, y: single; Source: TBGRACustomBitmap); 691 procedure PutImagePart(x,y: integer; Source: TBGRACustomBitmap; SourceRect: TRect; mode: TDrawMode; AOpacity: byte = 255); 692 procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOpacity: Byte=255; ACorrectBlur: Boolean = false); overload; 693 procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AOpacity: Byte=255); overload; 694 procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOutputBounds: TRect; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255); virtual; abstract; overload; 695 procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOutputBounds: TRect; AOpacity: Byte=255; ACorrectBlur: Boolean = false); overload; 696 function GetImageAffineBounds(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap): TRect; 697 procedure PutImageAngle(x,y: single; Source: TBGRACustomBitmap; angle: single; AOutputBounds: TRect; imageCenterX: single = 0; imageCenterY: single = 0; AOpacity: Byte=255; ARestoreOffsetAfterRotation: boolean = false; ACorrectBlur: Boolean = false); overload; 698 procedure PutImageAngle(x,y: single; Source: TBGRACustomBitmap; angle: single; imageCenterX: single = 0; imageCenterY: single = 0; AOpacity: Byte=255; ARestoreOffsetAfterRotation: boolean = false; ACorrectBlur: Boolean = false); overload; 699 procedure PutImageAngle(x,y: single; Source: TBGRACustomBitmap; angle: single; AOutputBounds: TRect; AResampleFilter: TResampleFilter; imageCenterX: single = 0; imageCenterY: single = 0; AOpacity: Byte=255; ARestoreOffsetAfterRotation: boolean = false); overload; 700 procedure PutImageAngle(x,y: single; Source: TBGRACustomBitmap; angle: single; AResampleFilter: TResampleFilter; imageCenterX: single = 0; imageCenterY: single = 0; AOpacity: Byte=255; ARestoreOffsetAfterRotation: boolean = false); overload; 701 procedure ComputeImageAngleAxes(x,y,w,h,angle: single; imageCenterX,imageCenterY: single; ARestoreOffsetAfterRotation: boolean; 702 out Origin,HAxis,VAxis: TPointF); 703 function GetImageAngleBounds(x,y: single; Source: TBGRACustomBitmap; angle: single; imageCenterX: single = 0; imageCenterY: single = 0; ARestoreOffsetAfterRotation: boolean = false): TRect; 704 procedure BlendImage(x, y: integer; Source: TBGRACustomBitmap; operation: TBlendOperation); virtual; abstract; 705 procedure BlendImageOver(x, y: integer; Source: TBGRACustomBitmap; operation: TBlendOperation; AOpacity: byte = 255; 706 ALinearBlend: boolean = false); virtual; abstract; 707 function Duplicate(DuplicateProperties: Boolean = False): TBGRACustomBitmap; virtual; abstract; 708 function Equals(comp: TBGRACustomBitmap): boolean; virtual; abstract; 709 function Equals(comp: TBGRAPixel): boolean; virtual; abstract; 710 function Resample(newWidth, newHeight: integer; 711 mode: TResampleMode = rmFineResample): TBGRACustomBitmap; virtual; abstract; 712 procedure VerticalFlip; virtual; overload; 713 procedure VerticalFlip(ARect: TRect); virtual; abstract; overload; 714 procedure HorizontalFlip; virtual; overload; 715 procedure HorizontalFlip(ARect: TRect); virtual; abstract; overload; 716 function RotateCW: TBGRACustomBitmap; virtual; abstract; 717 function RotateCCW: TBGRACustomBitmap; virtual; abstract; 718 procedure Negative; virtual; abstract; 719 procedure NegativeRect(ABounds: TRect); virtual; abstract; 720 procedure LinearNegative; virtual; abstract; 721 procedure LinearNegativeRect(ABounds: TRect); virtual; abstract; 722 procedure InplaceGrayscale; virtual; abstract; 723 procedure InplaceGrayscale(ABounds: TRect); virtual; abstract; 724 procedure ConvertToLinearRGB; virtual; abstract; 725 procedure ConvertFromLinearRGB; virtual; abstract; 726 procedure SwapRedBlue; virtual; abstract; 727 procedure GrayscaleToAlpha; virtual; abstract; 728 procedure AlphaToGrayscale; virtual; abstract; 729 procedure ApplyMask(mask: TBGRACustomBitmap); overload; 730 procedure ApplyMask(mask: TBGRACustomBitmap; ARect: TRect); overload; 731 procedure ApplyMask(mask: TBGRACustomBitmap; ARect: TRect; AMaskRectTopLeft: TPoint); virtual; abstract; overload; 732 function GetImageBounds(Channel: TChannel = cAlpha; ANothingValue: Byte = 0): TRect; virtual; abstract; 733 function GetImageBounds(Channels: TChannels; ANothingValue: Byte = 0): TRect; virtual; abstract; 734 function GetDifferenceBounds(ABitmap: TBGRACustomBitmap): TRect; virtual; abstract; 735 function MakeBitmapCopy(BackgroundColor: TColor): TBitmap; virtual; abstract; 736 737 {Filters} 738 function FilterSmartZoom3(Option: TMedianOption): TBGRACustomBitmap; virtual; abstract; 739 function FilterMedian(Option: TMedianOption): TBGRACustomBitmap; virtual; abstract; 740 function FilterSmooth: TBGRACustomBitmap; virtual; abstract; 741 function FilterSharpen(Amount: single = 1): TBGRACustomBitmap; virtual; abstract; 742 function FilterSharpen(ABounds: TRect; Amount: single = 1): TBGRACustomBitmap; virtual; abstract; 743 function FilterContour: TBGRACustomBitmap; virtual; abstract; 744 function FilterPixelate(pixelSize: integer; useResample: boolean; filter: TResampleFilter = rfLinear): TBGRACustomBitmap; virtual; abstract; 745 function FilterBlurRadial(radius: integer; 746 blurType: TRadialBlurType): TBGRACustomBitmap; virtual; abstract; 747 function FilterBlurRadial(ABounds: TRect; radius: integer; 748 blurType: TRadialBlurType): TBGRACustomBitmap; virtual; abstract; 749 function FilterBlurMotion(distance: integer; angle: single; 750 oriented: boolean): TBGRACustomBitmap; virtual; abstract; 751 function FilterBlurMotion(ABounds: TRect; distance: integer; angle: single; 752 oriented: boolean): TBGRACustomBitmap; virtual; abstract; 753 function FilterCustomBlur(mask: TBGRACustomBitmap): TBGRACustomBitmap; virtual; abstract; 754 function FilterCustomBlur(ABounds: TRect; mask: TBGRACustomBitmap): TBGRACustomBitmap; virtual; abstract; 755 function FilterEmboss(angle: single): TBGRACustomBitmap; virtual; abstract; 756 function FilterEmboss(angle: single; ABounds: TRect): TBGRACustomBitmap; virtual; abstract; 757 function FilterEmbossHighlight(FillSelection: boolean): TBGRACustomBitmap; virtual; abstract; 758 function FilterEmbossHighlight(FillSelection: boolean; BorderColor: TBGRAPixel): TBGRACustomBitmap; virtual; abstract; 759 function FilterEmbossHighlight(FillSelection: boolean; BorderColor: TBGRAPixel; var Offset: TPoint): TBGRACustomBitmap; virtual; abstract; 760 function FilterGrayscale: TBGRACustomBitmap; virtual; abstract; 761 function FilterGrayscale(ABounds: TRect): TBGRACustomBitmap; virtual; abstract; 762 function FilterNormalize(eachChannel: boolean = True): TBGRACustomBitmap; virtual; abstract; 763 function FilterNormalize(ABounds: TRect; eachChannel: boolean = True): TBGRACustomBitmap; virtual; abstract; 764 function FilterRotate(origin: TPointF; angle: single; correctBlur: boolean = false): TBGRACustomBitmap; virtual; abstract; 765 function FilterSphere: TBGRACustomBitmap; virtual; abstract; 766 function FilterTwirl(ACenter: TPoint; ARadius: Single; ATurn: Single=1; AExponent: Single=3): TBGRACustomBitmap; virtual; abstract; 767 function FilterTwirl(ABounds: TRect; ACenter: TPoint; ARadius: Single; ATurn: Single=1; AExponent: Single=3): TBGRACustomBitmap; virtual; abstract; 768 function FilterCylinder: TBGRACustomBitmap; virtual; abstract; 769 function FilterPlane: TBGRACustomBitmap; virtual; abstract; 770 771 property Width: integer Read GetWidth; //width of the image in pixels 772 property Height: integer Read GetHeight; //height of the image in pixels 773 property NbPixels: integer Read GetNbPixels; //total number of pixels. It is always true that NbPixels = Width * Height 774 775 property ScanLine[y: integer]: PBGRAPixel Read GetScanLine; //Returns the address of the left-most pixel of any line. 776 //The parameter y ranges from 0 to Height-1. 777 778 property LineOrder: TRawImageLineOrder Read GetLineOrder; //Indicates the order in which lines are stored in memory. 779 //If it is equal to riloTopToBottom, the first line is the top line. 780 //If it is equal to riloBottomToTop, the first line is the bottom line. 781 782 property Data: PBGRAPixel Read GetDataPtr; //Provides a pointer to the first pixel in memory. 783 //Depending on the LineOrder property, this can be the top-left pixel or the bottom-left pixel. 784 //There is no padding between scanlines, so the start of the next line is at the address Data + Width. 785 786 property Empty: boolean Read CheckEmpty; //Returns True if the bitmap only contains transparent pixels or has a size of zero. 787 788 property HasTransparentPixels: boolean Read GetHasTransparentPixels; //Returns True if there are transparent or semitransparent pixels, 789 //and so if the image would be stored with an alpha channel. 790 791 property RefCount: integer Read GetRefCount; 792 property Bitmap: TBitmap Read GetBitmap; //don't forget to call InvalidateBitmap before if you changed something with Scanline 793 property AverageColor: TColor Read GetAverageColor; 794 property AveragePixel: TBGRAPixel Read GetAveragePixel; 795 property CanvasFP: TFPImageCanvas read GetCanvasFP; 796 property CanvasDrawModeFP: TDrawMode read GetCanvasDrawModeFP write SetCanvasDrawModeFP; 797 property Canvas: TCanvas Read GetCanvas; 798 property CanvasOpacity: byte Read GetCanvasOpacity Write SetCanvasOpacity; 799 property CanvasAlphaCorrection: boolean 800 Read GetCanvasAlphaCorrection Write SetCanvasAlphaCorrection; 801 802 property PenStyle: TPenStyle read GetPenStyle Write SetPenStyle; 803 property CustomPenStyle: TBGRAPenStyle read GetCustomPenStyle write SetCustomPenStyle; 804 property ClipRect: TRect read GetClipRect write SetClipRect; 805 806 { Specifies the height of the font without taking into account additional line spacing. 807 A negative value means that it is the full height instead (see below). } 808 property FontHeight: integer Read GetFontHeight Write SetFontHeight; 809 810 { Specifies the height of the font, taking into account the additional line spacing defined for the font. } 811 property FontFullHeight: integer read GetFontFullHeight write SetFontFullHeight; 812 813 property FontAntialias: Boolean read GetFontAntialias write SetFontAntialias; //Simplified property to specify the quality. 814 property FontPixelMetric: TFontPixelMetric read GetFontPixelMetric; //Returns measurement for the current font in pixels. 815 816 { Specifies the font renderer. By default it is an instance of TLCLFontRenderer of unit BGRAText. 817 Other renderers are provided in BGRATextFX unit and BGRAVectorize unit. 818 Once you assign a renderer, it will automatically be freed. 819 The renderers may provide additional styling for the font. } 820 property FontRenderer: TBGRACustomFontRenderer read GetFontRenderer write SetFontRenderer; 821 822 property LineCap: TPenEndCap read GetLineCap write SetLineCap; 823 property ArrowStartSize: TPointF read GetArrowStartSize write SetArrowStartSize; 824 property ArrowEndSize: TPointF read GetArrowEndSize write SetArrowEndSize; 825 property ArrowStartOffset: single read GetArrowStartOffset write SetArrowStartOffset; 826 property ArrowEndOffset: single read GetArrowEndOffset write SetArrowEndOffset; 827 property ArrowStartRepeat: integer read GetArrowStartRepeat write SetArrowStartRepeat; 828 property ArrowEndRepeat: integer read GetArrowEndRepeat write SetArrowEndRepeat; 829 830 //IBGRAScanner 831 function ScanAtInteger(X,Y: integer): TBGRAPixel; virtual; abstract; 832 procedure ScanMoveTo(X,Y: Integer); virtual; abstract; 833 function ScanNextPixel: TBGRAPixel; virtual; abstract; 834 function ScanAt(X,Y: Single): TBGRAPixel; virtual; abstract; 835 procedure ScanPutPixels(pdest: PBGRAPixel; count: integer; mode: TDrawMode); virtual; 836 function IsScanPutPixelsDefined: boolean; virtual; 837 838 protected 839 //interface 840 function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} IID: TGUID; out Obj): HResult; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 841 function _AddRef: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 842 function _Release: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 843 844 end; 845 846 { TBGRACustomScanner } 847 848 TBGRACustomScanner = class(IBGRAScanner) 849 private 850 FCurX,FCurY: integer; 851 public 852 function ScanAtInteger(X,Y: integer): TBGRAPixel; virtual; 853 procedure ScanMoveTo(X,Y: Integer); virtual; 854 function ScanNextPixel: TBGRAPixel; virtual; 855 function ScanAt(X,Y: Single): TBGRAPixel; virtual; abstract; 856 procedure ScanPutPixels(pdest: PBGRAPixel; count: integer; mode: TDrawMode); virtual; 857 function IsScanPutPixelsDefined: boolean; virtual; 858 protected 859 function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} IID: TGUID; out Obj): HResult; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 860 function _AddRef: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 861 function _Release: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 862 end; 863 864 { TBGRACustomGradient } 865 866 TBGRACustomGradient = class 867 public 868 function GetColorAt(position: integer): TBGRAPixel; virtual; abstract; 869 function GetColorAtF(position: single): TBGRAPixel; virtual; 870 function GetAverageColor: TBGRAPixel; virtual; abstract; 871 function GetMonochrome: boolean; virtual; abstract; 872 property Monochrome: boolean read GetMonochrome; 873 end; 874 875 { TIntersectionInfo } 876 877 TIntersectionInfo = class 878 interX: single; 879 winding: integer; 880 numSegment: integer; 881 procedure SetValues(AInterX: Single; AWinding, ANumSegment: integer); 882 end; 883 ArrayOfTIntersectionInfo = array of TIntersectionInfo; 884 885 TBGRACustomFillInfo = class 886 public 887 //returns true if the same segment number can be curved 888 function SegmentsCurved: boolean; virtual; abstract; 889 890 //returns integer bounds 891 function GetBounds: TRect; virtual; abstract; 892 893 //compute min-max to be drawn on destination bitmap according to cliprect. Returns false if 894 //there is nothing to draw 895 function ComputeMinMax(out minx,miny,maxx,maxy: integer; bmpDest: TBGRACustomBitmap): boolean; virtual; abstract; 896 897 //check if the point is inside the filling zone 898 function IsPointInside(x,y: single; windingMode: boolean): boolean; virtual; abstract; 899 900 //create an array that will contain computed intersections. 901 //you may augment, in this case, use CreateIntersectionInfo for new items 902 function CreateIntersectionArray: ArrayOfTIntersectionInfo; virtual; abstract; 903 function CreateIntersectionInfo: TIntersectionInfo; virtual; abstract; //creates a single info 904 procedure FreeIntersectionArray(var inter: ArrayOfTIntersectionInfo); virtual; abstract; 905 906 //fill a previously created array of intersections with actual intersections at the current y coordinate. 907 //nbInter gets the number of computed intersections 908 procedure ComputeAndSort(cury: single; var inter: ArrayOfTIntersectionInfo; out nbInter: integer; windingMode: boolean); virtual; abstract; 909 end; 910 911 { TBGRACustomFontRenderer } 912 913 TBGRACustomFontRenderer = class 914 FontName: string; //Specifies the font to use. Unless the font renderer accept otherwise, 915 //the name is in human readable form, like 'Arial', 'Times New Roman', ... 916 917 FontStyle: TFontStyles; //Specifies the set of styles to be applied to the font. 918 //These can be fsBold, fsItalic, fsStrikeOut, fsUnderline. 919 //So the value [fsBold,fsItalic] means that the font must be bold and italic. 920 921 FontQuality : TBGRAFontQuality;//Specifies the quality of rendering. Default value is fqSystem. 922 923 FontOrientation: integer; //Specifies the rotation of the text, for functions that support text rotation. 924 //It is expressed in tenth of degrees, positive values going counter-clockwise. 925 926 FontEmHeight: integer; // Specifies the height of the font without taking into account additional line spacing. 927 // A negative value means that it is the full height instead. 928 929 { Returns measurement for the current font in pixels. } 930 function GetFontPixelMetric: TFontPixelMetric; virtual; abstract; 931 932 { Returns the total size of the string provided using the current font. 933 Orientation is not taken into account, so that the width is along the text. } 934 function TextSize(sUTF8: string): TSize; virtual; abstract; 935 936 { Draws the UTF8 encoded string, with color c. 937 If align is taLeftJustify, (x,y) is the top-left corner. 938 If align is taCenter, (x,y) is at the top and middle of the text. 939 If align is taRightJustify, (x,y) is the top-right corner. 940 The value of FontOrientation is taken into account, so that the text may be rotated. } 941 procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; c: TBGRAPixel; align: TAlignment); virtual; abstract; 942 943 { Same as above functions, except that the text is filled using texture. 944 The value of FontOrientation is taken into account, so that the text may be rotated. } 945 procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; texture: IBGRAScanner; align: TAlignment); virtual; abstract; 946 947 { Same as above, except that the orientation is specified, overriding the value of the property FontOrientation. } 948 procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientationTenthDegCCW: integer; sUTF8: string; c: TBGRAPixel; align: TAlignment); virtual; abstract; 949 procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientationTenthDegCCW: integer; sUTF8: string; texture: IBGRAScanner; align: TAlignment); virtual; abstract; 950 951 { Draw the UTF8 encoded string at the coordinate (x,y), clipped inside the rectangle ARect. 952 Additional style information is provided by the style parameter. 953 The color c or texture is used to fill the text. No rotation is applied. } 954 procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; c: TBGRAPixel); virtual; abstract; 955 procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; texture: IBGRAScanner); virtual; abstract; 956 957 { Copy the path for the UTF8 encoded string into ADest. 958 If align is taLeftJustify, (x,y) is the top-left corner. 959 If align is taCenter, (x,y) is at the top and middle of the text. 960 If align is taRightJustify, (x,y) is the top-right corner. } 961 procedure CopyTextPathTo({%H-}ADest: IBGRAPath; {%H-}x, {%H-}y: single; {%H-}s: string; {%H-}align: TAlignment); virtual; //optional 962 end; 963 964 type 965 TBGRABitmapAny = class of TBGRACustomBitmap; //used to create instances of the same type (see NewBitmap) 966 TBGRATextOutImproveReadabilityMode = (irMask, irNormal, irClearTypeRGB, irClearTypeBGR); 967 968 var 969 BGRABitmapFactory : TBGRABitmapAny; 970 BGRATextOutImproveReadabilityProc : procedure (bmp: TBGRACustomBitmap; AFont: TFont; xf,yf: single; text: string; color: TBGRAPixel; tex: IBGRAScanner; align: TAlignment; mode : TBGRATextOutImproveReadabilityMode); 971 972 function CheckPutImageBounds(x, y, tx, ty: integer; out minxb, minyb, maxxb, maxyb, ignoreleft: integer; const cliprect: TRect): boolean; inline; 973 974 { Color functions } 975 function GetIntensity(const c: TExpandedPixel): word; inline; 976 function GetIntensity(c: TBGRAPixel): word; inline; 977 function SetIntensity(const c: TExpandedPixel; intensity: word): TExpandedPixel; 978 function SetIntensity(c: TBGRAPixel; intensity: word): TBGRAPixel; 979 function GetLightness(c: TBGRAPixel): word; 980 function GetLightness(const c: TExpandedPixel): word; inline; 981 function SetLightness(const c: TExpandedPixel; lightness: word): TExpandedPixel; 982 function SetLightness(c: TBGRAPixel; lightness: word): TBGRAPixel; 983 function SetLightness(const c: TExpandedPixel; lightness: word; curLightness: word): TExpandedPixel; //if you already know the current lightness of the color 984 function ApplyLightnessFast(color: TBGRAPixel; lightness: word): TBGRAPixel; inline; 985 function ApplyIntensityFast(color: TBGRAPixel; lightness: longword): TBGRAPixel; 986 function CombineLightness(lightness1,lightness2: Int32or64): Int32or64; 987 function BGRAToHSLA(c: TBGRAPixel): THSLAPixel; 988 function ExpandedToHSLA(const ec: TExpandedPixel): THSLAPixel; 989 function ExpandedToGSBA(ec: TExpandedPixel): TGSBAPixel; 990 function BGRAToGSBA(c: TBGRAPixel): TGSBAPixel; 991 function HSLAToExpanded(const c: THSLAPixel): TExpandedPixel; 992 function HSLAToBGRA(const c: THSLAPixel): TBGRAPixel; 993 function GtoH(ghue: word): word; 994 function HtoG(hue: word): word; 995 function HueDiff(h1, h2: word): word; 996 function GetHue(ec: TExpandedPixel): word; 997 function ColorImportance(ec: TExpandedPixel): word; 998 function GSBAToBGRA(c: TGSBAPixel): TBGRAPixel; 999 function GSBAToExpanded(c: TGSBAPixel): TExpandedPixel; 1000 function GSBAToHSLA(c: TGSBAPixel): THSLAPixel; 1001 function GammaExpansion(c: TBGRAPixel): TExpandedPixel; inline; 1002 function GammaCompression(const ec: TExpandedPixel): TBGRAPixel; inline; 1003 function GammaCompression(red,green,blue,alpha: word): TBGRAPixel; inline; 1004 function BGRAToGrayscale(c: TBGRAPixel): TBGRAPixel; 1005 function GrayscaleToBGRA(lightness: word): TBGRAPixel; 1006 function MergeBGRA(const colors: array of TBGRAPixel): TBGRAPixel; overload; 1007 function MergeBGRAWithGammaCorrection(c1: TBGRAPixel; weight1: byte; c2: TBGRAPixel; weight2: byte): TBGRAPixel; 1008 function MergeBGRA(c1, c2: TBGRAPixel): TBGRAPixel; overload; 1009 function MergeBGRA(c1: TBGRAPixel; weight1: integer; c2: TBGRAPixel; weight2: integer): TBGRAPixel; overload; 1010 function MergeBGRA(ec1, ec2: TExpandedPixel): TExpandedPixel; overload; 1011 function BGRA(red, green, blue, alpha: byte): TBGRAPixel; overload; inline; 1012 function BGRA(red, green, blue: byte): TBGRAPixel; overload; inline; 1013 function HSLA(hue, saturation, lightness, alpha: word): THSLAPixel; overload; inline; 1014 function HSLA(hue, saturation, lightness: word): THSLAPixel; overload; inline; 1015 function ColorToBGRA(color: TColor): TBGRAPixel; overload; 1016 function ColorToBGRA(color: TColor; opacity: byte): TBGRAPixel; overload; 1017 function BGRAToFPColor(AValue: TBGRAPixel): TFPColor; inline; 1018 function FPColorToBGRA(AValue: TFPColor): TBGRAPixel; 1019 function BGRAToColor(c: TBGRAPixel): TColor; 1020 operator = (const c1, c2: TBGRAPixel): boolean; inline; 1021 function ExpandedDiff(ec1, ec2: TExpandedPixel): word; 1022 function BGRAWordDiff(c1, c2: TBGRAPixel): word; 1023 function BGRADiff(c1, c2: TBGRAPixel): byte; 1024 operator - (const c1, c2: TColorF): TColorF; inline; 1025 operator + (const c1, c2: TColorF): TColorF; inline; 1026 operator * (const c1, c2: TColorF): TColorF; inline; 1027 operator * (const c1: TColorF; factor: single): TColorF; inline; 1028 function ColorF(red,green,blue,alpha: single): TColorF; 1029 function BGRAToStr(c: TBGRAPixel; AColorList: TBGRAColorList = nil; AMaxDiff: Word= 0): string; 1030 function StrToBGRA(str: string): TBGRAPixel; //full parse 1031 function StrToBGRA(str: string; const DefaultColor: TBGRAPixel): TBGRAPixel; //full parse with default when error or missing values 1032 function PartialStrToBGRA(str: string; const fallbackValues: TBGRAPixel; out error: boolean): TBGRAPixel; //partial parse allowed 1033 procedure TryStrToBGRA(str: string; var parsedValue: TBGRAPixel; out missingValues: boolean; out error: boolean); 1034 1035 { Get height [0..1] stored in a TBGRAPixel } 1036 function MapHeight(Color: TBGRAPixel): Single; 1037 1038 { Get TBGRAPixel to store height [0..1] } 1039 function MapHeightToBGRA(Height: Single; Alpha: Byte): TBGRAPixel; 1040 1041 1042 { Gamma conversion arrays. Should be used as readonly } 1043 var 1044 // TBGRAPixel -> TExpandedPixel 1045 GammaExpansionTab: packed array[0..255] of word; 1046 1047 // TExpandedPixel -> TBGRAPixel 1048 GammaCompressionTab: packed array[0..65535] of byte; 1049 1050 { Point functions } 1051 function PointF(x, y: single): TPointF; 1052 function PointsF(const pts: array of TPointF): ArrayOfTPointF; 1053 operator = (const pt1, pt2: TPointF): boolean; inline; 1054 operator - (const pt1, pt2: TPointF): TPointF; inline; 1055 operator - (const pt2: TPointF): TPointF; inline; 1056 operator + (const pt1, pt2: TPointF): TPointF; inline; 1057 operator * (const pt1, pt2: TPointF): single; inline; //scalar product 1058 operator * (const pt1: TPointF; factor: single): TPointF; inline; 1059 operator * (factor: single; const pt1: TPointF): TPointF; inline; 1060 function PtInRect(const pt: TPoint; r: TRect): boolean; overload; 1061 function RectWithSize(left,top,width,height: integer): TRect; 1062 function VectLen(dx,dy: single): single; overload; 1063 function VectLen(v: TPointF): single; overload; 1064 1065 { Line and polygon functions } 1066 type 1067 TLineDef = record 1068 origin, dir: TPointF; 1069 end; 1070 1071 function IntersectLine(line1, line2: TLineDef): TPointF; 1072 function IntersectLine(line1, line2: TLineDef; out parallel: boolean): TPointF; 1073 function IsConvex(const pts: array of TPointF; IgnoreAlign: boolean = true): boolean; 1074 function DoesQuadIntersect(pt1,pt2,pt3,pt4: TPointF): boolean; 1075 function DoesSegmentIntersect(pt1,pt2,pt3,pt4: TPointF): boolean; 1076 1077 { Cyclic functions } 1078 function PositiveMod(value, cycle: Int32or64): Int32or64; inline; overload; 1079 1080 { Sin65536 and Cos65536 are fast routines to compute sine and cosine as integer values. 1081 They use a table to store already computed values. The return value is an integer 1082 ranging from 0 to 65536, so the mean value is 32768 and the half amplitude is 1083 32768 instead of 1. The input has a period of 65536, so you can supply any integer 1084 without applying a modulo. } 1085 procedure PrecalcSin65536; // compute all values now 1086 function Sin65536(value: word): Int32or64; inline; 1087 function Cos65536(value: word): Int32or64; inline; 1088 function ByteSqrt(value: byte): byte; inline; 1089 1090 function DetectFileFormat(AFilenameUTF8: string): TBGRAImageFormat; 1091 function DetectFileFormat(AStream: TStream; ASuggestedExtensionUTF8: string = ''): TBGRAImageFormat; 1092 function SuggestImageFormat(AFilenameOrExtensionUTF8: string): TBGRAImageFormat; 1093 function CreateBGRAImageReader(AFormat: TBGRAImageFormat): TFPCustomImageReader; 1094 function CreateBGRAImageWriter(AFormat: TBGRAImageFormat; AHasTransparentPixels: boolean): TFPCustomImageWriter; 441 {** Detect the file format of a given file } 442 function DetectFileFormat(AFilenameUTF8: string): TBGRAImageFormat; 443 {** Detect the file format of a given stream. ''ASuggestedExtensionUTF8'' can 444 be provided to guess the format } 445 function DetectFileFormat(AStream: TStream; ASuggestedExtensionUTF8: string = ''): TBGRAImageFormat; 446 {** Returns the file format that is most likely to be stored in the 447 given filename (according to its extension) } 448 function SuggestImageFormat(AFilenameOrExtensionUTF8: string): TBGRAImageFormat; 449 {** Returns a likely image extension for the format } 450 function SuggestImageExtension(AFormat: TBGRAImageFormat): string; 451 {** Create an image reader for the given format } 452 function CreateBGRAImageReader(AFormat: TBGRAImageFormat): TFPCustomImageReader; 453 {** Create an image writer for the given format. ''AHasTransparentPixels'' 454 specifies if alpha channel must be supported } 455 function CreateBGRAImageWriter(AFormat: TBGRAImageFormat; AHasTransparentPixels: boolean): TFPCustomImageWriter; 456 457 {$DEFINE INCLUDE_INTERFACE} 458 {$I bgracustombitmap.inc} 1095 459 1096 460 implementation 1097 461 1098 uses Math, SysUtils, FileUtil, lazutf8classes, LCLProc,462 uses Math, SysUtils, BGRAUTF8, 1099 463 FPReadTiff, FPReadXwd, FPReadXPM, 1100 FPWriteTiff, FPWriteJPEG, FPWritePNG, FPWriteBMP, FPWritePCX,464 FPWriteTiff, FPWriteJPEG, BGRAWritePNG, FPWriteBMP, FPWritePCX, 1101 465 FPWriteTGA, FPWriteXPM; 466 467 {$DEFINE INCLUDE_IMPLEMENTATION} 468 {$I geometrytypes.inc} 469 470 {$DEFINE INCLUDE_IMPLEMENTATION} 471 {$I csscolorconst.inc} 472 473 {$DEFINE INCLUDE_IMPLEMENTATION} 474 {$I bgracustombitmap.inc} 475 476 {$DEFINE INCLUDE_IMPLEMENTATION} 477 {$I bgrapixel.inc} 478 479 function CleanTextOutString(s: string): string; 480 var idxIn, idxOut: integer; 481 begin 482 setlength(result, length(s)); 483 idxIn := 1; 484 idxOut := 1; 485 while IdxIn <= length(s) do 486 begin 487 if not (s[idxIn] in[#13,#10,#9]) then //those characters are always 1 byte long so it is the same with UTF8 488 begin 489 result[idxOut] := s[idxIn]; 490 inc(idxOut); 491 end; 492 inc(idxIn); 493 end; 494 setlength(result, idxOut-1); 495 end; 496 497 function RemoveLineEnding(var s: string; indexByte: integer): boolean; 498 begin //we can ignore UTF8 character length because #13 and #10 are always 1 byte long 499 //so this function can be applied to UTF8 strings as well 500 result := false; 501 if length(s) >= indexByte then 502 begin 503 if s[indexByte] in[#13,#10] then 504 begin 505 result := true; 506 if length(s) >= indexByte+1 then 507 begin 508 if (s[indexByte+1] <> s[indexByte]) and (s[indexByte+1] in[#13,#10]) then 509 delete(s,indexByte,2) 510 else 511 delete(s,indexByte,1); 512 end 513 else 514 delete(s,indexByte,1); 515 end; 516 end; 517 end; 518 519 function RemoveLineEndingUTF8(var sUTF8: string; indexUTF8: integer): boolean; 520 var indexByte: integer; 521 pIndex: PChar; 522 begin 523 pIndex := UTF8CharStart(@sUTF8[1],length(sUTF8),indexUTF8); 524 if pIndex = nil then 525 begin 526 result := false; 527 exit; 528 end; 529 indexByte := pIndex - @sUTF8[1]; 530 result := RemoveLineEnding(sUTF8, indexByte); 531 end; 532 533 procedure BGRADefaultWordBreakHandler(var ABefore, AAfter: string); 534 var p: integer; 535 begin 536 if (AAfter <> '') and (ABefore <> '') and (AAfter[1]<> ' ') and (ABefore[length(ABefore)] <> ' ') then 537 begin 538 p := length(ABefore); 539 while (p > 1) and (ABefore[p-1] <> ' ') do dec(p); 540 if p > 1 then //can put the word after 541 begin 542 AAfter := copy(ABefore,p,length(ABefore)-p+1)+AAfter; 543 ABefore := copy(ABefore,1,p-1); 544 end else 545 begin //cannot put the word after, so before 546 547 end; 548 end; 549 while (ABefore <> '') and (ABefore[length(ABefore)] =' ') do delete(ABefore,length(ABefore),1); 550 while (AAfter <> '') and (AAfter[1] =' ') do delete(AAfter,1,1); 551 end; 552 1102 553 1103 554 function StrToResampleFilter(str: string): TResampleFilter; … … 1114 565 end; 1115 566 1116 function StrToBlendOperation(str: string): TBlendOperation;1117 var op: TBlendOperation;1118 begin1119 result := boTransparent;1120 str := LowerCase(str);1121 for op := low(TBlendOperation) to high(TBlendOperation) do1122 if str = LowerCase(BlendOperationStr[op]) then1123 begin1124 result := op;1125 exit;1126 end;1127 end;1128 1129 function StrToGradientType(str: string): TGradientType;1130 var gt: TGradientType;1131 begin1132 result := gtLinear;1133 str := LowerCase(str);1134 for gt := low(TGradientType) to high(TGradientType) do1135 if str = LowerCase(GradientTypeStr[gt]) then1136 begin1137 result := gt;1138 exit;1139 end;1140 end;1141 1142 { Make a pen style. Need an even number of values. See TBGRAPenStyle }1143 function BGRAPenStyle(dash1, space1: single; dash2: single; space2: single;1144 dash3: single; space3: single; dash4: single; space4: single): TBGRAPenStyle;1145 var1146 i: Integer;1147 begin1148 if dash4 <> 0 then1149 begin1150 setlength(result,8);1151 result[6] := dash4;1152 result[7] := space4;1153 result[4] := dash3;1154 result[5] := space3;1155 result[2] := dash2;1156 result[3] := space2;1157 end else1158 if dash3 <> 0 then1159 begin1160 setlength(result,6);1161 result[4] := dash3;1162 result[5] := space3;1163 result[2] := dash2;1164 result[3] := space2;1165 end else1166 if dash2 <> 0 then1167 begin1168 setlength(result,4);1169 result[2] := dash2;1170 result[3] := space2;1171 end else1172 begin1173 setlength(result,2);1174 end;1175 result[0] := dash1;1176 result[1] := space1;1177 for i := 0 to high(result) do1178 if result[i]=0 then1179 raise exception.Create('Zero is not a valid value');1180 end;1181 1182 { Bézier curves definitions. See : http://en.wikipedia.org/wiki/B%C3%A9zier_curve }1183 1184 function ConcatPointsF(const APolylines: array of ArrayOfTPointF1185 ): ArrayOfTPointF;1186 var1187 i,pos,count:integer;1188 j: Integer;1189 begin1190 count := 0;1191 for i := 0 to high(APolylines) do1192 inc(count,length(APolylines[i]));1193 setlength(result,count);1194 pos := 0;1195 for i := 0 to high(APolylines) do1196 for j := 0 to high(APolylines[i]) do1197 begin1198 result[pos] := APolylines[i][j];1199 inc(pos);1200 end;1201 end;1202 1203 operator-(const v: TPoint3D): TPoint3D;1204 begin1205 result.x := -v.x;1206 result.y := -v.y;1207 result.z := -v.z;1208 end;1209 1210 operator + (const v1,v2: TPoint3D): TPoint3D; inline;1211 begin1212 result.x := v1.x+v2.x;1213 result.y := v1.y+v2.y;1214 result.z := v1.z+v2.z;1215 end;1216 1217 operator - (const v1,v2: TPoint3D): TPoint3D; inline;1218 begin1219 result.x := v1.x-v2.x;1220 result.y := v1.y-v2.y;1221 result.z := v1.z-v2.z;1222 end;1223 1224 operator * (const v1: TPoint3D; const factor: single): TPoint3D; inline;1225 begin1226 result.x := v1.x*factor;1227 result.y := v1.y*factor;1228 result.z := v1.z*factor;1229 end;1230 1231 function Point3D(x, y, z: single): TPoint3D;1232 begin1233 result.x := x;1234 result.y := y;1235 result.z := z;1236 end;1237 1238 operator=(const v1, v2: TPoint3D): boolean;1239 begin1240 result := (v1.x=v2.x) and (v1.y=v2.y) and (v1.z=v2.z);1241 end;1242 1243 operator * (const v1,v2: TPoint3D): single; inline;1244 begin1245 result := v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;1246 end;1247 1248 procedure Normalize3D(var v: TPoint3D); inline;1249 var len: double;1250 begin1251 len := v*v;1252 if len = 0 then exit;1253 len := sqrt(len);1254 v.x /= len;1255 v.y /= len;1256 v.z /= len;1257 end;1258 1259 procedure VectProduct3D(u,v: TPoint3D; out w: TPoint3D);1260 begin1261 w.x := u.y*v.z-u.z*v.y;1262 w.y := u.z*v.x-u.x*v.z;1263 w.z := u.x*v.Y-u.y*v.x;1264 end;1265 1266 // Define a Bézier curve with two control points.1267 function BezierCurve(origin, control1, control2, destination: TPointF): TCubicBezierCurve;1268 begin1269 result.p1 := origin;1270 result.c1 := control1;1271 result.c2 := control2;1272 result.p2 := destination;1273 end;1274 1275 // Define a Bézier curve with one control point.1276 function BezierCurve(origin, control, destination: TPointF1277 ): TQuadraticBezierCurve;1278 begin1279 result.p1 := origin;1280 result.c := control;1281 result.p2 := destination;1282 end;1283 1284 //straight line1285 function BezierCurve(origin, destination: TPointF): TQuadraticBezierCurve;1286 begin1287 result.p1 := origin;1288 result.c := (origin+destination)*0.5;1289 result.p2 := destination;1290 end;1291 1292 function ArcDef(cx, cy, rx, ry, xAngleRadCW, startAngleRadCW, endAngleRadCW: single;1293 anticlockwise: boolean): TArcDef;1294 begin1295 result.center := PointF(cx,cy);1296 result.radius := PointF(rx,ry);1297 result.xAngleRadCW:= xAngleRadCW;1298 result.startAngleRadCW := startAngleRadCW;1299 result.endAngleRadCW:= endAngleRadCW;1300 result.anticlockwise:= anticlockwise;1301 end;1302 1303 { Check if a PointF structure is empty or should be treated as a list separator }1304 function isEmptyPointF(pt: TPointF): boolean;1305 begin1306 Result := (pt.x = EmptySingle) and (pt.y = EmptySingle);1307 end;1308 1309 567 { TBGRACustomFontRenderer } 1310 568 1311 569 procedure TBGRACustomFontRenderer.CopyTextPathTo(ADest: IBGRAPath; x, y: single; s: string; align: TAlignment); 1312 begin 1313 end; 1314 1315 { TIntersectionInfo } 1316 1317 procedure TIntersectionInfo.SetValues(AInterX: Single; AWinding, 1318 ANumSegment: integer); 1319 begin 1320 interX := AInterX; 1321 winding := AWinding; 1322 numSegment := ANumSegment; 1323 end; 1324 1325 { TBGRACustomGradient } 1326 1327 function TBGRACustomGradient.GetColorAtF(position: single): TBGRAPixel; 1328 begin 1329 position *= 65536; 1330 if position < low(integer) then 1331 result := GetColorAt(low(Integer)) 1332 else if position > high(integer) then 1333 result := GetColorAt(high(Integer)) 1334 else 1335 result := GetColorAt(round(position)); 1336 end; 1337 1338 { TBGRAColorList } 1339 1340 function TBGRAColorList.GetByIndex(Index: integer): TBGRAPixel; 1341 begin 1342 if (Index < 0) or (Index >= FNbColors) then 1343 result := BGRAPixelTransparent 1344 else 1345 result := FColors[Index].Color; 1346 end; 1347 1348 function TBGRAColorList.GetByName(Name: string): TBGRAPixel; 1349 var i: integer; 1350 begin 1351 i := IndexOf(Name); 1352 if i = -1 then 1353 result := BGRAPixelTransparent 1354 else 1355 result := FColors[i].Color; 1356 end; 1357 1358 function TBGRAColorList.GetName(Index: integer): string; 1359 begin 1360 if (Index < 0) or (Index >= FNbColors) then 1361 result := '' 1362 else 1363 result := FColors[Index].Name; 1364 end; 1365 1366 constructor TBGRAColorList.Create; 1367 begin 1368 FNbColors:= 0; 1369 FColors := nil; 1370 FFinished:= false; 1371 end; 1372 1373 procedure TBGRAColorList.Add(Name: string; const Color: TBGRAPixel); 1374 begin 1375 if FFinished then 1376 raise Exception.Create('This list is already finished'); 1377 if length(FColors) = FNbColors then 1378 SetLength(FColors, FNbColors*2+1); 1379 FColors[FNbColors].Name := Name; 1380 FColors[FNbColors].Color := Color; 1381 inc(FNbColors); 1382 end; 1383 1384 procedure TBGRAColorList.Finished; 1385 begin 1386 if FFinished then exit; 1387 FFinished := true; 1388 SetLength(FColors, FNbColors); 1389 end; 1390 1391 function TBGRAColorList.IndexOf(Name: string): integer; 1392 var i: integer; 1393 begin 1394 for i := 0 to FNbColors-1 do 1395 if CompareText(Name, FColors[i].Name) = 0 then 1396 begin 1397 result := i; 1398 exit; 1399 end; 1400 result := -1; 1401 end; 1402 1403 function TBGRAColorList.IndexOfColor(const AColor: TBGRAPixel; AMaxDiff: Word = 0): integer; 1404 var i: integer; 1405 MinDiff,CurDiff: Word; 1406 begin 1407 if AMaxDiff = 0 then 1408 begin 1409 for i := 0 to FNbColors-1 do 1410 if AColor = FColors[i].Color then 1411 begin 1412 result := i; 1413 exit; 1414 end; 1415 result := -1; 1416 end else 1417 begin 1418 MinDiff := AMaxDiff; 1419 result := -1; 1420 for i := 0 to FNbColors-1 do 1421 begin 1422 CurDiff := BGRAWordDiff(AColor,FColors[i].Color); 1423 if CurDiff <= MinDiff then 1424 begin 1425 result := i; 1426 MinDiff := CurDiff; 1427 if MinDiff = 0 then exit; 1428 end; 1429 end; 1430 end; 1431 end; 1432 1433 { TBGRACustomBitmap } 1434 1435 function TBGRACustomBitmap.GetFontAntialias: Boolean; 1436 begin 1437 result := FontQuality <> fqSystem; 1438 end; 1439 1440 procedure TBGRACustomBitmap.SetFontAntialias(const AValue: Boolean); 1441 begin 1442 if AValue and not FontAntialias then 1443 FontQuality := fqFineAntialiasing 1444 else if not AValue and (FontQuality <> fqSystem) then 1445 FontQuality := fqSystem; 1446 end; 1447 1448 { These declaration make sure that these methods are virtual } 1449 procedure TBGRACustomBitmap.LoadFromFile(const filename: string); 1450 begin 1451 LoadFromFileUTF8(SysToUtf8(filename)); 1452 end; 1453 1454 procedure TBGRACustomBitmap.LoadFromFileUTF8(const filenameUTF8: string); 1455 var 1456 Stream: TStream; 1457 format: TBGRAImageFormat; 1458 reader: TFPCustomImageReader; 1459 begin 1460 stream := TFileStreamUTF8.Create(filenameUTF8,fmOpenRead or fmShareDenyWrite); 1461 try 1462 format := DetectFileFormat(Stream, ExtractFileExt(filenameUTF8)); 1463 reader := CreateBGRAImageReader(format); 1464 try 1465 LoadFromStream(stream, reader); 1466 finally 1467 reader.Free; 1468 end; 1469 finally 1470 ClearTransparentPixels; 1471 stream.Free; 1472 end; 1473 end; 1474 1475 procedure TBGRACustomBitmap.LoadFromFileUTF8(const filenameUTF8: string; 1476 AHandler: TFPCustomImageReader); 1477 var 1478 Stream: TStream; 1479 begin 1480 stream := TFileStreamUTF8.Create(filenameUTF8,fmOpenRead or fmShareDenyWrite); 1481 try 1482 LoadFromStream(stream, AHandler); 1483 finally 1484 ClearTransparentPixels; 1485 stream.Free; 1486 end; 1487 end; 1488 1489 procedure TBGRACustomBitmap.SaveToFile(const filename: string); 1490 begin 1491 SaveToFileUTF8(SysToUtf8(filename)); 1492 end; 1493 1494 procedure TBGRACustomBitmap.SaveToFileUTF8(const filenameUTF8: string); 1495 var 1496 writer: TFPCustomImageWriter; 1497 format: TBGRAImageFormat; 1498 begin 1499 format := SuggestImageFormat(filenameUTF8); 1500 writer := CreateBGRAImageWriter(Format, HasTransparentPixels); 1501 try 1502 SaveToFileUTF8(filenameUTF8, writer); 1503 finally 1504 writer.free; 1505 end; 1506 end; 1507 1508 procedure TBGRACustomBitmap.SaveToFile(const filename: string; 1509 Handler: TFPCustomImageWriter); 1510 begin 1511 SaveToFileUTF8(SysToUtf8(filename),Handler); 1512 end; 1513 1514 procedure TBGRACustomBitmap.SaveToFileUTF8(const filenameUTF8: string; 1515 Handler: TFPCustomImageWriter); 1516 var 1517 stream: TFileStreamUTF8; 1518 begin 1519 stream := TFileStreamUTF8.Create(filenameUTF8,fmCreate); 1520 try 1521 SaveToStream(stream, Handler); 1522 finally 1523 stream.Free; 1524 end; 1525 end; 1526 1527 procedure TBGRACustomBitmap.SaveToStreamAs(Str: TStream; 1528 AFormat: TBGRAImageFormat); 1529 var handler: TFPCustomImageWriter; 1530 begin 1531 handler := CreateBGRAImageWriter(AFormat, HasTransparentPixels); 1532 try 1533 SaveToStream(Str, handler) 1534 finally 1535 handler.Free; 1536 end; 1537 end; 1538 1539 procedure TBGRACustomBitmap.DrawPixel(x, y: int32or64; c: TBGRAPixel; 1540 ADrawMode: TDrawMode); 1541 begin 1542 case ADrawMode of 1543 dmSet: SetPixel(x,y,c); 1544 dmSetExceptTransparent: if c.alpha = 255 then SetPixel(x,y,c); 1545 dmLinearBlend: FastBlendPixel(x,y,c); 1546 dmDrawWithTransparency: DrawPixel(x,y,c); 1547 dmXor: XorPixel(x,y,c); 1548 end; 1549 end; 1550 1551 procedure TBGRACustomBitmap.LoadFromStream(Str: TStream); 1552 var 1553 format: TBGRAImageFormat; 1554 reader: TFPCustomImageReader; 1555 begin 1556 format := DetectFileFormat(Str); 1557 reader := CreateBGRAImageReader(format); 1558 try 1559 LoadFromStream(Str,reader); 1560 finally 1561 reader.Free; 1562 end; 1563 end; 1564 1565 { LoadFromStream uses TFPCustomImage routine, which uses 1566 Colors property to access pixels. That's why the 1567 FP drawing mode is temporarily changed to load 1568 bitmaps properly } 1569 procedure TBGRACustomBitmap.LoadFromStream(Str: TStream; 1570 Handler: TFPCustomImageReader); 1571 var 1572 OldDrawMode: TDrawMode; 1573 begin 1574 OldDrawMode := CanvasDrawModeFP; 1575 CanvasDrawModeFP := dmSet; 1576 try 1577 inherited LoadFromStream(Str, Handler); 1578 finally 1579 CanvasDrawModeFP := OldDrawMode; 1580 end; 1581 end; 1582 1583 { Look for a pixel considering the bitmap is repeated in both directions } 1584 function TBGRACustomBitmap.GetPixelCycle(x, y: int32or64): TBGRAPixel; 1585 begin 1586 if (Width = 0) or (Height = 0) then 1587 Result := BGRAPixelTransparent 1588 else 1589 Result := (Scanline[PositiveMod(y,Height)] + PositiveMod(x,Width))^; 1590 end; 1591 1592 procedure TBGRACustomBitmap.DrawHorizLine(x, y, x2: int32or64; 1593 texture: IBGRAScanner); 1594 begin 1595 HorizLine(x,y,x2,texture,dmDrawWithTransparency); 1596 end; 1597 1598 procedure TBGRACustomBitmap.HorizLine(x, y, x2: Int32or64; c: TBGRAPixel; 1599 ADrawMode: TDrawMode); 1600 begin 1601 case ADrawMode of 1602 dmSet: SetHorizLine(x,y,x2,c); 1603 dmSetExceptTransparent: if c.alpha = 255 then SetHorizLine(x,y,x2,c); 1604 dmXor: XorHorizLine(x,y,x2,c); 1605 dmLinearBlend: FastBlendHorizLine(x,y,x2,c); 1606 dmDrawWithTransparency: DrawHorizLine(x,y,x2,c); 1607 end; 1608 end; 1609 1610 procedure TBGRACustomBitmap.VertLine(x, y, y2: Int32or64; c: TBGRAPixel; 1611 ADrawMode: TDrawMode); 1612 begin 1613 case ADrawMode of 1614 dmSet: SetVertLine(x,y,y2,c); 1615 dmSetExceptTransparent: if c.alpha = 255 then SetVertLine(x,y,y2,c); 1616 dmXor: XorVertLine(x,y,y2,c); 1617 dmLinearBlend: FastBlendVertLine(x,y,y2,c); 1618 dmDrawWithTransparency: DrawVertLine(x,y,y2,c); 1619 end; 1620 end; 1621 1622 procedure TBGRACustomBitmap.ArrowStartAsNone; 1623 begin 1624 SetArrowStart(asNone); 1625 end; 1626 1627 procedure TBGRACustomBitmap.ArrowStartAsClassic(AFlipped: boolean; ACut: boolean; ARelativePenWidth: single); 1628 var join: TPenJoinStyle; 1629 begin 1630 if (LineCap = pecRound) and not ACut then join := pjsRound else join := pjsMiter; 1631 if ACut then 1632 begin 1633 if AFlipped then 1634 SetArrowStart(asFlippedCut,join,ARelativePenWidth) 1635 else 1636 SetArrowStart(asCut,join,ARelativePenWidth) 1637 end 1638 else 1639 begin 1640 if AFlipped then 1641 SetArrowStart(asFlipped,join,ARelativePenWidth) 1642 else 1643 SetArrowStart(asNormal,join,ARelativePenWidth) 1644 end; 1645 end; 1646 1647 procedure TBGRACustomBitmap.ArrowStartAsTriangle(ABackOffset: single; ARounded: boolean; AHollow: boolean; 1648 AHollowPenWidth: single); 1649 var join: TPenJoinStyle; 1650 begin 1651 if ARounded then join := pjsRound else join := pjsMiter; 1652 if AHollow then 1653 SetArrowStart(asHollowTriangle, join,AHollowPenWidth, ABackOffset) 1654 else 1655 SetArrowStart(asTriangle, join,1,ABackOffset); 1656 end; 1657 1658 procedure TBGRACustomBitmap.ArrowStartAsTail; 1659 begin 1660 SetArrowStart(asTail); 1661 end; 1662 1663 procedure TBGRACustomBitmap.ArrowEndAsNone; 1664 begin 1665 SetArrowEnd(asNone); 1666 end; 1667 1668 procedure TBGRACustomBitmap.ArrowEndAsClassic(AFlipped: boolean; ACut: boolean; ARelativePenWidth: single); 1669 var join: TPenJoinStyle; 1670 begin 1671 if (LineCap = pecRound) and not ACut then join := pjsRound else join := pjsMiter; 1672 if ACut then 1673 begin 1674 if AFlipped then 1675 SetArrowEnd(asFlippedCut,join,ARelativePenWidth) 1676 else 1677 SetArrowEnd(asCut,join,ARelativePenWidth) 1678 end 1679 else 1680 begin 1681 if AFlipped then 1682 SetArrowEnd(asFlipped,join,ARelativePenWidth) 1683 else 1684 SetArrowEnd(asNormal,join,ARelativePenWidth) 1685 end; 1686 end; 1687 1688 procedure TBGRACustomBitmap.ArrowEndAsTriangle(ABackOffset: single; ARounded: boolean; AHollow: boolean; 1689 AHollowPenWidth: single); 1690 var join: TPenJoinStyle; 1691 begin 1692 if ARounded then join := pjsRound else join := pjsMiter; 1693 if AHollow then 1694 SetArrowEnd(asHollowTriangle, join,AHollowPenWidth, ABackOffset) 1695 else 1696 SetArrowEnd(asTriangle, join,1, ABackOffset); 1697 end; 1698 1699 procedure TBGRACustomBitmap.ArrowEndAsTail; 1700 begin 1701 SetArrowEnd(asTail); 1702 end; 1703 1704 procedure TBGRACustomBitmap.DrawPolyLine(const points: array of TPoint; 1705 c: TBGRAPixel; DrawLastPixel: boolean; ADrawMode: TDrawMode); 1706 var i: integer; 1707 begin 1708 if length(points) = 1 then 1709 begin 1710 if DrawLastPixel then DrawPixel(points[0].x,points[0].y,c,ADrawMode); 1711 end 1712 else 1713 for i := 0 to high(points)-1 do 1714 DrawLine(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,c,DrawLastPixel and (i=high(points)-1),ADrawMode); 1715 end; 1716 1717 { Pixel polylines are constructed by concatenation } 1718 procedure TBGRACustomBitmap.DrawPolyLineAntialias(const points: array of TPoint; 1719 c: TBGRAPixel; DrawLastPixel: boolean); 1720 var i: integer; 1721 begin 1722 if length(points) = 1 then 1723 begin 1724 if DrawLastPixel then DrawLineAntialias(points[0].x,points[0].y,points[0].x,points[0].y,c,true); 1725 end 1726 else 1727 for i := 0 to high(points)-1 do 1728 DrawLineAntialias(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,c,DrawLastPixel and (i=high(points)-1)); 1729 end; 1730 1731 procedure TBGRACustomBitmap.DrawPolyLineAntialias(const points: array of TPoint; c1, 1732 c2: TBGRAPixel; dashLen: integer; DrawLastPixel: boolean); 1733 var i: integer; 1734 DashPos: integer; 1735 begin 1736 DashPos := 0; 1737 if length(points) = 1 then 1738 begin 1739 if DrawLastPixel then DrawPixel(points[0].x,points[0].y,c1); 1740 end 1741 else 1742 for i := 0 to high(points)-1 do 1743 DrawLineAntialias(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,c1,c2,dashLen,DrawLastPixel and (i=high(points)-1),DashPos); 1744 end; 1745 1746 procedure TBGRACustomBitmap.DrawPolygon(const points: array of TPoint; 1747 c: TBGRAPixel; ADrawMode: TDrawMode); 1748 var i: integer; 1749 begin 1750 if length(points) = 1 then 1751 begin 1752 DrawPixel(points[0].x,points[0].y,c,ADrawMode); 1753 end 1754 else 1755 begin 1756 for i := 0 to high(points)-1 do 1757 DrawLine(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,c,false,ADrawMode); 1758 DrawLine(points[high(points)].x,points[high(points)].Y,points[0].x,points[0].y,c,false,ADrawMode); 1759 end; 1760 end; 1761 1762 procedure TBGRACustomBitmap.DrawPolygonAntialias(const points: array of TPoint; 1763 c: TBGRAPixel); 1764 var i: integer; 1765 begin 1766 if length(points) = 1 then 1767 begin 1768 DrawLineAntialias(points[0].x,points[0].y,points[0].x,points[0].y,c,true); 1769 end 1770 else 1771 begin 1772 for i := 0 to high(points)-1 do 1773 DrawLineAntialias(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,c,false); 1774 DrawLineAntialias(points[high(points)].x,points[high(points)].Y,points[0].x,points[0].y,c,false); 1775 end; 1776 end; 1777 1778 procedure TBGRACustomBitmap.ErasePolyLine(const points: array of TPoint; alpha: byte; 1779 DrawLastPixel: boolean); 1780 var i: integer; 1781 begin 1782 if length(points) = 1 then 1783 begin 1784 if DrawLastPixel then ErasePixel(points[0].x,points[0].y,alpha); 1785 end 1786 else 1787 for i := 0 to high(points)-1 do 1788 EraseLine(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,alpha,DrawLastPixel and (i=high(points)-1)); 1789 end; 1790 1791 procedure TBGRACustomBitmap.ErasePolyLineAntialias( 1792 const points: array of TPoint; alpha: byte; DrawLastPixel: boolean); 1793 var i: integer; 1794 begin 1795 if length(points) = 1 then 1796 begin 1797 if DrawLastPixel then ErasePixel(points[0].x,points[0].y,alpha); 1798 end 1799 else 1800 for i := 0 to high(points)-1 do 1801 EraseLineAntialias(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,alpha,DrawLastPixel and (i=high(points)-1)); 1802 end; 1803 1804 procedure TBGRACustomBitmap.ErasePolygonOutline(const points: array of TPoint; 1805 alpha: byte); 1806 var i: integer; 1807 begin 1808 if length(points) = 1 then 1809 begin 1810 ErasePixel(points[0].x,points[0].y,alpha); 1811 end 1812 else 1813 begin 1814 for i := 0 to high(points)-1 do 1815 EraseLine(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,alpha,false); 1816 EraseLine(points[high(points)].x,points[high(points)].Y,points[0].x,points[0].y,alpha,false); 1817 end; 1818 end; 1819 1820 procedure TBGRACustomBitmap.ErasePolygonOutlineAntialias( 1821 const points: array of TPoint; alpha: byte); 1822 var i: integer; 1823 begin 1824 if length(points) = 1 then 1825 begin 1826 ErasePixel(points[0].x,points[0].y,alpha); 1827 end 1828 else 1829 begin 1830 for i := 0 to high(points)-1 do 1831 EraseLineAntialias(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,alpha,false); 1832 EraseLineAntialias(points[high(points)].x,points[high(points)].Y,points[0].x,points[0].y,alpha,false); 1833 end; 1834 end; 1835 1836 { Following functions are defined for convenience } 1837 procedure TBGRACustomBitmap.Rectangle(x, y, x2, y2: integer; c: TColor); 1838 begin 1839 Rectangle(x, y, x2, y2, ColorToBGRA(c), dmSet); 1840 end; 1841 1842 procedure TBGRACustomBitmap.Rectangle(r: TRect; c: TBGRAPixel; mode: TDrawMode 1843 ); 1844 begin 1845 Rectangle(r.left, r.top, r.right, r.bottom, c, mode); 1846 end; 1847 1848 procedure TBGRACustomBitmap.Rectangle(r: TRect; BorderColor, 1849 FillColor: TBGRAPixel; mode: TDrawMode); 1850 begin 1851 Rectangle(r.left, r.top, r.right, r.bottom, BorderColor, FillColor, mode); 1852 end; 1853 1854 procedure TBGRACustomBitmap.Rectangle(r: TRect; c: TColor); 1855 begin 1856 Rectangle(r.left, r.top, r.right, r.bottom, c); 1857 end; 1858 1859 procedure TBGRACustomBitmap.RectangleAntialias(x, y, x2, y2: single; 1860 c: TBGRAPixel; w: single); 1861 begin 1862 RectangleAntialias(x, y, x2, y2, c, w, BGRAPixelTransparent); 1863 end; 1864 1865 procedure TBGRACustomBitmap.FillRoundRect(X1, Y1, X2, Y2: integer; DX, 1866 DY: integer; FillColor: TBGRAPixel; ADrawMode: TDrawMode); 1867 begin 1868 RoundRect(X1,Y1,X2,Y2,DX,DY,FillColor,FillColor,ADrawMode); 1869 end; 1870 1871 procedure TBGRACustomBitmap.EllipseInRect(r: TRect; BorderColor: TBGRAPixel; 1872 ADrawMode: TDrawMode); 1873 begin 1874 RoundRect(r.left,r.top,r.right,r.bottom,abs(r.right-r.left),abs(r.bottom-r.top),BorderColor,ADrawMode); 1875 end; 1876 1877 procedure TBGRACustomBitmap.EllipseInRect(r: TRect; BorderColor, 1878 FillColor: TBGRAPixel; ADrawMode: TDrawMode); 1879 begin 1880 RoundRect(r.left,r.top,r.right,r.bottom,abs(r.right-r.left),abs(r.bottom-r.top),BorderColor,FillColor,ADrawMode); 1881 end; 1882 1883 procedure TBGRACustomBitmap.FillEllipseInRect(r: TRect; FillColor: TBGRAPixel; 1884 ADrawMode: TDrawMode); 1885 begin 1886 FillRoundRect(r.left,r.top,r.right,r.bottom,abs(r.right-r.left),abs(r.bottom-r.top),FillColor,ADrawMode); 1887 end; 1888 1889 procedure TBGRACustomBitmap.FillRect(r: TRect; c: TColor); 1890 begin 1891 FillRect(r.Left, r.top, r.right, r.bottom, c); 1892 end; 1893 1894 procedure TBGRACustomBitmap.FillRect(r: TRect; c: TBGRAPixel; mode: TDrawMode); 1895 begin 1896 FillRect(r.Left, r.top, r.right, r.bottom, c, mode); 1897 end; 1898 1899 procedure TBGRACustomBitmap.FillRect(r: TRect; texture: IBGRAScanner; 1900 mode: TDrawMode); 1901 begin 1902 FillRect(r.Left, r.top, r.right, r.bottom, texture, mode); 1903 end; 1904 1905 procedure TBGRACustomBitmap.FillRect(x, y, x2, y2: integer; c: TColor); 1906 begin 1907 FillRect(x, y, x2, y2, ColorToBGRA(c), dmSet); 1908 end; 1909 1910 { Draw the UTF8 encoded string, (x,y) being the top-left corner. The color c is used to fill the text. 1911 The value of FontOrientation is taken into account, so that the text may be rotated. } 1912 procedure TBGRACustomBitmap.TextOut(x, y: single; sUTF8: string; c: TBGRAPixel); 1913 begin 1914 TextOut(x, y, sUTF8, c, taLeftJustify); 1915 end; 1916 1917 { Draw the UTF8 encoded string, (x,y) being the top-left corner. The color c is used to fill the text. 1918 The value of FontOrientation is taken into account, so that the text may be rotated. } 1919 procedure TBGRACustomBitmap.TextOut(x, y: single; sUTF8: string; c: TColor); 1920 begin 1921 TextOut(x, y, sUTF8, ColorToBGRA(c)); 1922 end; 1923 1924 { Draw the UTF8 encoded string, (x,y) being the top-left corner. The texture is used to fill the text. 1925 The value of FontOrientation is taken into account, so that the text may be rotated. } 1926 procedure TBGRACustomBitmap.TextOut(x, y: single; sUTF8: string; 1927 texture: IBGRAScanner); 1928 begin 1929 TextOut(x, y, sUTF8, texture, taLeftJustify); 1930 end; 1931 1932 { Draw the UTF8 encoded string in the rectangle ARect. Text is wrapped if necessary. 1933 The position depends on the specified horizontal alignment halign and vertical alignement valign. 1934 The color c is used to fill the text. No rotation is applied. } 1935 procedure TBGRACustomBitmap.TextRect(ARect: TRect; sUTF8: string; 1936 halign: TAlignment; valign: TTextLayout; c: TBGRAPixel); 1937 var 1938 style: TTextStyle; 1939 begin 1940 {$hints off} 1941 FillChar(style,sizeof(style),0); 1942 {$hints on} 1943 style.Alignment := halign; 1944 style.Layout := valign; 1945 style.Wordbreak := true; 1946 style.ShowPrefix := false; 1947 style.Clipping := false; 1948 TextRect(ARect,ARect.Left,ARect.Top,sUTF8,style,c); 1949 end; 1950 1951 { Draw the UTF8 encoded string in the rectangle ARect. Text is wrapped if necessary. 1952 The position depends on the specified horizontal alignment halign and vertical alignement valign. 1953 The texture is used to fill the text. No rotation is applied. } 1954 procedure TBGRACustomBitmap.TextRect(ARect: TRect; sUTF8: string; 1955 halign: TAlignment; valign: TTextLayout; texture: IBGRAScanner); 1956 var 1957 style: TTextStyle; 1958 begin 1959 {$hints off} 1960 FillChar(style,sizeof(style),0); 1961 {$hints on} 1962 style.Alignment := halign; 1963 style.Layout := valign; 1964 style.Wordbreak := true; 1965 style.ShowPrefix := false; 1966 style.Clipping := false; 1967 TextRect(ARect,ARect.Left,ARect.Top,sUTF8,style,texture); 1968 end; 1969 1970 function TBGRACustomBitmap.ComputeEllipse(x, y, rx, ry: single): ArrayOfTPointF; 1971 begin 1972 result := ComputeEllipseContour(x,y,rx,ry); 1973 end; 1974 1975 function TBGRACustomBitmap.ComputeEllipse(x, y, rx, ry, w: single 1976 ): ArrayOfTPointF; 1977 begin 1978 result := ComputeEllipseBorder(x,y,rx,ry,w); 1979 end; 1980 1981 procedure TBGRACustomBitmap.FillTransparent; 1982 begin 1983 Fill(BGRAPixelTransparent); 1984 end; 1985 1986 procedure TBGRACustomBitmap.Fill(c: TColor); 1987 begin 1988 Fill(ColorToBGRA(c)); 1989 end; 1990 1991 procedure TBGRACustomBitmap.Fill(c: TBGRAPixel); 1992 begin 1993 Fill(c, 0, NbPixels); 1994 end; 1995 1996 procedure TBGRACustomBitmap.AlphaFill(alpha: byte); 1997 begin 1998 AlphaFill(alpha, 0, NbPixels); 1999 end; 2000 2001 procedure TBGRACustomBitmap.FillMask(x, y: integer; AMask: TBGRACustomBitmap; 2002 color: TBGRAPixel); 2003 begin 2004 FillMask(x,y, AMask, color, dmDrawWithTransparency); 2005 end; 2006 2007 procedure TBGRACustomBitmap.FillMask(x, y: integer; AMask: TBGRACustomBitmap; 2008 texture: IBGRAScanner); 2009 begin 2010 FillMask(x,y, AMask, texture, dmDrawWithTransparency); 2011 end; 2012 2013 procedure TBGRACustomBitmap.FloodFill(X, Y: integer; Color: TBGRAPixel; 2014 mode: TFloodfillMode; Tolerance: byte); 2015 begin 2016 ParallelFloodFill(X,Y,Self,Color,mode,Tolerance); 2017 end; 2018 2019 procedure TBGRACustomBitmap.DrawPart(ARect: TRect; Canvas: TCanvas; x, 2020 y: integer; Opaque: boolean); 2021 var 2022 partial: TBGRACustomBitmap; 2023 begin 2024 partial := GetPart(ARect); 2025 if partial <> nil then 2026 begin 2027 partial.Draw(Canvas, x, y, Opaque); 2028 partial.Free; 2029 end; 2030 end; 2031 2032 procedure TBGRACustomBitmap.PutImageSubpixel(x, y: single; Source: TBGRACustomBitmap); 2033 begin 2034 PutImageAngle(x,y,source,0); 2035 end; 2036 2037 procedure TBGRACustomBitmap.PutImagePart(x, y: integer; 2038 Source: TBGRACustomBitmap; SourceRect: TRect; mode: TDrawMode; AOpacity: byte); 2039 var w,h,sourcex,sourcey,nx,ny,xb,yb,destx,desty: integer; 2040 oldClip,newClip: TRect; 2041 begin 2042 if (Source = nil) or (AOpacity = 0) then exit; 2043 w := SourceRect.Right-SourceRect.Left; 2044 h := SourceRect.Bottom-SourceRect.Top; 2045 if (w <= 0) or (h <= 0) or (Source.Width = 0) or (Source.Height = 0) then exit; 2046 sourcex := PositiveMod(SourceRect.Left, Source.Width); 2047 sourcey := PositiveMod(SourceRect.Top, Source.Height); 2048 nx := (sourceX+w + Source.Width-1) div Source.Width; 2049 ny := (sourceY+h + Source.Height-1) div Source.Height; 2050 2051 oldClip := ClipRect; 2052 newClip := rect(x,y,x+w,y+h); 2053 if not IntersectRect(newClip,newClip,oldClip) then exit; 2054 2055 ClipRect := newClip; 2056 2057 desty := y-sourcey; 2058 for yb := 0 to ny-1 do 2059 begin 2060 destx := x-sourcex; 2061 for xb := 0 to nx-1 do 2062 begin 2063 self.PutImage(destx,desty,Source,mode,AOpacity); 2064 inc(destx,Source.Width); 2065 end; 2066 inc(desty,Source.Height); 2067 end; 2068 2069 ClipRect := oldClip; 2070 end; 2071 2072 procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF; 2073 Source: TBGRACustomBitmap; AOpacity: Byte; ACorrectBlur: Boolean); 2074 begin 2075 if ACorrectBlur then 2076 PutImageAffine(Origin,HAxis,VAxis,Source,rfCosine,AOpacity) 2077 else 2078 PutImageAffine(Origin,HAxis,VAxis,Source,rfLinear,AOpacity); 2079 end; 2080 2081 procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF; 2082 Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AOpacity: Byte); 2083 var outputBounds: TRect; 2084 begin 2085 if (Source = nil) or (AOpacity = 0) then exit; 2086 if (abs(Origin.x-round(Origin.x))<1e-6) and (abs(Origin.y-round(Origin.Y))<1e-6) and 2087 (abs(HAxis.x-(Origin.x+Source.Width))<1e-6) and (abs(HAxis.y-origin.y)<1e-6) and 2088 (abs(VAxis.x-Origin.x)<1e-6) and (abs(VAxis.y-(Origin.y+Source.Height))<1e-6) then 2089 begin 2090 PutImage(round(origin.x),round(origin.y),Source,dmDrawWithTransparency,AOpacity); 2091 exit; 2092 end; 2093 outputBounds := GetImageAffineBounds(Origin,HAxis,VAxis,Source); 2094 PutImageAffine(Origin,HAxis,VAxis,Source,outputBounds,AResampleFilter,dmDrawWithTransparency,AOpacity); 2095 end; 2096 2097 procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF; 2098 Source: TBGRACustomBitmap; AOutputBounds: TRect; AOpacity: Byte; 2099 ACorrectBlur: Boolean); 2100 begin 2101 if ACorrectBlur then 2102 PutImageAffine(Origin,HAxis,VAxis,Source,AOutputBounds,rfCosine,dmDrawWithTransparency, AOpacity) 2103 else 2104 PutImageAffine(Origin,HAxis,VAxis,Source,AOutputBounds,rfLinear,dmDrawWithTransparency,AOpacity); 2105 end; 2106 2107 { Returns the area that contains the affine transformed image } 2108 function TBGRACustomBitmap.GetImageAffineBounds(Origin, HAxis, VAxis: TPointF; 2109 Source: TBGRACustomBitmap): TRect; 2110 var minx,miny,maxx,maxy: integer; 2111 vx,vy,pt1: TPointF; 2112 sourceBounds: TRect; 2113 2114 //include specified point in the bounds 2115 procedure Include(pt: TPointF); 2116 begin 2117 if floor(pt.X) < minx then minx := floor(pt.X); 2118 if floor(pt.Y) < miny then miny := floor(pt.Y); 2119 if ceil(pt.X) > maxx then maxx := ceil(pt.X); 2120 if ceil(pt.Y) > maxy then maxy := ceil(pt.Y); 2121 end; 2122 2123 begin 2124 result := EmptyRect; 2125 if (Source = nil) then exit; 2126 sourceBounds := source.GetImageBounds; 2127 if IsRectEmpty(sourceBounds) then exit; 2128 2129 if (abs(Origin.x-round(Origin.x))<1e-6) and (abs(Origin.y-round(Origin.Y))<1e-6) and 2130 (abs(HAxis.x-(Origin.x+Source.Width))<1e-6) and (abs(HAxis.y-origin.y)<1e-6) and 2131 (abs(VAxis.x-Origin.x)<1e-6) and (abs(VAxis.y-(Origin.y+Source.Height))<1e-6) then 2132 begin 2133 result := sourceBounds; 2134 OffsetRect(result,round(origin.x),round(origin.y)); 2135 IntersectRect(result,result,ClipRect); 2136 exit; 2137 end; 2138 2139 { Compute bounds } 2140 vx := (HAxis-Origin)*(1/source.Width); 2141 vy := (VAxis-Origin)*(1/source.Height); 2142 pt1 := Origin+vx*sourceBounds.Left+vy*sourceBounds.Top; 2143 minx := floor(pt1.X); 2144 miny := floor(pt1.Y); 2145 maxx := ceil(pt1.X); 2146 maxy := ceil(pt1.Y); 2147 Include(Origin+vx*sourceBounds.Right+vy*sourceBounds.Top); 2148 Include(Origin+vx*sourceBounds.Right+vy*sourceBounds.Bottom); 2149 Include(Origin+vx*sourceBounds.Left+vy*sourceBounds.Bottom); 2150 2151 result := rect(minx,miny,maxx+1,maxy+1); 2152 IntersectRect(result,result,ClipRect); 2153 end; 2154 2155 procedure TBGRACustomBitmap.PutImageAngle(x, y: single; 2156 Source: TBGRACustomBitmap; angle: single; AOutputBounds: TRect; 2157 imageCenterX: single; imageCenterY: single; AOpacity: Byte; 2158 ARestoreOffsetAfterRotation: boolean; ACorrectBlur: Boolean); 2159 begin 2160 if ACorrectBlur then 2161 PutImageAngle(x,y,Source,angle,AOutputBounds,rfCosine,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation) 2162 else 2163 PutImageAngle(x,y,Source,angle,AOutputBounds,rfLinear,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation); 2164 end; 2165 2166 procedure TBGRACustomBitmap.PutImageAngle(x, y: single; 2167 Source: TBGRACustomBitmap; angle: single; imageCenterX: single; 2168 imageCenterY: single; AOpacity: Byte; ARestoreOffsetAfterRotation: boolean; ACorrectBlur: Boolean); 2169 begin 2170 if ACorrectBlur then 2171 PutImageAngle(x,y,Source,angle,rfCosine,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation) 2172 else 2173 PutImageAngle(x,y,Source,angle,rfLinear,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation); 2174 end; 2175 2176 procedure TBGRACustomBitmap.PutImageAngle(x, y: single; 2177 Source: TBGRACustomBitmap; angle: single; AOutputBounds: TRect; 2178 AResampleFilter: TResampleFilter; imageCenterX: single; imageCenterY: single; AOpacity: Byte; 2179 ARestoreOffsetAfterRotation: boolean); 2180 var 2181 Origin,HAxis,VAxis: TPointF; 2182 begin 2183 if (source = nil) or (AOpacity=0) then exit; 2184 ComputeImageAngleAxes(x,y,source.Width,source.Height,angle,imageCenterX,imageCenterY,ARestoreOffsetAfterRotation, 2185 Origin,HAxis,VAxis); 2186 PutImageAffine(Origin,HAxis,VAxis,source,AOutputBounds,AResampleFilter,dmDrawWithTransparency,AOpacity); 2187 end; 2188 2189 procedure TBGRACustomBitmap.PutImageAngle(x, y: single; 2190 Source: TBGRACustomBitmap; angle: single; AResampleFilter: TResampleFilter; 2191 imageCenterX: single; imageCenterY: single; AOpacity: Byte; 2192 ARestoreOffsetAfterRotation: boolean); 2193 var 2194 Origin,HAxis,VAxis: TPointF; 2195 begin 2196 if (source = nil) or (AOpacity=0) then exit; 2197 ComputeImageAngleAxes(x,y,source.Width,source.Height,angle,imageCenterX,imageCenterY,ARestoreOffsetAfterRotation, 2198 Origin,HAxis,VAxis); 2199 PutImageAffine(Origin,HAxis,VAxis,source,AResampleFilter,AOpacity); 2200 end; 2201 2202 procedure TBGRACustomBitmap.ComputeImageAngleAxes(x, y, w, h, 2203 angle: single; imageCenterX, imageCenterY: single; 2204 ARestoreOffsetAfterRotation: boolean; out Origin, HAxis, VAxis: TPointF); 2205 var 2206 cosa,sina: single; 2207 2208 { Compute rotated coordinates } 2209 function Coord(relX,relY: single): TPointF; 2210 begin 2211 relX -= imageCenterX; 2212 relY -= imageCenterY; 2213 result.x := relX*cosa-relY*sina+x; 2214 result.y := relY*cosa+relX*sina+y; 2215 if ARestoreOffsetAfterRotation then 2216 begin 2217 result.x += imageCenterX; 2218 result.y += imageCenterY; 2219 end; 2220 end; 2221 2222 begin 2223 cosa := cos(-angle*Pi/180); 2224 sina := -sin(-angle*Pi/180); 2225 Origin := Coord(0,0); 2226 HAxis := Coord(w,0); 2227 VAxis := Coord(0,h); 2228 end; 2229 2230 function TBGRACustomBitmap.GetImageAngleBounds(x, y: single; 2231 Source: TBGRACustomBitmap; angle: single; imageCenterX: single; 2232 imageCenterY: single; ARestoreOffsetAfterRotation: boolean): TRect; 2233 var 2234 cosa,sina: single; 2235 2236 { Compute rotated coordinates } 2237 function Coord(relX,relY: single): TPointF; 2238 begin 2239 relX -= imageCenterX; 2240 relY -= imageCenterY; 2241 result.x := relX*cosa-relY*sina+x; 2242 result.y := relY*cosa+relX*sina+y; 2243 if ARestoreOffsetAfterRotation then 2244 begin 2245 result.x += imageCenterX; 2246 result.y += imageCenterY; 2247 end; 2248 end; 2249 2250 begin 2251 if (source = nil) then 2252 begin 2253 result := EmptyRect; 2254 exit; 2255 end; 2256 cosa := cos(-angle*Pi/180); 2257 sina := -sin(-angle*Pi/180); 2258 result := GetImageAffineBounds(Coord(0,0),Coord(source.Width,0),Coord(0,source.Height),source); 2259 end; 2260 2261 procedure TBGRACustomBitmap.VerticalFlip; 2262 begin 2263 VerticalFlip(rect(0,0,Width,Height)); 2264 end; 2265 2266 procedure TBGRACustomBitmap.HorizontalFlip; 2267 begin 2268 HorizontalFlip(rect(0,0,Width,Height)); 2269 end; 2270 2271 procedure TBGRACustomBitmap.ApplyMask(mask: TBGRACustomBitmap); 2272 begin 2273 ApplyMask(mask, Rect(0,0,Width,Height), Point(0,0)); 2274 end; 2275 2276 procedure TBGRACustomBitmap.ApplyMask(mask: TBGRACustomBitmap; ARect: TRect); 2277 begin 2278 ApplyMask(mask, ARect, ARect.TopLeft); 2279 end; 2280 2281 { Interface gateway } 2282 function TBGRACustomBitmap.QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} IID: TGUID; out Obj): HResult; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 2283 begin 2284 if GetInterface(iid, obj) then 2285 Result := S_OK 2286 else 2287 Result := longint(E_NOINTERFACE); 2288 end; 2289 2290 { There is no automatic reference counting, but it is compulsory to define these functions } 2291 function TBGRACustomBitmap._AddRef: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 2292 begin 2293 result := 0; 2294 end; 2295 2296 function TBGRACustomBitmap._Release: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 2297 begin 2298 result := 0; 2299 end; 2300 2301 {$hints off} 2302 procedure TBGRACustomBitmap.ScanPutPixels(pdest: PBGRAPixel; count: integer; 2303 mode: TDrawMode); 2304 begin 2305 //do nothing 2306 end; 2307 {$hints on} 2308 2309 function TBGRACustomBitmap.IsScanPutPixelsDefined: boolean; 2310 begin 2311 result := False; 2312 end; 2313 2314 {********************** End of TBGRACustomBitmap **************************} 2315 2316 { TBGRACustomScanner } 2317 { The abstract class record the position so that a derived class 2318 need only to redefine ScanAt } 2319 2320 function TBGRACustomScanner.ScanAtInteger(X, Y: integer): TBGRAPixel; 2321 begin 2322 result := ScanAt(X,Y); 2323 end; 2324 2325 procedure TBGRACustomScanner.ScanMoveTo(X, Y: Integer); 2326 begin 2327 FCurX := X; 2328 FCurY := Y; 2329 end; 2330 2331 { Call ScanAt to determine pixel value } 2332 function TBGRACustomScanner.ScanNextPixel: TBGRAPixel; 2333 begin 2334 result := ScanAt(FCurX,FCurY); 2335 Inc(FCurX); 2336 end; 2337 2338 {$hints off} 2339 procedure TBGRACustomScanner.ScanPutPixels(pdest: PBGRAPixel; count: integer; 2340 mode: TDrawMode); 2341 begin 2342 //do nothing 2343 end; 2344 {$hints on} 2345 2346 function TBGRACustomScanner.IsScanPutPixelsDefined: boolean; 2347 begin 2348 result := false; 2349 end; 2350 2351 { Interface gateway } 2352 function TBGRACustomScanner.QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} IID: TGUID; out Obj): HResult; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 2353 begin 2354 if GetInterface(iid, obj) then 2355 Result := S_OK 2356 else 2357 Result := longint(E_NOINTERFACE); 2358 end; 2359 2360 { There is no automatic reference counting, but it is compulsory to define these functions } 2361 function TBGRACustomScanner._AddRef: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 2362 begin 2363 result := 0; 2364 end; 2365 2366 function TBGRACustomScanner._Release: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 2367 begin 2368 result := 0; 2369 end; 2370 2371 {********************** End of TBGRACustomScanner **************************} 2372 2373 { The gamma correction is approximated here by a power function } 2374 const 2375 GammaExpFactor = 1.7; //exponent 2376 redWeightShl10 = 306; // = 0.299 2377 greenWeightShl10 = 601; // = 0.587 2378 blueWeightShl10 = 117; // = 0.114 2379 2380 var 2381 GammaLinearFactor: single; 2382 2383 procedure InitGamma; 2384 var 2385 i: integer; 2386 {$IFDEF WINCE} 2387 j,prevpos,curpos,midpos: integer; 2388 {$ENDIF} 2389 begin 2390 //the linear factor is used to normalize expanded values in the range 0..65535 2391 GammaLinearFactor := 65535 / power(255, GammaExpFactor); 2392 2393 {$IFDEF WINCE} 2394 curpos := 0; 2395 GammaExpansionTab[0] := 0; 2396 GammaCompressionTab[0] := 0; 2397 for i := 0 to 255 do 2398 begin 2399 prevpos := curpos; 2400 curpos := round(power(i, GammaExpFactor) * GammaLinearFactor); 2401 if i = 1 then curpos := 1; //to avoid information loss 2402 GammaExpansionTab[i] := curpos; 2403 midpos := (prevpos+1+curpos) div 2; 2404 for j := prevpos+1 to midpos-1 do 2405 GammaCompressionTab[j] := i-1; 2406 for j := midpos to curpos do 2407 GammaCompressionTab[j] := i; 2408 end; 2409 {$ELSE} 2410 for i := 0 to 255 do 2411 GammaExpansionTab[i] := round(power(i, GammaExpFactor) * GammaLinearFactor); 2412 2413 for i := 0 to 65535 do 2414 GammaCompressionTab[i] := round(power(i / GammaLinearFactor, 1 / GammaExpFactor)); 2415 2416 GammaExpansionTab[1] := 1; //to avoid information loss 2417 GammaCompressionTab[1] := 1; 2418 {$ENDIF} 2419 end; 2420 2421 {************************** Color functions **************************} 570 begin {optional implementation} end; 571 2422 572 2423 573 function CheckPutImageBounds(x, y, tx, ty: integer; out minxb, minyb, maxxb, … … 2460 610 2461 611 result := true; 2462 end;2463 2464 { The intensity is defined here as the maximum value of any color component }2465 function GetIntensity(const c: TExpandedPixel): word; inline;2466 begin2467 Result := c.red;2468 if c.green > Result then2469 Result := c.green;2470 if c.blue > Result then2471 Result := c.blue;2472 end;2473 2474 function GetIntensity(c: TBGRAPixel): word;2475 begin2476 Result := c.red;2477 if c.green > Result then2478 Result := c.green;2479 if c.blue > Result then2480 Result := c.blue;2481 result := GammaExpansionTab[Result];2482 end;2483 2484 function SetIntensity(const c: TExpandedPixel; intensity: word): TExpandedPixel;2485 var2486 curIntensity: word;2487 begin2488 curIntensity := GetIntensity(c);2489 if curIntensity = 0 then //suppose it's gray if there is no color information2490 begin2491 Result.red := intensity;2492 Result.green := intensity;2493 Result.blue := intensity;2494 result.alpha := c.alpha;2495 end2496 else2497 begin2498 //linear interpolation to reached wanted intensity2499 Result.red := (c.red * intensity + (curIntensity shr 1)) div curIntensity;2500 Result.green := (c.green * intensity + (curIntensity shr 1)) div curIntensity;2501 Result.blue := (c.blue * intensity + (curIntensity shr 1)) div curIntensity;2502 Result.alpha := c.alpha;2503 end;2504 end;2505 2506 function SetIntensity(c: TBGRAPixel; intensity: word): TBGRAPixel;2507 begin2508 result := GammaCompression(SetIntensity(GammaExpansion(c),intensity));2509 end;2510 2511 function GetLightness(c: TBGRAPixel): word;2512 begin2513 result := GetLightness(GammaExpansion(c));2514 end;2515 2516 { The lightness here is defined as the subjective sensation of luminosity, where2517 blue is the darkest component and green the lightest }2518 function GetLightness(const c: TExpandedPixel): word; inline;2519 begin2520 Result := (c.red * redWeightShl10 + c.green * greenWeightShl10 +2521 c.blue * blueWeightShl10 + 512) shr 10;2522 end;2523 2524 function SetLightness(const c: TExpandedPixel; lightness: word): TExpandedPixel;2525 var2526 curLightness: word;2527 begin2528 curLightness := GetLightness(c);2529 if lightness = curLightness then2530 begin //no change2531 Result := c;2532 exit;2533 end;2534 result := SetLightness(c, lightness, curLightness);2535 end;2536 2537 function SetLightness(c: TBGRAPixel; lightness: word): TBGRAPixel;2538 begin2539 result := GammaCompression(SetLightness(GammaExpansion(c),lightness));2540 end;2541 2542 function SetLightness(const c: TExpandedPixel; lightness: word; curLightness: word): TExpandedPixel;2543 var2544 AddedWhiteness, maxBeforeWhite: word;2545 clip: boolean;2546 begin2547 if lightness = curLightness then2548 begin //no change2549 Result := c;2550 exit;2551 end;2552 if lightness = 65535 then //set to white2553 begin2554 Result.red := 65535;2555 Result.green := 65535;2556 Result.blue := 65535;2557 Result.alpha := c.alpha;2558 exit;2559 end;2560 if lightness = 0 then //set to black2561 begin2562 Result.red := 0;2563 Result.green := 0;2564 Result.blue := 0;2565 Result.alpha := c.alpha;2566 exit;2567 end;2568 if curLightness = 0 then //set from black2569 begin2570 Result.red := lightness;2571 Result.green := lightness;2572 Result.blue := lightness;2573 Result.alpha := c.alpha;2574 exit;2575 end;2576 if lightness < curLightness then //darker is easy2577 begin2578 result.alpha:= c.alpha;2579 result.red := (c.red * lightness + (curLightness shr 1)) div curLightness;2580 result.green := (c.green * lightness + (curLightness shr 1)) div curLightness;2581 result.blue := (c.blue * lightness + (curLightness shr 1)) div curLightness;2582 exit;2583 end;2584 //lighter and grayer2585 Result := c;2586 AddedWhiteness := lightness - curLightness;2587 maxBeforeWhite := 65535 - AddedWhiteness;2588 clip := False;2589 if Result.red <= maxBeforeWhite then2590 Inc(Result.red, AddedWhiteness)2591 else2592 begin2593 Result.red := 65535;2594 clip := True;2595 end;2596 if Result.green <= maxBeforeWhite then2597 Inc(Result.green, AddedWhiteness)2598 else2599 begin2600 Result.green := 65535;2601 clip := True;2602 end;2603 if Result.blue <= maxBeforeWhite then2604 Inc(Result.blue, AddedWhiteness)2605 else2606 begin2607 Result.blue := 65535;2608 clip := True;2609 end;2610 2611 if clip then //light and whiter2612 begin2613 curLightness := GetLightness(Result);2614 addedWhiteness := lightness - curLightness;2615 maxBeforeWhite := 65535 - curlightness;2616 Result.red := Result.red + addedWhiteness * (65535 - Result.red) div2617 maxBeforeWhite;2618 Result.green := Result.green + addedWhiteness * (65535 - Result.green) div2619 maxBeforeWhite;2620 Result.blue := Result.blue + addedWhiteness * (65535 - Result.blue) div2621 maxBeforeWhite;2622 end;2623 end;2624 2625 function ApplyLightnessFast(color: TBGRAPixel; lightness: word): TBGRAPixel;2626 var2627 r,g,b: word;2628 lightness256: byte;2629 begin2630 if lightness <= 32768 then2631 begin2632 if lightness = 32768 then2633 result := color else2634 begin2635 lightness256 := GammaCompressionTab[lightness shl 1];2636 result := BGRA(color.red * lightness256 shr 8, color.green*lightness256 shr 8,2637 color.blue * lightness256 shr 8, color.alpha);2638 end;2639 end else2640 begin2641 if lightness = 65535 then2642 result := BGRA(255,255,255,color.alpha) else2643 begin2644 lightness -= 32767;2645 r := GammaExpansionTab[color.red];2646 g := GammaExpansionTab[color.green];2647 b := GammaExpansionTab[color.blue];2648 result := BGRA(GammaCompressionTab[ r + (not r)*lightness shr 15 ],2649 GammaCompressionTab[ g + (not g)*lightness shr 15 ],2650 GammaCompressionTab[ b + (not b)*lightness shr 15 ],2651 color.alpha);2652 end;2653 end;2654 end;2655 2656 function CombineLightness(lightness1,lightness2: Int32or64): Int32or64;2657 {$ifdef CPUI386} {$asmmode intel} assembler;2658 asm2659 imul edx2660 shl edx, 172661 shr eax, 152662 or edx, eax2663 mov result, edx2664 end;2665 {$ELSE}2666 begin2667 result := int64(lightness1)*lightness2 shr 15;2668 end;2669 {$ENDIF}2670 2671 function ApplyIntensityFast(color: TBGRAPixel; lightness: longword): TBGRAPixel;2672 var2673 maxValue,invMaxValue,r,g,b: longword;2674 lightness256: byte;2675 begin2676 if lightness <= 32768 then2677 begin2678 if lightness = 32768 then2679 result := color else2680 begin2681 lightness256 := GammaCompressionTab[lightness shl 1];2682 result := BGRA(color.red * lightness256 shr 8, color.green*lightness256 shr 8,2683 color.blue * lightness256 shr 8, color.alpha);2684 end;2685 end else2686 begin2687 r := CombineLightness(GammaExpansionTab[color.red], lightness);2688 g := CombineLightness(GammaExpansionTab[color.green], lightness);2689 b := CombineLightness(GammaExpansionTab[color.blue], lightness);2690 maxValue := r;2691 if g > maxValue then maxValue := g;2692 if b > maxValue then maxValue := b;2693 if maxValue <= 65535 then2694 result := BGRA(GammaCompressionTab[r],2695 GammaCompressionTab[g],2696 GammaCompressionTab[b],2697 color.alpha)2698 else2699 begin2700 invMaxValue := (longword(2147483647)+longword(maxValue-1)) div maxValue;2701 maxValue := (maxValue-65535) shr 1;2702 r := r*invMaxValue shr 15 + maxValue;2703 g := g*invMaxValue shr 15 + maxValue;2704 b := b*invMaxValue shr 15 + maxValue;2705 if r >= 65535 then result.red := 255 else2706 result.red := GammaCompressionTab[r];2707 if g >= 65535 then result.green := 255 else2708 result.green := GammaCompressionTab[g];2709 if b >= 65535 then result.blue := 255 else2710 result.blue := GammaCompressionTab[b];2711 result.alpha := color.alpha;2712 end;2713 end;2714 end;2715 2716 { Conversion from RGB value to HSL colorspace. See : http://en.wikipedia.org/wiki/HSL_color_space }2717 function BGRAToHSLA(c: TBGRAPixel): THSLAPixel;2718 begin2719 result := ExpandedToHSLA(GammaExpansion(c));2720 end;2721 2722 procedure ExpandedToHSLAInline(r,g,b: Int32Or64; var dest: THSLAPixel); inline;2723 const2724 deg60 = 10922;2725 deg120 = 21845;2726 deg240 = 43690;2727 var2728 min, max, minMax: Int32or64;2729 UMinMax,UTwiceLightness: UInt32or64;2730 begin2731 if g > r then2732 begin2733 max := g;2734 min := r;2735 end2736 else2737 begin2738 max := r;2739 min := g;2740 end;2741 if b > max then2742 max := b2743 else2744 if b < min then2745 min := b;2746 minMax := max - min;2747 2748 if minMax = 0 then2749 dest.hue := 02750 else2751 if max = r then2752 {$PUSH}{$RANGECHECKS OFF}2753 dest.hue := ((g - b) * deg60) div minMax2754 {$POP}2755 else2756 if max = g then2757 dest.hue := ((b - r) * deg60) div minMax + deg1202758 else2759 {max = b} dest.hue := ((r - g) * deg60) div minMax + deg240;2760 UTwiceLightness := max + min;2761 if min = max then2762 dest.saturation := 02763 else2764 begin2765 UMinMax:= minMax;2766 if UTwiceLightness < 65536 then2767 dest.saturation := (UMinMax shl 16) div (UTwiceLightness + 1)2768 else2769 dest.saturation := (UMinMax shl 16) div (131072 - UTwiceLightness);2770 end;2771 dest.lightness := UTwiceLightness shr 1;2772 end;2773 2774 function ExpandedToHSLA(const ec: TExpandedPixel): THSLAPixel;2775 begin2776 result.alpha := ec.alpha;2777 ExpandedToHSLAInline(ec.red,ec.green,ec.blue,result);2778 end;2779 2780 function HtoG(hue: word): word;2781 const2782 segmentDest: array[0..5] of NativeUInt =2783 (13653, 10923, 8192, 13653, 10923, 8192);2784 segmentSrc: array[0..5] of NativeUInt =2785 (10923, 10922, 10923, 10923, 10922, 10923);2786 var2787 h,g: NativeUInt;2788 begin2789 h := hue;2790 if h < segmentSrc[0] then2791 g := h * segmentDest[0] div segmentSrc[0]2792 else2793 begin2794 g := segmentDest[0];2795 h -= segmentSrc[0];2796 if h < segmentSrc[1] then2797 g += h * segmentDest[1] div segmentSrc[1]2798 else2799 begin2800 g += segmentDest[1];2801 h -= segmentSrc[1];2802 if h < segmentSrc[2] then2803 g += h * segmentDest[2] div segmentSrc[2]2804 else2805 begin2806 g += segmentDest[2];2807 h -= segmentSrc[2];2808 if h < segmentSrc[3] then2809 g += h * segmentDest[3] div segmentSrc[3]2810 else2811 begin2812 g += segmentDest[3];2813 h -= segmentSrc[3];2814 if h < segmentSrc[4] then2815 g += h * segmentDest[4] div segmentSrc[4]2816 else2817 begin2818 g += segmentDest[4];2819 h -= segmentSrc[4];2820 g += h * segmentDest[5] div segmentSrc[5];2821 end;2822 end;2823 end;2824 end;2825 end;2826 result := g;2827 end;2828 2829 function GtoH(ghue: word): word;2830 const2831 segment: array[0..5] of NativeUInt =2832 (13653, 10923, 8192, 13653, 10923, 8192);2833 var g: NativeUint;2834 begin2835 g := ghue;2836 if g < segment[0] then2837 result := g * 10923 div segment[0]2838 else2839 begin2840 g -= segment[0];2841 if g < segment[1] then2842 result := g * (21845-10923) div segment[1] + 109232843 else2844 begin2845 g -= segment[1];2846 if g < segment[2] then2847 result := g * (32768-21845) div segment[2] + 218452848 else2849 begin2850 g -= segment[2];2851 if g < segment[3] then2852 result := g * (43691-32768) div segment[3] + 327682853 else2854 begin2855 g -= segment[3];2856 if g < segment[4] then2857 result := g * (54613-43691) div segment[4] + 436912858 else2859 begin2860 g -= segment[4];2861 result := g * (65536-54613) div segment[5] + 54613;2862 end;2863 end;2864 end;2865 end;2866 end;2867 end;2868 2869 function BGRAToGSBA(c: TBGRAPixel): TGSBAPixel;2870 var lightness: UInt32Or64;2871 red,green,blue: Int32or64;2872 begin2873 red := GammaExpansionTab[c.red];2874 green := GammaExpansionTab[c.green];2875 blue := GammaExpansionTab[c.blue];2876 result.alpha := c.alpha shl 8 + c.alpha;2877 2878 lightness := (red * redWeightShl10 + green * greenWeightShl10 +2879 blue * blueWeightShl10 + 512) shr 10;2880 2881 ExpandedToHSLAInline(red,green,blue,result);2882 if result.lightness > 32768 then2883 result.saturation := result.saturation* UInt32or64(not result.lightness) div 32767;2884 result.lightness := lightness;2885 result.hue := HtoG(result.hue);2886 end;2887 2888 function ExpandedToGSBA(ec: TExpandedPixel): TGSBAPixel;2889 var lightness: UInt32Or64;2890 red,green,blue: Int32or64;2891 begin2892 red := ec.red;2893 green := ec.green;2894 blue := ec.blue;2895 result.alpha := ec.alpha;2896 2897 lightness := (red * redWeightShl10 + green * greenWeightShl10 +2898 blue * blueWeightShl10 + 512) shr 10;2899 2900 ExpandedToHSLAInline(red,green,blue,result);2901 if result.lightness > 32768 then2902 result.saturation := result.saturation* UInt32or64(not result.lightness) div 32767;2903 result.lightness := lightness;2904 result.hue := HtoG(result.hue);2905 end;2906 2907 function HSLAToExpanded(const c: THSLAPixel): TExpandedPixel;2908 const2909 deg30 = 4096;2910 deg60 = 8192;2911 deg120 = deg60 * 2;2912 deg180 = deg60 * 3;2913 deg240 = deg60 * 4;2914 deg360 = deg60 * 6;2915 2916 function ComputeColor(p, q: Int32or64; h: Int32or64): Int32or64; inline;2917 begin2918 if h < deg180 then2919 begin2920 if h < deg60 then2921 Result := p + ((q - p) * h + deg30) div deg602922 else2923 Result := q2924 end else2925 begin2926 if h < deg240 then2927 Result := p + ((q - p) * (deg240 - h) + deg30) div deg602928 else2929 Result := p;2930 end;2931 end;2932 2933 var2934 q, p, L, S, H: Int32or64;2935 begin2936 L := c.lightness;2937 S := c.saturation;2938 if S = 0 then //gray2939 begin2940 result.red := L;2941 result.green := L;2942 result.blue := L;2943 result.alpha := c.alpha;2944 exit;2945 end;2946 {$hints off}2947 if L < 32768 then2948 q := (L shr 1) * ((65535 + S) shr 1) shr 142949 else2950 q := L + S - ((L shr 1) *2951 (S shr 1) shr 14);2952 {$hints on}2953 if q > 65535 then q := 65535;2954 p := (L shl 1) - q;2955 if p > 65535 then p := 65535;2956 H := c.hue * deg360 shr 16;2957 result.green := ComputeColor(p, q, H);2958 inc(H, deg120);2959 if H > deg360 then Dec(H, deg360);2960 result.red := ComputeColor(p, q, H);2961 inc(H, deg120);2962 if H > deg360 then Dec(H, deg360);2963 result.blue := ComputeColor(p, q, H);2964 result.alpha := c.alpha;2965 end;2966 2967 { Conversion from HSL colorspace to RGB. See : http://en.wikipedia.org/wiki/HSL_color_space }2968 function HSLAToBGRA(const c: THSLAPixel): TBGRAPixel;2969 var ec: TExpandedPixel;2970 begin2971 ec := HSLAToExpanded(c);2972 Result := GammaCompression(ec);2973 end;2974 2975 function HueDiff(h1, h2: word): word;2976 begin2977 result := abs(integer(h1)-integer(h2));2978 if result > 32768 then result := 65536-result;2979 end;2980 2981 function GetHue(ec: TExpandedPixel): word;2982 const2983 deg60 = 8192;2984 deg120 = deg60 * 2;2985 deg240 = deg60 * 4;2986 deg360 = deg60 * 6;2987 var2988 min, max, minMax: integer;2989 r,g,b: integer;2990 begin2991 r := ec.red;2992 g := ec.green;2993 b := ec.blue;2994 min := r;2995 max := r;2996 if g > max then2997 max := g2998 else2999 if g < min then3000 min := g;3001 if b > max then3002 max := b3003 else3004 if b < min then3005 min := b;3006 minMax := max - min;3007 3008 if minMax = 0 then3009 Result := 03010 else3011 if max = r then3012 Result := (((g - b) * deg60) div3013 minMax + deg360) mod deg3603014 else3015 if max = g then3016 Result := ((b - r) * deg60) div minMax + deg1203017 else3018 {max = b} Result :=3019 ((r - g) * deg60) div minMax + deg240;3020 3021 Result := (Result shl 16) div deg360; //normalize3022 end;3023 3024 function ColorImportance(ec: TExpandedPixel): word;3025 var min,max: word;3026 begin3027 min := ec.red;3028 max := ec.red;3029 if ec.green > max then3030 max := ec.green3031 else3032 if ec.green < min then3033 min := ec.green;3034 if ec.blue > max then3035 max := ec.blue3036 else3037 if ec.blue < min then3038 min := ec.blue;3039 result := max - min;3040 end;3041 3042 function GSBAToBGRA(c: TGSBAPixel): TBGRAPixel;3043 var ec: TExpandedPixel;3044 lightness: word;3045 begin3046 c.hue := GtoH(c.hue);3047 lightness := c.lightness;3048 c.lightness := 32768;3049 ec := HSLAToExpanded(c);3050 result := GammaCompression(SetLightness(ec, lightness));3051 end;3052 3053 function GSBAToExpanded(c: TGSBAPixel): TExpandedPixel;3054 var lightness: word;3055 begin3056 c.hue := GtoH(c.hue);3057 lightness := c.lightness;3058 c.lightness := 32768;3059 result := SetLightness(HSLAToExpanded(c),lightness);3060 end;3061 3062 function GSBAToHSLA(c: TGSBAPixel): THSLAPixel;3063 begin3064 result := BGRAToHSLA(GSBAToBGRA(c));3065 end;3066 3067 { Apply gamma correction using conversion tables }3068 function GammaExpansion(c: TBGRAPixel): TExpandedPixel;3069 begin3070 Result.red := GammaExpansionTab[c.red];3071 Result.green := GammaExpansionTab[c.green];3072 Result.blue := GammaExpansionTab[c.blue];3073 Result.alpha := c.alpha shl 8 + c.alpha;3074 end;3075 3076 function GammaCompression(const ec: TExpandedPixel): TBGRAPixel;3077 begin3078 Result.red := GammaCompressionTab[ec.red];3079 Result.green := GammaCompressionTab[ec.green];3080 Result.blue := GammaCompressionTab[ec.blue];3081 Result.alpha := ec.alpha shr 8;3082 end;3083 3084 function GammaCompression(red, green, blue, alpha: word): TBGRAPixel;3085 begin3086 Result.red := GammaCompressionTab[red];3087 Result.green := GammaCompressionTab[green];3088 Result.blue := GammaCompressionTab[blue];3089 Result.alpha := alpha shr 8;3090 end;3091 3092 // Conversion to grayscale by taking into account3093 // different color weights3094 function BGRAToGrayscale(c: TBGRAPixel): TBGRAPixel;3095 var3096 ec: TExpandedPixel;3097 gray: word;3098 cgray: byte;3099 begin3100 if c.alpha = 0 then3101 begin3102 result := BGRAPixelTransparent;3103 exit;3104 end;3105 //gamma expansion3106 ec := GammaExpansion(c);3107 //gray composition3108 gray := (ec.red * redWeightShl10 + ec.green * greenWeightShl10 +3109 ec.blue * blueWeightShl10 + 512) shr 10;3110 //gamma compression3111 cgray := GammaCompressionTab[gray];3112 Result.red := cgray;3113 Result.green := cgray;3114 Result.blue := cgray;3115 Result.alpha := c.alpha;3116 end;3117 3118 function GrayscaleToBGRA(lightness: word): TBGRAPixel;3119 begin3120 result.red := GammaCompressionTab[lightness];3121 result.green := result.red;3122 result.blue := result.red;3123 result.alpha := $ff;3124 end;3125 3126 function MergeBGRA(const colors: array of TBGRAPixel): TBGRAPixel;3127 var3128 sumR,sumG,sumB,sumA: NativeUInt;3129 i: integer;3130 begin3131 if length(colors)<=0 then3132 begin3133 result := BGRAPixelTransparent;3134 exit;3135 end;3136 sumR := 0;3137 sumG := 0;3138 sumB := 0;3139 sumA := 0;3140 for i := 0 to high(colors) do3141 with colors[i] do3142 begin3143 sumR += red*alpha;3144 sumG += green*alpha;3145 sumB += blue*alpha;3146 sumA += alpha;3147 end;3148 if sumA > 0 then3149 begin3150 result.red := (sumR + sumA shr 1) div sumA;3151 result.green := (sumG + sumA shr 1) div sumA;3152 result.blue := (sumB + sumA shr 1) div sumA;3153 result.alpha := sumA div longword(length(colors));3154 end3155 else3156 result := BGRAPixelTransparent;3157 end;3158 3159 { Merge linearly two colors of same importance }3160 function MergeBGRA(c1, c2: TBGRAPixel): TBGRAPixel;3161 var c12: cardinal;3162 begin3163 if (c1.alpha = 0) then3164 Result := c23165 else3166 if (c2.alpha = 0) then3167 Result := c13168 else3169 begin3170 c12 := c1.alpha + c2.alpha;3171 Result.red := (c1.red * c1.alpha + c2.red * c2.alpha + c12 shr 1) div c12;3172 Result.green := (c1.green * c1.alpha + c2.green * c2.alpha + c12 shr 1) div c12;3173 Result.blue := (c1.blue * c1.alpha + c2.blue * c2.alpha + c12 shr 1) div c12;3174 Result.alpha := (c12 + 1) shr 1;3175 end;3176 end;3177 3178 function MergeBGRA(c1: TBGRAPixel; weight1: integer; c2: TBGRAPixel;3179 weight2: integer): TBGRAPixel;3180 var3181 f1,f2,f12: int64;3182 begin3183 if (weight1 = 0) then3184 begin3185 if (weight2 = 0) then3186 result := BGRAPixelTransparent3187 else3188 Result := c23189 end3190 else3191 if (weight2 = 0) then3192 Result := c13193 else3194 if (weight1+weight2 = 0) then3195 Result := BGRAPixelTransparent3196 else3197 begin3198 f1 := int64(c1.alpha)*weight1;3199 f2 := int64(c2.alpha)*weight2;3200 f12 := f1+f2;3201 if f12 = 0 then3202 result := BGRAPixelTransparent3203 else3204 begin3205 Result.red := (c1.red * f1 + c2.red * f2 + f12 shr 1) div f12;3206 Result.green := (c1.green * f1 + c2.green * f2 + f12 shr 1) div f12;3207 Result.blue := (c1.blue * f1 + c2.blue * f2 + f12 shr 1) div f12;3208 {$hints off}3209 Result.alpha := (f12 + ((weight1+weight2) shr 1)) div (weight1+weight2);3210 {$hints on}3211 end;3212 end;3213 end;3214 3215 function MergeBGRAWithGammaCorrection(c1: TBGRAPixel; weight1: byte; c2: TBGRAPixel;3216 weight2: byte): TBGRAPixel;3217 var3218 w1,w2,f1,f2,f12,a: UInt32or64;3219 begin3220 w1 := weight1;3221 w2 := weight2;3222 if (w1 = 0) then3223 begin3224 if (w2 = 0) then3225 result := BGRAPixelTransparent3226 else3227 Result := c23228 end3229 else3230 if (w2 = 0) then3231 Result := c13232 else3233 begin3234 f1 := c1.alpha*w1;3235 f2 := c2.alpha*w2;3236 a := (f1+f2 + ((w1+w2) shr 1)) div (w1+w2);3237 if a = 0 then3238 begin3239 result := BGRAPixelTransparent;3240 exit;3241 end else3242 Result.alpha := a;3243 {$IFNDEF CPU64}3244 if (f1 >= 32768) or (f2 >= 32768) then3245 begin3246 f1 := f1 shr 1;3247 f2 := f2 shr 1;3248 end;3249 {$ENDIF}3250 f12 := f1+f2;3251 Result.red := GammaCompressionTab[(GammaExpansionTab[c1.red] * f1 + GammaExpansionTab[c2.red] * f2) div f12];3252 Result.green := GammaCompressionTab[(GammaExpansionTab[c1.green] * f1 + GammaExpansionTab[c2.green] * f2) div f12];3253 Result.blue := GammaCompressionTab[(GammaExpansionTab[c1.blue] * f1 + GammaExpansionTab[c2.blue] * f2) div f12];3254 end;3255 end;3256 3257 { Merge two colors of same importance }3258 function MergeBGRA(ec1, ec2: TExpandedPixel): TExpandedPixel;3259 var c12: cardinal;3260 begin3261 if (ec1.alpha = 0) then3262 Result := ec23263 else3264 if (ec2.alpha = 0) then3265 Result := ec13266 else3267 begin3268 c12 := ec1.alpha + ec2.alpha;3269 Result.red := (int64(ec1.red) * ec1.alpha + int64(ec2.red) * ec2.alpha + c12 shr 1) div c12;3270 Result.green := (int64(ec1.green) * ec1.alpha + int64(ec2.green) * ec2.alpha + c12 shr 1) div c12;3271 Result.blue := (int64(ec1.blue) * ec1.alpha + int64(ec2.blue) * ec2.alpha + c12 shr 1) div c12;3272 Result.alpha := (c12 + 1) shr 1;3273 end;3274 end;3275 3276 function BGRA(red, green, blue, alpha: byte): TBGRAPixel;3277 begin3278 Result.red := red;3279 Result.green := green;3280 Result.blue := blue;3281 Result.alpha := alpha;3282 end;3283 3284 function BGRA(red, green, blue: byte): TBGRAPixel; overload;3285 begin3286 Result.red := red;3287 Result.green := green;3288 Result.blue := blue;3289 Result.alpha := 255;3290 end;3291 3292 { Convert a TColor value to a TBGRAPixel value. Note that3293 you need to call ColorToRGB first if you use a system3294 color identifier like clWindow. }3295 {$PUSH}{$R-}3296 3297 function HSLA(hue, saturation, lightness, alpha: word): THSLAPixel;3298 begin3299 Result.hue := hue;3300 Result.saturation := saturation;3301 Result.lightness := lightness;3302 Result.alpha := alpha;3303 end;3304 3305 function HSLA(hue, saturation, lightness: word): THSLAPixel;3306 begin3307 Result.hue := hue;3308 Result.saturation := saturation;3309 Result.lightness := lightness;3310 Result.alpha := $ffff;3311 end;3312 3313 function ColorToBGRA(color: TColor): TBGRAPixel; overload;3314 begin3315 Result.red := color;3316 Result.green := color shr 8;3317 Result.blue := color shr 16;3318 Result.alpha := 255;3319 end;3320 3321 function ColorToBGRA(color: TColor; opacity: byte): TBGRAPixel; overload;3322 begin3323 Result.red := color;3324 Result.green := color shr 8;3325 Result.blue := color shr 16;3326 Result.alpha := opacity;3327 end;3328 {$POP}3329 3330 { Conversion from TFPColor to TBGRAPixel assuming TFPColor3331 is already gamma compressed }3332 function FPColorToBGRA(AValue: TFPColor): TBGRAPixel;3333 begin3334 with AValue do3335 Result := BGRA(red shr 8, green shr 8, blue shr 8, alpha shr 8);3336 end;3337 3338 function BGRAToFPColor(AValue: TBGRAPixel): TFPColor; inline;3339 begin3340 result.red := AValue.red shl 8 + AValue.red;3341 result.green := AValue.green shl 8 + AValue.green;3342 result.blue := AValue.blue shl 8 + AValue.blue;3343 result.alpha := AValue.alpha shl 8 + AValue.alpha;3344 end;3345 3346 function BGRAToColor(c: TBGRAPixel): TColor;3347 begin3348 Result := c.red + (c.green shl 8) + (c.blue shl 16);3349 end;3350 3351 operator = (const c1, c2: TBGRAPixel): boolean;3352 begin3353 if (c1.alpha = 0) and (c2.alpha = 0) then3354 Result := True3355 else3356 Result := (c1.alpha = c2.alpha) and (c1.red = c2.red) and3357 (c1.green = c2.green) and (c1.blue = c2.blue);3358 end;3359 3360 function LessStartSlope65535(value: word): word;3361 var factor: word;3362 begin3363 factor := 4096 - (not value)*3 shr 7;3364 result := value*factor shr 12;3365 end;3366 3367 function ExpandedDiff(ec1, ec2: TExpandedPixel): word;3368 var3369 CompRedAlpha1, CompGreenAlpha1, CompBlueAlpha1, CompRedAlpha2,3370 CompGreenAlpha2, CompBlueAlpha2: integer;3371 DiffAlpha: word;3372 ColorDiff: word;3373 TempHueDiff: word;3374 begin3375 CompRedAlpha1 := ec1.red * ec1.alpha shr 16; //gives 0..655353376 CompGreenAlpha1 := ec1.green * ec1.alpha shr 16;3377 CompBlueAlpha1 := ec1.blue * ec1.alpha shr 16;3378 CompRedAlpha2 := ec2.red * ec2.alpha shr 16;3379 CompGreenAlpha2 := ec2.green * ec2.alpha shr 16;3380 CompBlueAlpha2 := ec2.blue * ec2.alpha shr 16;3381 Result := (Abs(CompRedAlpha2 - CompRedAlpha1)*redWeightShl10 +3382 Abs(CompBlueAlpha2 - CompBlueAlpha1)*blueWeightShl10 +3383 Abs(CompGreenAlpha2 - CompGreenAlpha1)*greenWeightShl10) shr 10;3384 ColorDiff := min(ColorImportance(ec1),ColorImportance(ec2));3385 if ColorDiff > 0 then3386 begin3387 TempHueDiff := HueDiff(HtoG(GetHue(ec1)),HtoG(GetHue(ec2)));3388 if TempHueDiff < 32768 then3389 TempHueDiff := LessStartSlope65535(TempHueDiff shl 1) shr 43390 else3391 TempHueDiff := TempHueDiff shr 3;3392 Result := ((Result shr 4)* (not ColorDiff) + TempHueDiff*ColorDiff) shr 12;3393 end;3394 DiffAlpha := Abs(integer(ec2.Alpha) - integer(ec1.Alpha));3395 if DiffAlpha > Result then3396 Result := DiffAlpha;3397 end;3398 3399 function BGRAWordDiff(c1, c2: TBGRAPixel): word;3400 begin3401 result := ExpandedDiff(GammaExpansion(c1),GammaExpansion(c2));3402 end;3403 3404 function BGRADiff(c1,c2: TBGRAPixel): byte;3405 begin3406 result := ExpandedDiff(GammaExpansion(c1),GammaExpansion(c2)) shr 8;3407 end;3408 3409 operator-(const c1, c2: TColorF): TColorF;3410 begin3411 result[1] := c1[1]-c2[1];3412 result[2] := c1[2]-c2[2];3413 result[3] := c1[3]-c2[3];3414 result[4] := c1[4]-c2[4];3415 end;3416 3417 operator+(const c1, c2: TColorF): TColorF;3418 begin3419 result[1] := c1[1]+c2[1];3420 result[2] := c1[2]+c2[2];3421 result[3] := c1[3]+c2[3];3422 result[4] := c1[4]+c2[4];3423 end;3424 3425 operator*(const c1, c2: TColorF): TColorF;3426 begin3427 result[1] := c1[1]*c2[1];3428 result[2] := c1[2]*c2[2];3429 result[3] := c1[3]*c2[3];3430 result[4] := c1[4]*c2[4];3431 end;3432 3433 operator*(const c1: TColorF; factor: single): TColorF;3434 begin3435 result[1] := c1[1]*factor;3436 result[2] := c1[2]*factor;3437 result[3] := c1[3]*factor;3438 result[4] := c1[4]*factor;3439 end;3440 3441 function ColorF(red, green, blue, alpha: single): TColorF;3442 begin3443 result[1] := red;3444 result[2] := green;3445 result[3] := blue;3446 result[4] := alpha;3447 end;3448 3449 { Write a color in hexadecimal format RRGGBBAA or using the name in a color list }3450 function BGRAToStr(c: TBGRAPixel; AColorList: TBGRAColorList = nil; AMaxDiff: Word= 0): string;3451 var idx: integer;3452 begin3453 if Assigned(AColorList) then3454 begin3455 idx := AColorList.IndexOfColor(c, AMaxDiff);3456 if idx<> -1 then3457 begin3458 result := AColorList.Name[idx];3459 exit;3460 end;3461 end;3462 result := IntToHex(c.red,2)+IntToHex(c.green,2)+IntToHex(c.Blue,2)+IntToHex(c.Alpha,2);3463 end;3464 3465 type3466 arrayOfString = array of string;3467 3468 function SimpleParseFuncParam(str: string; var flagError: boolean): arrayOfString;3469 var idxOpen,start,cur: integer;3470 begin3471 result := nil;3472 idxOpen := pos('(',str);3473 if idxOpen = 0 then3474 begin3475 start := 1;3476 //find first space3477 while (start <= length(str)) and (str[start]<>' ') do inc(start);3478 end else3479 start := idxOpen+1;3480 cur := start;3481 while cur <= length(str) do3482 begin3483 if str[cur] in[',',')'] then3484 begin3485 setlength(result,length(result)+1);3486 result[high(result)] := trim(copy(str,start,cur-start));3487 start := cur+1;3488 if str[cur] = ')' then exit;3489 end;3490 inc(cur);3491 end;3492 if idxOpen <> 0 then flagError := true; //should exit on ')'3493 if start <= length(str) then3494 begin3495 setlength(result,length(result)+1);3496 result[high(result)] := copy(str,start,length(str)-start+1);3497 end;3498 end;3499 3500 function ParseColorValue(str: string; var flagError: boolean): byte;3501 var pourcent,unclipped,{%H-}errPos: integer;3502 begin3503 if str = '' then result := 0 else3504 begin3505 if str[length(str)]='%' then3506 begin3507 val(copy(str,1,length(str)-1),pourcent,errPos);3508 if errPos <> 0 then flagError := true;3509 if pourcent < 0 then result := 0 else3510 if pourcent > 100 then result := 255 else3511 result := pourcent*255 div 100;3512 end else3513 begin3514 val(str,unclipped,errPos);3515 if errPos <> 0 then flagError := true;3516 if unclipped < 0 then result := 0 else3517 if unclipped > 255 then result := 255 else3518 result := unclipped;3519 end;3520 end;3521 end;3522 3523 //this function returns the parsed value only if it contains no error nor missing values, otherwise3524 //it returns BGRAPixelTransparent3525 function StrToBGRA(str: string): TBGRAPixel;3526 var missingValues, error: boolean;3527 begin3528 result := BGRABlack;3529 TryStrToBGRA(str, result, missingValues, error);3530 if missingValues or error then result := BGRAPixelTransparent;3531 end;3532 3533 //this function changes the content of parsedValue depending on available and parsable information.3534 //set parsedValue to the fallback values before calling this function.3535 //missing values are expressed by empty string or by '?', for example 'rgb(255,?,?,?)' will change only the red value.3536 //note that if alpha is not expressed by the string format, it will be opaque. So 'rgb(255,?,?)' will change the red value and the alpha value.3537 //the last parameter of rgba() is a floating point number where 1 is opaque and 0 is transparent.3538 procedure TryStrToBGRA(str: string; var parsedValue: TBGRAPixel; out missingValues: boolean; out error: boolean);3539 var errPos: integer;3540 values: array of string;3541 alphaF: single;3542 idx: integer;3543 begin3544 str := Trim(str);3545 error := false;3546 if (str = '') or (str = '?') then3547 begin3548 missingValues := true;3549 exit;3550 end else3551 missingValues := false;3552 str := StringReplace(lowerCase(str),'grey','gray',[]);3553 3554 //VGA color names3555 idx := VGAColors.IndexOf(str);3556 if idx <> -1 then3557 begin3558 parsedValue := VGAColors[idx];3559 exit;3560 end;3561 if str='transparent' then parsedValue := BGRAPixelTransparent else3562 begin3563 //check CSS color3564 idx := CSSColors.IndexOf(str);3565 if idx <> -1 then3566 begin3567 parsedValue := CSSColors[idx];3568 exit;3569 end;3570 3571 //CSS RGB notation3572 if (copy(str,1,4)='rgb(') or (copy(str,1,5)='rgba(') or3573 (copy(str,1,4)='rgb ') or (copy(str,1,5)='rgba ') then3574 begin3575 values := SimpleParseFuncParam(str,error);3576 if (length(values)=3) or (length(values)=4) then3577 begin3578 if (values[0] <> '') and (values[0] <> '?') then3579 parsedValue.red := ParseColorValue(values[0], error)3580 else3581 missingValues := true;3582 if (values[1] <> '') and (values[1] <> '?') then3583 parsedValue.green := ParseColorValue(values[1], error)3584 else3585 missingValues := true;3586 if (values[2] <> '') and (values[2] <> '?') then3587 parsedValue.blue := ParseColorValue(values[2], error)3588 else3589 missingValues := true;3590 if length(values)=4 then3591 begin3592 if (values[3] <> '') and (values[3] <> '?') then3593 begin3594 val(values[3],alphaF,errPos);3595 if errPos <> 0 then3596 begin3597 parsedValue.alpha := 255;3598 error := true;3599 end3600 else3601 begin3602 if alphaF < 0 then3603 parsedValue.alpha := 0 else3604 if alphaF > 1 then3605 parsedValue.alpha := 2553606 else3607 parsedValue.alpha := round(alphaF*255);3608 end;3609 end else3610 missingValues := true;3611 end else3612 parsedValue.alpha := 255;3613 end else3614 error := true;3615 exit;3616 end;3617 3618 //remove HTML notation header3619 if str[1]='#' then delete(str,1,1);3620 3621 //add alpha if missing (if you want an undefined alpha use '??' or '?')3622 if length(str)=6 then str += 'FF';3623 if length(str)=3 then str += 'F';3624 3625 //hex notation3626 if length(str)=8 then3627 begin3628 if copy(str,1,2) <> '??' then3629 begin3630 val('$'+copy(str,1,2),parsedValue.red,errPos);3631 if errPos <> 0 then error := true;3632 end else missingValues := true;3633 if copy(str,3,2) <> '??' then3634 begin3635 val('$'+copy(str,3,2),parsedValue.green,errPos);3636 if errPos <> 0 then error := true;3637 end else missingValues := true;3638 if copy(str,5,2) <> '??' then3639 begin3640 val('$'+copy(str,5,2),parsedValue.blue,errPos);3641 if errPos <> 0 then error := true;3642 end else missingValues := true;3643 if copy(str,7,2) <> '??' then3644 begin3645 val('$'+copy(str,7,2),parsedValue.alpha,errPos);3646 if errPos <> 0 then3647 begin3648 error := true;3649 parsedValue.alpha := 255;3650 end;3651 end else missingValues := true;3652 end else3653 if length(str)=4 then3654 begin3655 if str[1] <> '?' then3656 begin3657 val('$'+str[1],parsedValue.red,errPos);3658 if errPos <> 0 then error := true;3659 parsedValue.red *= $11;3660 end else missingValues := true;3661 if str[2] <> '?' then3662 begin3663 val('$'+str[2],parsedValue.green,errPos);3664 if errPos <> 0 then error := true;3665 parsedValue.green *= $11;3666 end else missingValues := true;3667 if str[3] <> '?' then3668 begin3669 val('$'+str[3],parsedValue.blue,errPos);3670 if errPos <> 0 then error := true;3671 parsedValue.blue *= $11;3672 end else missingValues := true;3673 if str[4] <> '?' then3674 begin3675 val('$'+str[4],parsedValue.alpha,errPos);3676 if errPos <> 0 then3677 begin3678 error := true;3679 parsedValue.alpha := 255;3680 end else3681 parsedValue.alpha *= $11;3682 end else missingValues := true;3683 end else3684 error := true; //string format not recognised3685 end;3686 3687 end;3688 3689 //this function returns the values that can be read from the string, otherwise3690 //it fills the gaps with the fallback values. The error boolean is True only3691 //if there was invalid values, it is not set to True if there was missing values.3692 function PartialStrToBGRA(str: string; const fallbackValues: TBGRAPixel; out3693 error: boolean): TBGRAPixel;3694 var missingValues: boolean;3695 begin3696 result := fallbackValues;3697 TryStrToBGRA(str, result, missingValues, error);3698 end;3699 3700 { Read a color, for example in hexadecimal format RRGGBB(AA) or RGB(A). Partial colors are not accepted by this function. }3701 function StrToBGRA(str: string; const DefaultColor: TBGRAPixel): TBGRAPixel;3702 var missingValues, error: boolean;3703 begin3704 result := BGRABlack;3705 TryStrToBGRA(str, result, missingValues, error);3706 if missingValues or error then result := DefaultColor;3707 end;3708 3709 function MapHeight(Color: TBGRAPixel): Single;3710 var intval: integer;3711 begin3712 intval := color.Green shl 16 + color.red shl 8 + color.blue;3713 result := intval*5.960464832810452e-8;3714 end;3715 3716 function MapHeightToBGRA(Height: Single; Alpha: Byte): TBGRAPixel;3717 var intval: integer;3718 begin3719 if Height >= 1 then result := BGRA(255,255,255,alpha) else3720 if Height <= 0 then result := BGRA(0,0,0,alpha) else3721 begin3722 intval := round(Height*16777215);3723 result := BGRA(intval shr 8,intval shr 16,intval,alpha);3724 end;3725 end;3726 3727 {********************** Point functions **************************}3728 3729 function PointF(x, y: single): TPointF;3730 begin3731 Result.x := x;3732 Result.y := y;3733 end;3734 3735 function PointsF(const pts: array of TPointF): ArrayOfTPointF;3736 var3737 i: Integer;3738 begin3739 setlength(result, length(pts));3740 for i := 0 to high(pts) do result[i] := pts[i];3741 end;3742 3743 operator =(const pt1, pt2: TPointF): boolean;3744 begin3745 result := (pt1.x = pt2.x) and (pt1.y = pt2.y);3746 end;3747 3748 operator-(const pt1, pt2: TPointF): TPointF;3749 begin3750 result.x := pt1.x-pt2.x;3751 result.y := pt1.y-pt2.y;3752 end;3753 3754 operator-(const pt2: TPointF): TPointF;3755 begin3756 result.x := -pt2.x;3757 result.y := -pt2.y;3758 end;3759 3760 operator+(const pt1, pt2: TPointF): TPointF;3761 begin3762 result.x := pt1.x+pt2.x;3763 result.y := pt1.y+pt2.y;3764 end;3765 3766 operator*(const pt1, pt2: TPointF): single;3767 begin3768 result := pt1.x*pt2.x + pt1.y*pt2.y;3769 end;3770 3771 operator*(const pt1: TPointF; factor: single): TPointF;3772 begin3773 result.x := pt1.x*factor;3774 result.y := pt1.y*factor;3775 end;3776 3777 operator*(factor: single; const pt1: TPointF): TPointF;3778 begin3779 result.x := pt1.x*factor;3780 result.y := pt1.y*factor;3781 end;3782 3783 function PtInRect(const pt: TPoint; r: TRect): boolean;3784 var3785 temp: integer;3786 begin3787 if r.right < r.left then3788 begin3789 temp := r.left;3790 r.left := r.right;3791 r.Right := temp;3792 end;3793 if r.bottom < r.top then3794 begin3795 temp := r.top;3796 r.top := r.bottom;3797 r.bottom := temp;3798 end;3799 Result := (pt.X >= r.left) and (pt.Y >= r.top) and (pt.X < r.right) and3800 (pt.y < r.bottom);3801 end;3802 3803 function RectWithSize(left, top, width, height: integer): TRect;3804 begin3805 result.left := left;3806 result.top := top;3807 result.right := left+width;3808 result.bottom := top+height;3809 end;3810 3811 function VectLen(dx, dy: single): single;3812 begin3813 result := sqrt(dx*dx+dy*dy);3814 end;3815 3816 function VectLen(v: TPointF): single;3817 begin3818 result := sqrt(v.x*v.x+v.y*v.y);3819 end;3820 {$OPTIMIZATION OFF} // Modif J.P 5/20133821 function IntersectLine(line1, line2: TLineDef): TPointF;3822 var parallel: boolean;3823 begin3824 result := IntersectLine(line1,line2,parallel);3825 end;3826 {$OPTIMIZATION ON}3827 3828 function IntersectLine(line1, line2: TLineDef; out parallel: boolean): TPointF;3829 var divFactor: double;3830 begin3831 parallel := false;3832 //if lines are parallel3833 if ((line1.dir.x = line2.dir.x) and (line1.dir.y = line2.dir.y)) or3834 ((abs(line1.dir.y) < 1e-6) and (abs(line2.dir.y) < 1e-6)) then3835 begin3836 parallel := true;3837 //return the center of the segment between line origins3838 result.x := (line1.origin.x+line2.origin.x)/2;3839 result.y := (line1.origin.y+line2.origin.y)/2;3840 end else3841 if abs(line1.dir.y) < 1e-6 then //line1 is horizontal3842 begin3843 result.y := line1.origin.y;3844 result.x := line2.origin.x + (result.y - line2.origin.y)3845 /line2.dir.y*line2.dir.x;3846 end else3847 if abs(line2.dir.y) < 1e-6 then //line2 is horizontal3848 begin3849 result.y := line2.origin.y;3850 result.x := line1.origin.x + (result.y - line1.origin.y)3851 /line1.dir.y*line1.dir.x;3852 end else3853 begin3854 divFactor := line1.dir.x/line1.dir.y - line2.dir.x/line2.dir.y;3855 if abs(divFactor) < 1e-6 then //almost parallel3856 begin3857 parallel := true;3858 //return the center of the segment between line origins3859 result.x := (line1.origin.x+line2.origin.x)/2;3860 result.y := (line1.origin.y+line2.origin.y)/2;3861 end else3862 begin3863 result.y := (line2.origin.x - line1.origin.x +3864 line1.origin.y*line1.dir.x/line1.dir.y -3865 line2.origin.y*line2.dir.x/line2.dir.y)3866 / divFactor;3867 result.x := line1.origin.x + (result.y - line1.origin.y)3868 /line1.dir.y*line1.dir.x;3869 end;3870 end;3871 end;3872 3873 { Check if a polygon is convex, i.e. it always turns in the same direction }3874 function IsConvex(const pts: array of TPointF; IgnoreAlign: boolean = true): boolean;3875 var3876 positive,negative,zero: boolean;3877 product: single;3878 i: Integer;3879 begin3880 positive := false;3881 negative := false;3882 zero := false;3883 for i := 0 to high(pts) do3884 begin3885 product := (pts[(i+1) mod length(pts)].x-pts[i].x)*(pts[(i+2) mod length(pts)].y-pts[i].y) -3886 (pts[(i+1) mod length(pts)].y-pts[i].y)*(pts[(i+2) mod length(pts)].x-pts[i].x);3887 if product > 0 then3888 begin3889 if negative then3890 begin3891 result := false;3892 exit;3893 end;3894 positive := true;3895 end else3896 if product < 0 then3897 begin3898 if positive then3899 begin3900 result := false;3901 exit;3902 end;3903 negative := true;3904 end else3905 zero := true;3906 end;3907 if not IgnoreAlign and zero then3908 result := false3909 else3910 result := true;3911 end;3912 3913 { Check if two segments intersect }3914 function DoesSegmentIntersect(pt1,pt2,pt3,pt4: TPointF): boolean;3915 var3916 seg1: TLineDef;3917 seg1len: single;3918 seg2: TLineDef;3919 seg2len: single;3920 inter: TPointF;3921 pos1,pos2: single;3922 para: boolean;3923 3924 begin3925 { Determine line definitions }3926 seg1.origin := pt1;3927 seg1.dir := pt2-pt1;3928 seg1len := sqrt(sqr(seg1.dir.X)+sqr(seg1.dir.Y));3929 if seg1len = 0 then3930 begin3931 result := false;3932 exit;3933 end;3934 seg1.dir *= 1/seg1len;3935 3936 seg2.origin := pt3;3937 seg2.dir := pt4-pt3;3938 seg2len := sqrt(sqr(seg2.dir.X)+sqr(seg2.dir.Y));3939 if seg2len = 0 then3940 begin3941 result := false;3942 exit;3943 end;3944 seg2.dir *= 1/seg2len;3945 3946 //obviously parallel3947 if seg1.dir = seg2.dir then3948 result := false3949 else3950 begin3951 //try to compute intersection3952 inter := IntersectLine(seg1,seg2,para);3953 if para then3954 result := false3955 else3956 begin3957 //check if intersections are inside the segments3958 pos1 := (inter-seg1.origin)*seg1.dir;3959 pos2 := (inter-seg2.origin)*seg2.dir;3960 if (pos1 >= 0) and (pos1 <= seg1len) and3961 (pos2 >= 0) and (pos2 <= seg2len) then3962 result := true3963 else3964 result := false;3965 end;3966 end;3967 end;3968 3969 { Check if a quaduadrilateral intersects itself }3970 function DoesQuadIntersect(pt1,pt2,pt3,pt4: TPointF): boolean;3971 begin3972 result := DoesSegmentIntersect(pt1,pt2,pt3,pt4) or DoesSegmentIntersect(pt2,pt3,pt4,pt1);3973 612 end; 3974 613 … … 4110 749 begin 4111 750 for i := 0 to 6 do dwords[i] := LEtoN(dwords[i]); 4112 if (dwords[0] = 0) and (dwords[1] <= expectedFileSize) and (dwords[5] <= expectedFileSize) and4113 (dwords[9] <= expectedFileSize) and751 if (dwords[0] = 0) and (dwords[1] <= maxFileSize) and (dwords[5] <= maxFileSize) and 752 (dwords[9] <= maxFileSize) and 4114 753 (dwords[6] = 0) then inc(scores[ifLazPaint],2); 4115 754 end; … … 4199 838 end; 4200 839 840 if (copy(magicAsText,1,4) = 'oXo ') then 841 begin 842 inc(scores[ifPhoxo],1); 843 if (magic[4] = 1) and (magic[5] = 0) and (magic[6] = 0) and (magic[7] = 0) then 844 inc(scores[ifPhoxo],1); 845 end; 846 4201 847 DetectLazPaint; 4202 848 … … 4233 879 4234 880 ASuggestedExtensionUTF8:= UTF8LowerCase(ASuggestedExtensionUTF8); 4235 if (ASuggestedExtensionUTF8 <> '') and ( UTF8Copy(ASuggestedExtensionUTF8,1,1) <> '.') then881 if (ASuggestedExtensionUTF8 <> '') and (ASuggestedExtensionUTF8[1] <> '.') then //first UTF8 char is in first pos 4236 882 ASuggestedExtensionUTF8 := '.'+ASuggestedExtensionUTF8; 4237 883 … … 4254 900 function SuggestImageFormat(AFilenameOrExtensionUTF8: string): TBGRAImageFormat; 4255 901 var ext: string; 902 posDot: integer; 4256 903 begin 4257 904 result := ifUnknown; 4258 905 4259 906 ext := ExtractFileName(AFilenameOrExtensionUTF8); 4260 if pos('.', ext) <> 0 then ext := ExtractFileExt(ext) else ext := '.'+ext; 907 posDot := LastDelimiter('.', ext); 908 if posDot <> 0 then ext := copy(ext,posDot,length(ext)-posDot+1) 909 else ext := '.'+ext; 4261 910 ext := UTF8LowerCase(ext); 4262 911 … … 4274 923 if (ext = '.tif') or (ext = '.tiff') then result := ifTiff else 4275 924 if (ext = '.xwd') then result := ifXwd else 4276 if (ext = '.xpm') then result := ifXPixMap; 925 if (ext = '.xpm') then result := ifXPixMap else 926 if (ext = '.oxo') then result := ifPhoxo; 927 end; 928 929 function SuggestImageExtension(AFormat: TBGRAImageFormat): string; 930 begin 931 case AFormat of 932 ifJpeg: result := 'jpg'; 933 ifPng: result := 'png'; 934 ifGif: result := 'gif'; 935 ifBmp: result := 'bmp'; 936 ifIco: result := 'ico'; 937 ifPcx: result := 'pcx'; 938 ifPaintDotNet: result := 'pdn'; 939 ifLazPaint: result := 'lzp'; 940 ifOpenRaster: result := 'ora'; 941 ifPsd: result := 'psd'; 942 ifTarga: result := 'tga'; 943 ifTiff: result := 'tif'; 944 ifXwd: result := 'xwd'; 945 ifXPixMap: result := 'xpm'; 946 ifBmpMioMap: result := 'bmp'; 947 else result := '?'; 948 end; 4277 949 end; 4278 950 … … 4306 978 if AFormat = ifPng then 4307 979 begin 4308 result := TFPWriterPNG.Create; 4309 TFPWriterPNG(result).Indexed := false; 4310 TFPWriterPNG(result).WordSized := false; 4311 TFPWriterPNG(result).UseAlpha := AHasTransparentPixels; 980 result := TBGRAWriterPNG.Create; 981 TBGRAWriterPNG(result).UseAlpha := AHasTransparentPixels; 4312 982 end else 4313 983 if AFormat = ifBmp then … … 4328 998 initialization 4329 999 4330 InitGamma; 4331 {$DEFINE INCLUDE_COLOR_LIST} 1000 {$DEFINE INCLUDE_INIT} 1001 {$I bgrapixel.inc} 1002 1003 {$DEFINE INCLUDE_INIT} 4332 1004 {$I csscolorconst.inc} 1005 4333 1006 DefaultBGRAImageWriter[ifJpeg] := TFPWriterJPEG; 4334 DefaultBGRAImageWriter[ifPng] := T FPWriterPNG;1007 DefaultBGRAImageWriter[ifPng] := TBGRAWriterPNG; 4335 1008 DefaultBGRAImageWriter[ifBmp] := TFPWriterBMP; 4336 1009 DefaultBGRAImageWriter[ifPcx] := TFPWriterPCX; … … 4346 1019 finalization 4347 1020 4348 CSSColors.Free; 4349 VGAColors.Free; 4350 1021 {$DEFINE INCLUDE_FINAL} 1022 {$I csscolorconst.inc} 1023 1024 {$DEFINE INCLUDE_FINAL} 1025 {$I bgrapixel.inc} 4351 1026 end.
Note:
See TracChangeset
for help on using the changeset viewer.