source: trunk/Packages/bgrabitmap/bgrapixel.inc

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 24.2 KB
Line 
1{=== Pixel types and functions ===}
2
3{$IFDEF INCLUDE_INTERFACE}
4{$UNDEF INCLUDE_INTERFACE}
5type
6 {* Pointer for direct pixel access. Data is stored as a sequence of ''TBGRAPixel''.
7 See [[BGRABitmap tutorial 4]] }
8 PBGRAPixel = ^TBGRAPixel;
9
10 {$IFNDEF BGRABITMAP_BGRAPIXEL}
11 {$IFDEF BGRABITMAP_USE_LCL}
12 {$IFDEF LCLgtk}
13 {$DEFINE BGRABITMAP_RGBAPIXEL}
14 {$ENDIF}
15 {$IFDEF LCLgtk2}
16 {$DEFINE BGRABITMAP_RGBAPIXEL}
17 {$ENDIF}
18 {$IFDEF DARWIN}
19 {$IFNDEF LCLQt}
20 {$DEFINE BGRABITMAP_RGBAPIXEL}
21 {$ENDIF}
22 {$ENDIF}
23 {$ENDIF}
24 {$ENDIF}
25
26 {* Each pixel is a sequence of 4 bytes containing blue, green, red and alpha channel.
27 Values range from 0 to 255, color is in sRGB colorspace. The alpha value of 0
28 is transparent and 255 is opaque. In the bitmap data, when the pixel is fully transparent,
29 the RGB values are supposed to be set to zero. }
30
31 { TBGRAPixel }
32
33 TBGRAPixel = packed record
34 private
35 function GetClassIntensity: word;
36 function GetClassLightness: word;
37 procedure SetClassIntensity(AValue: word);
38 procedure SetClassLightness(AValue: word);
39 public
40 {$IFDEF BGRABITMAP_RGBAPIXEL}
41 red, green, blue, alpha: byte;
42 {$ELSE}
43 blue, green, red, alpha: byte;
44 {$ENDIF}
45 procedure FromRGB(ARed,AGreen,ABlue: Byte; AAlpha: Byte = 255);
46 procedure FromColor(AColor: TColor; AAlpha: Byte = 255);
47 procedure FromString(AStr: string);
48 procedure FromFPColor(AColor: TFPColor);
49 procedure ToRGB(out ARed,AGreen,ABlue,AAlpha: Byte); overload;
50 procedure ToRGB(out ARed,AGreen,ABlue: Byte); overload;
51 function ToColor: TColor;
52 function ToString: string;
53 function ToGrayscale(AGammaCorrection: boolean = true): TBGRAPixel;
54 function ToFPColor: TFPColor;
55 class Operator := (Source: TBGRAPixel): TColor;
56 class Operator := (Source: TColor): TBGRAPixel;
57 property Intensity: word read GetClassIntensity write SetClassIntensity;
58 property Lightness: word read GetClassLightness write SetClassLightness;
59 end;
60 TBGRAPixelBuffer = packed array of TBGRAPixel;
61
62procedure AllocateBGRAPixelBuffer(var ABuffer: TBGRAPixelBuffer; ASize: integer);
63
64const
65 {$IFDEF BGRABITMAP_RGBAPIXEL}
66 TBGRAPixel_RGBAOrder = True;
67 TBGRAPixel_RedByteOffset = 0;
68 TBGRAPixel_GreenByteOffset = 1;
69 TBGRAPixel_BlueByteOffset = 2;
70 {$ELSE}
71 TBGRAPixel_RGBAOrder = False;
72 TBGRAPixel_BlueByteOffset = 0;
73 TBGRAPixel_GreenByteOffset = 1;
74 TBGRAPixel_RedByteOffset = 2;
75 {$ENDIF}
76 TBGRAPixel_AlphaByteOffset = 3;
77 {$IFDEF ENDIAN_LITTLE}
78 TBGRAPixel_RedShift = TBGRAPixel_RedByteOffset*8;
79 TBGRAPixel_GreenShift = TBGRAPixel_GreenByteOffset*8;
80 TBGRAPixel_BlueShift = TBGRAPixel_BlueByteOffset*8;
81 TBGRAPixel_AlphaShift = TBGRAPixel_AlphaByteOffset*8;
82 {$ELSE}
83 TBGRAPixel_RedShift = 24 - TBGRAPixel_RedByteOffset*8;
84 TBGRAPixel_GreenShift = 24 - TBGRAPixel_GreenByteOffset*8;
85 TBGRAPixel_BlueShift = 24 - TBGRAPixel_BlueByteOffset*8;
86 TBGRAPixel_AlphaShift = 24 - TBGRAPixel_AlphaByteOffset*8;
87 {$ENDIF}
88
89 {** Creates a pixel with given RGBA values }
90 function BGRA(red, green, blue, alpha: byte): TBGRAPixel; overload; inline;
91 {** Creates a opaque pixel with given RGB values }
92 function BGRA(red, green, blue: byte): TBGRAPixel; overload; inline;
93 {** Checks if two pixels are equal. If they are both transparent,
94 RGB values are ignored }
95 operator = (const c1, c2: TBGRAPixel): boolean; inline;
96 {** Returns the intensity of a pixel. The intensity is the
97 maximum value reached by any component }
98 function GetIntensity(c: TBGRAPixel): word; inline;
99 {** Sets the intensity of a pixel }
100 function SetIntensity(c: TBGRAPixel; intensity: word): TBGRAPixel;
101 {** Returns the lightness of a pixel. The lightness is the
102 perceived brightness, 0 being black and 65535 being white }
103 function GetLightness(c: TBGRAPixel): word; overload;
104 {** Sets the lightness of a pixel }
105 function SetLightness(c: TBGRAPixel; lightness: word): TBGRAPixel; overload;
106 {** Sets the lightness quickly, by fading towards black if ''lightness'' is
107 less than 32768, and fading towards white if ''lightness'' is more
108 than 32768 }
109 function ApplyLightnessFast(color: TBGRAPixel; lightness: word): TBGRAPixel; inline;
110 {** Sets the intensity quickly, by fading towards black if ''lightness'' is
111 less than 32768, and multiplying all components if ''lightness'' is more
112 than 32768. In case of saturation, it fades towards white }
113 function ApplyIntensityFast(color: TBGRAPixel; lightness: longword): TBGRAPixel;
114 {** Combines two lightnesses together. A value of 32768 is neutral. The
115 result may exceed 65535 }
116 function CombineLightness(lightness1,lightness2: Int32or64): Int32or64;
117 {** Converts a color into grayscale }
118 function BGRAToGrayscale(c: TBGRAPixel): TBGRAPixel;
119 function BGRAToGrayscaleLinear(c: TBGRAPixel): TBGRAPixel;
120 {** Create a gray color with the given ''lightness'' }
121 function GrayscaleToBGRA(lightness: word): TBGRAPixel;
122 {** Merge two colors without gamma correction }
123 function MergeBGRA(c1, c2: TBGRAPixel): TBGRAPixel; overload;
124 {** Merge two colors without gamma correction. ''weight1'' and ''weight2''
125 indicates the weight of the color barycentre }
126 function MergeBGRA(c1: TBGRAPixel; weight1: integer; c2: TBGRAPixel; weight2: integer): TBGRAPixel; overload;
127 {** Merge two colors with gamma correction. ''weight1'' and ''weight2''
128 indicates the weight of the color barycentre }
129 function MergeBGRAWithGammaCorrection(c1: TBGRAPixel; weight1: byte; c2: TBGRAPixel; weight2: byte): TBGRAPixel;
130 {** Converts a ''TColor'' value into an opaque pixel }
131 function ColorToBGRA(color: TColor): TBGRAPixel; overload;
132 {** Converts a ''TColor'' value into a pixel with given ''opacity'' }
133 function ColorToBGRA(color: TColor; opacity: byte): TBGRAPixel; overload;
134 {** Converts a pixel into a TColor value, discarding the alpha value }
135 function BGRAToColor(c: TBGRAPixel): TColor;
136 {** Converts a ''TFPColor'' value into a pixel. Note that even if
137 ''TFPColor'' have 16-bit values, they are not considered as
138 gamma expanded }
139 function FPColorToBGRA(AValue: TFPColor): TBGRAPixel;
140 {** Converts a pixel into a ''TFPColor'' }
141 function BGRAToFPColor(AValue: TBGRAPixel): TFPColor; inline;
142 function Color16BitToBGRA(AColor: Word): TBGRAPixel;
143 function BGRAToColor16Bit(const AColor: TBGRAPixel): Word;
144 {** Computes the difference (with gamma correction) between two pixels,
145 taking into account all dimensions, including transparency. The
146 result ranges from 0 to 65535 }
147 function BGRAWordDiff(c1, c2: TBGRAPixel): word;
148 {** Computes the difference (with gamma correction) between two pixels,
149 taking into account all dimensions, including transparency. The
150 result ranges from 0 to 255 }
151 function BGRADiff(c1, c2: TBGRAPixel): byte;
152 function FastBGRALinearDiff(c1,c2: TBGRAPixel): byte;
153 function FastBGRAExpandedDiff(c1,c2: TBGRAPixel): word;
154
155type
156 {* Array of pixels }
157 ArrayOfTBGRAPixel = array of TBGRAPixel;
158 {** Merge given colors without gamma correction }
159 function MergeBGRA(const colors: array of TBGRAPixel): TBGRAPixel; overload;
160
161{ Get height [0..1] stored in a TBGRAPixel }
162function MapHeight(Color: TBGRAPixel): Single;
163
164{ Get TBGRAPixel to store height [0..1] }
165function MapHeightToBGRA(Height: Single; Alpha: Byte): TBGRAPixel;
166
167type
168 {* Possible modes when drawing a pixel over another one }
169 TDrawMode = (
170 {** The pixel is replaced }
171 dmSet,
172 {** The pixel is replaced if the pixel over has an alpha value of 255 }
173 dmSetExceptTransparent,
174 {** The pixel is blend over the other one according to alpha values,
175 however no gamma correction is applied. In other words, the color
176 space is assumed to be linear }
177 dmLinearBlend,
178 {** The pixel is blend over the other one according to alpha values,
179 and a gamma correction is applied. In other word, the color
180 space is assumed to be sRGB }
181 dmDrawWithTransparency,
182 {** Values of all channels are combined with Xor. This is useful to
183 compute the binary difference, however it is not something that makes
184 much sense to display on the screen }
185 dmXor);
186
187const
188 {** An alias for the linear blend, because it is faster than blending
189 with gamma correction }
190 dmFastBlend = dmLinearBlend;
191
192type
193 {* Advanced blending modes. See [http://www.brighthub.com/multimedia/photography/articles/18301.aspx Paint.NET blend modes]
194 and [http://www.pegtop.net/delphi/articles/blendmodes/ Formulas]. Blending layers has two steps. The first one is
195 to apply the blend operations listed below, and the second is the actual merging of the colors }
196 TBlendOperation = (
197 {** Simple blend, except that it forces a linear merge so it is equivalent to ''dmLinearBlend'' }
198 boLinearBlend,
199 {** Simple blend. It is equivalent to ''dmLinearBlend'' or ''dmDrawWithTransparency'' }
200 boTransparent,
201 {** Lighting blend modes (tends to increase the luminosity) }
202 boLighten, boScreen, boAdditive, boLinearAdd, boColorDodge, boDivide, boNiceGlow, boSoftLight, boHardLight,
203 {** Masking blend modes (tends to decrease the luminosity) }
204 boGlow, boReflect, boOverlay, boDarkOverlay, boDarken, boMultiply, boColorBurn,
205 {** Difference blend modes }
206 boDifference, boLinearDifference, boExclusion, boLinearExclusion, boSubtract, boLinearSubtract, boSubtractInverse, boLinearSubtractInverse,
207 {** Negation blend modes }
208 boNegation, boLinearNegation,
209 {** Xor blend mode. It is sightly different from ''dmXor'' because the alpha value is used like in other blends modes }
210 boXor,
211 {** Additional blend modes **}
212 boSvgSoftLight);
213
214const
215 {** Alias to glow that express that this blend mode masks the part where the top layer is black }
216 boGlowMask = boGlow;
217 {** Alias because linear or non linear multiply modes are identical }
218 boLinearMultiply = boMultiply;
219 {** Alias to express that dark overlay is simply an overlay with gamma correction }
220 boNonLinearOverlay = boDarkOverlay;
221
222const
223 {** String constants for blend modes }
224 BlendOperationStr : array[TBlendOperation] of string
225 = ('LinearBlend', 'Transparent',
226 'Lighten', 'Screen', 'Additive', 'LinearAdd', 'ColorDodge', 'Divide', 'NiceGlow', 'SoftLight', 'HardLight',
227 'Glow', 'Reflect', 'Overlay', 'DarkOverlay', 'Darken', 'Multiply', 'ColorBurn',
228 'Difference', 'LinearDifference', 'Exclusion', 'LinearExclusion', 'Subtract', 'LinearSubtract', 'SubtractInverse', 'LinearSubtractInverse',
229 'Negation', 'LinearNegation', 'Xor', 'SvgSoftLight');
230
231 {** Returns the blend mode expressed by the string }
232 function StrToBlendOperation(str: string): TBlendOperation;
233
234type
235 {* Specifies how a palette handles the alpha channel }
236 TAlphaChannelPaletteOption = (
237 {** The alpha channel is ignored. The alpha channel is considered to be stored elsewhere }
238 acIgnore,
239 {** One entry is allocated the fully transparent color }
240 acTransparentEntry,
241 {** The alpha channel is fully embedded in the palette so that a color is identified by its four RGBA channels }
242 acFullChannelInPalette);
243
244 {* Dithering algorithms that specifies how to handle colors that are not found in the palette }
245 TDitheringAlgorithm = (
246 {** The nearest color is to be used instead }
247 daNearestNeighbor,
248 {** The nearest color may be used however another color may be used to compensate for the error,
249 following Floyd-Steinberg algorithm }
250 daFloydSteinberg);
251
252{$DEFINE INCLUDE_INTERFACE}
253{$i basiccolorspace.inc}
254
255{$DEFINE INCLUDE_INTERFACE}
256{$i extendedcolorspace.inc}
257
258{$ENDIF}
259
260{$IFDEF INCLUDE_IMPLEMENTATION}
261{$UNDEF INCLUDE_IMPLEMENTATION}
262
263{$DEFINE INCLUDE_IMPLEMENTATION}
264{$i basiccolorspace.inc}
265
266{$DEFINE INCLUDE_IMPLEMENTATION}
267{$i extendedcolorspace.inc}
268
269function StrToBlendOperation(str: string): TBlendOperation;
270var op: TBlendOperation;
271begin
272 result := boTransparent;
273 str := LowerCase(str);
274 for op := low(TBlendOperation) to high(TBlendOperation) do
275 if str = LowerCase(BlendOperationStr[op]) then
276 begin
277 result := op;
278 exit;
279 end;
280end;
281
282{************************** Color functions **************************}
283
284procedure AllocateBGRAPixelBuffer(var ABuffer: TBGRAPixelBuffer; ASize: integer);
285begin
286 if ASize > length(ABuffer) then
287 setlength(ABuffer, max(length(ABuffer)*2,ASize));
288end;
289
290function BGRA(red, green, blue, alpha: byte): TBGRAPixel;
291begin
292 DWord(result) := (red shl TBGRAPixel_RedShift) or
293 (green shl TBGRAPixel_GreenShift) or
294 (blue shl TBGRAPixel_BlueShift) or
295 (alpha shl TBGRAPixel_AlphaShift);
296end;
297
298function BGRA(red, green, blue: byte): TBGRAPixel; overload;
299begin
300 DWord(result) := (red shl TBGRAPixel_RedShift) or
301 (green shl TBGRAPixel_GreenShift) or
302 (blue shl TBGRAPixel_BlueShift) or
303 (255 shl TBGRAPixel_AlphaShift);
304end;
305
306operator = (const c1, c2: TBGRAPixel): boolean;
307begin
308 if (c1.alpha = 0) and (c2.alpha = 0) then
309 Result := True
310 else
311 Result := (c1.alpha = c2.alpha) and (c1.red = c2.red) and
312 (c1.green = c2.green) and (c1.blue = c2.blue);
313end;
314
315function GetIntensity(c: TBGRAPixel): word;
316begin
317 Result := c.red;
318 if c.green > Result then
319 Result := c.green;
320 if c.blue > Result then
321 Result := c.blue;
322 result := GammaExpansionTab[Result];
323end;
324
325function SetIntensity(c: TBGRAPixel; intensity: word): TBGRAPixel;
326begin
327 result := GammaCompression(SetIntensity(GammaExpansion(c),intensity));
328end;
329
330function GetLightness(c: TBGRAPixel): word;
331begin
332 result := GetLightness(GammaExpansion(c));
333end;
334
335function SetLightness(c: TBGRAPixel; lightness: word): TBGRAPixel;
336begin
337 result := GammaCompression(SetLightness(GammaExpansion(c),lightness));
338end;
339
340function ApplyLightnessFast(color: TBGRAPixel; lightness: word): TBGRAPixel;
341var
342 r,g,b: word;
343 lightness256: byte;
344begin
345 if lightness <= 32768 then
346 begin
347 if lightness = 32768 then
348 result := color else
349 begin
350 lightness256 := GammaCompressionTab[lightness shl 1];
351 result := BGRA(color.red * lightness256 shr 8, color.green*lightness256 shr 8,
352 color.blue * lightness256 shr 8, color.alpha);
353 end;
354 end else
355 begin
356 if lightness = 65535 then
357 result := BGRA(255,255,255,color.alpha) else
358 begin
359 lightness -= 32767;
360 r := GammaExpansionTab[color.red];
361 g := GammaExpansionTab[color.green];
362 b := GammaExpansionTab[color.blue];
363 result := BGRA(GammaCompressionTab[ r + (not r)*lightness shr 15 ],
364 GammaCompressionTab[ g + (not g)*lightness shr 15 ],
365 GammaCompressionTab[ b + (not b)*lightness shr 15 ],
366 color.alpha);
367 end;
368 end;
369end;
370
371function ApplyIntensityFast(color: TBGRAPixel; lightness: longword): TBGRAPixel;
372var
373 maxValue,invMaxValue,r,g,b: longword;
374 lightness256: byte;
375begin
376 if lightness <= 32768 then
377 begin
378 if lightness = 32768 then
379 result := color else
380 begin
381 lightness256 := GammaCompressionTab[lightness shl 1];
382 result := BGRA(color.red * lightness256 shr 8, color.green*lightness256 shr 8,
383 color.blue * lightness256 shr 8, color.alpha);
384 end;
385 end else
386 begin
387 r := CombineLightness(GammaExpansionTab[color.red], lightness);
388 g := CombineLightness(GammaExpansionTab[color.green], lightness);
389 b := CombineLightness(GammaExpansionTab[color.blue], lightness);
390 maxValue := r;
391 if g > maxValue then maxValue := g;
392 if b > maxValue then maxValue := b;
393 if maxValue <= 65535 then
394 result := BGRA(GammaCompressionTab[r],
395 GammaCompressionTab[g],
396 GammaCompressionTab[b],
397 color.alpha)
398 else
399 begin
400 invMaxValue := (longword(2147483647)+longword(maxValue-1)) div maxValue;
401 maxValue := (maxValue-65535) shr 1;
402 r := r*invMaxValue shr 15 + maxValue;
403 g := g*invMaxValue shr 15 + maxValue;
404 b := b*invMaxValue shr 15 + maxValue;
405 if r >= 65535 then result.red := 255 else
406 result.red := GammaCompressionTab[r];
407 if g >= 65535 then result.green := 255 else
408 result.green := GammaCompressionTab[g];
409 if b >= 65535 then result.blue := 255 else
410 result.blue := GammaCompressionTab[b];
411 result.alpha := color.alpha;
412 end;
413 end;
414end;
415
416function CombineLightness(lightness1,lightness2: Int32or64): Int32or64;
417{$ifdef CPUI386} {$asmmode intel} assembler;
418 asm
419 imul edx
420 shl edx, 17
421 shr eax, 15
422 or edx, eax
423 mov result, edx
424 end;
425{$ELSE}
426begin
427 if (lightness1 < 0) xor (lightness2 < 0) then
428 result := -(int64(-lightness1)*lightness2 shr 15)
429 else
430 result := int64(lightness1)*lightness2 shr 15;
431end;
432{$ENDIF}
433
434// Conversion to grayscale by taking into account
435// different color weights
436function BGRAToGrayscale(c: TBGRAPixel): TBGRAPixel;
437var
438 ec: TExpandedPixel;
439 gray: word;
440 cgray: byte;
441begin
442 if c.alpha = 0 then
443 begin
444 result := BGRAPixelTransparent;
445 exit;
446 end;
447 //gamma expansion
448 ec := GammaExpansion(c);
449 //gray composition
450 gray := (ec.red * redWeightShl10 + ec.green * greenWeightShl10 +
451 ec.blue * blueWeightShl10 + 512) shr 10;
452 //gamma compression
453 cgray := GammaCompressionTab[gray];
454 Result.red := cgray;
455 Result.green := cgray;
456 Result.blue := cgray;
457 Result.alpha := c.alpha;
458end;
459
460function BGRAToGrayscaleLinear(c: TBGRAPixel): TBGRAPixel;
461var
462 gray: byte;
463begin
464 if c.alpha = 0 then
465 begin
466 result := BGRAPixelTransparent;
467 exit;
468 end;
469 //gray composition
470 gray := (c.red * redWeightShl10 + c.green * greenWeightShl10 +
471 c.blue * blueWeightShl10 + 512) shr 10;
472 //gamma compression
473 Result.red := gray;
474 Result.green := gray;
475 Result.blue := gray;
476 Result.alpha := c.alpha;
477end;
478
479function GrayscaleToBGRA(lightness: word): TBGRAPixel;
480begin
481 result.red := GammaCompressionTab[lightness];
482 result.green := result.red;
483 result.blue := result.red;
484 result.alpha := $ff;
485end;
486
487{ Merge linearly two colors of same importance }
488function MergeBGRA(c1, c2: TBGRAPixel): TBGRAPixel;
489var c12: cardinal;
490begin
491 if (c1.alpha = 0) then
492 Result := c2
493 else
494 if (c2.alpha = 0) then
495 Result := c1
496 else
497 begin
498 c12 := c1.alpha + c2.alpha;
499 Result.red := (c1.red * c1.alpha + c2.red * c2.alpha + c12 shr 1) div c12;
500 Result.green := (c1.green * c1.alpha + c2.green * c2.alpha + c12 shr 1) div c12;
501 Result.blue := (c1.blue * c1.alpha + c2.blue * c2.alpha + c12 shr 1) div c12;
502 Result.alpha := (c12 + 1) shr 1;
503 end;
504end;
505
506function MergeBGRA(c1: TBGRAPixel; weight1: integer; c2: TBGRAPixel;
507 weight2: integer): TBGRAPixel;
508var
509 f1,f2,f12: int64;
510begin
511 if (weight1 = 0) then
512 begin
513 if (weight2 = 0) then
514 result := BGRAPixelTransparent
515 else
516 Result := c2
517 end
518 else
519 if (weight2 = 0) then
520 Result := c1
521 else
522 if (weight1+weight2 = 0) then
523 Result := BGRAPixelTransparent
524 else
525 begin
526 f1 := int64(c1.alpha)*weight1;
527 f2 := int64(c2.alpha)*weight2;
528 f12 := f1+f2;
529 if f12 = 0 then
530 result := BGRAPixelTransparent
531 else
532 begin
533 Result.red := (c1.red * f1 + c2.red * f2 + f12 shr 1) div f12;
534 Result.green := (c1.green * f1 + c2.green * f2 + f12 shr 1) div f12;
535 Result.blue := (c1.blue * f1 + c2.blue * f2 + f12 shr 1) div f12;
536 {$hints off}
537 Result.alpha := (f12 + ((weight1+weight2) shr 1)) div (weight1+weight2);
538 {$hints on}
539 end;
540 end;
541end;
542
543function MergeBGRAWithGammaCorrection(c1: TBGRAPixel; weight1: byte; c2: TBGRAPixel;
544 weight2: byte): TBGRAPixel;
545var
546 w1,w2,f1,f2,f12,a: UInt32or64;
547begin
548 w1 := weight1;
549 w2 := weight2;
550 if (w1 = 0) then
551 begin
552 if (w2 = 0) then
553 result := BGRAPixelTransparent
554 else
555 Result := c2
556 end
557 else
558 if (w2 = 0) then
559 Result := c1
560 else
561 begin
562 f1 := c1.alpha*w1;
563 f2 := c2.alpha*w2;
564 a := (f1+f2 + ((w1+w2) shr 1)) div (w1+w2);
565 if a = 0 then
566 begin
567 result := BGRAPixelTransparent;
568 exit;
569 end else
570 Result.alpha := a;
571 {$IFNDEF CPU64}
572 if (f1 >= 32768) or (f2 >= 32768) then
573 begin
574 f1 := f1 shr 1;
575 f2 := f2 shr 1;
576 end;
577 {$ENDIF}
578 f12 := f1+f2;
579 Result.red := GammaCompressionTab[(GammaExpansionTab[c1.red] * f1 + GammaExpansionTab[c2.red] * f2) div f12];
580 Result.green := GammaCompressionTab[(GammaExpansionTab[c1.green] * f1 + GammaExpansionTab[c2.green] * f2) div f12];
581 Result.blue := GammaCompressionTab[(GammaExpansionTab[c1.blue] * f1 + GammaExpansionTab[c2.blue] * f2) div f12];
582 end;
583end;
584
585{ Convert a TColor value to a TBGRAPixel value }
586{$PUSH}{$R-}
587function ColorToBGRA(color: TColor): TBGRAPixel; overload;
588begin
589 if (color < 0) or (color > $ffffff) then color := ColorToRGB(color);
590 RedGreenBlue(color, Result.red,Result.green,Result.blue);
591 Result.alpha := 255;
592end;
593
594function ColorToBGRA(color: TColor; opacity: byte): TBGRAPixel; overload;
595begin
596 if (color < 0) or (color > $ffffff) then color := ColorToRGB(color);
597 RedGreenBlue(color, Result.red,Result.green,Result.blue);
598 Result.alpha := opacity;
599end;
600{$POP}
601
602function BGRAToColor(c: TBGRAPixel): TColor;
603begin
604 Result := RGBToColor(c.red, c.green, c.blue);
605end;
606
607{ Conversion from TFPColor to TBGRAPixel assuming TFPColor
608 is already gamma compressed }
609function FPColorToBGRA(AValue: TFPColor): TBGRAPixel;
610begin
611 with AValue do
612 Result := BGRA(red shr 8, green shr 8, blue shr 8, alpha shr 8);
613end;
614
615function BGRAToFPColor(AValue: TBGRAPixel): TFPColor; inline;
616begin
617 result.red := AValue.red shl 8 + AValue.red;
618 result.green := AValue.green shl 8 + AValue.green;
619 result.blue := AValue.blue shl 8 + AValue.blue;
620 result.alpha := AValue.alpha shl 8 + AValue.alpha;
621end;
622
623function Color16BitToBGRA(AColor: Word): TBGRAPixel;
624begin
625 result := BGRA( ((AColor and $F800) shr 11)*255 div 31,
626 ((AColor and $07e0) shr 5)*255 div 63,
627 (AColor and $001f)*255 div 31 );
628end;
629
630function BGRAToColor16Bit(const AColor: TBGRAPixel): Word;
631begin
632 result := (((AColor.Red * 31 + 64) div 255) shl 11) +
633 (((AColor.green * 63 + 64) div 255) shl 5) +
634 ((AColor.blue * 31 + 64) div 255);
635end;
636
637function BGRAWordDiff(c1, c2: TBGRAPixel): word;
638begin
639 result := ExpandedDiff(GammaExpansion(c1),GammaExpansion(c2));
640end;
641
642function BGRADiff(c1,c2: TBGRAPixel): byte;
643begin
644 result := ExpandedDiff(GammaExpansion(c1),GammaExpansion(c2)) shr 8;
645end;
646
647function FastBGRALinearDiff(c1, c2: TBGRAPixel): byte;
648begin
649 result := max(min((abs(c1.red-c2.red)+(abs(c1.green-c2.green) shl 1)+abs(c1.blue-c2.blue)) shr 2,
650 min(c1.alpha,c2.alpha)), abs(c1.alpha-c2.alpha));
651end;
652
653function FastBGRAExpandedDiff(c1, c2: TBGRAPixel): word;
654var wa1,wa2: word;
655begin
656 wa1 := c1.alpha shl 8 + c1.alpha;
657 wa2 := (c2.alpha shl 8) + c2.alpha;
658 result := max(min((abs(GammaExpansionTab[c1.red]-GammaExpansionTab[c2.red])+
659 (abs(GammaExpansionTab[c1.green]-GammaExpansionTab[c2.green]) shl 1)+
660 abs(GammaExpansionTab[c1.blue]-GammaExpansionTab[c2.blue])) shr 2,
661 min(wa1,wa2)),
662 abs(wa1-wa2));
663end;
664
665function MergeBGRA(const colors: array of TBGRAPixel): TBGRAPixel;
666var
667 sumR,sumG,sumB,sumA: NativeUInt;
668 i: integer;
669begin
670 if length(colors)<=0 then
671 begin
672 result := BGRAPixelTransparent;
673 exit;
674 end;
675 sumR := 0;
676 sumG := 0;
677 sumB := 0;
678 sumA := 0;
679 for i := 0 to high(colors) do
680 with colors[i] do
681 begin
682 sumR += red*alpha;
683 sumG += green*alpha;
684 sumB += blue*alpha;
685 sumA += alpha;
686 end;
687 if sumA > 0 then
688 begin
689 result.red := (sumR + sumA shr 1) div sumA;
690 result.green := (sumG + sumA shr 1) div sumA;
691 result.blue := (sumB + sumA shr 1) div sumA;
692 result.alpha := sumA div longword(length(colors));
693 end
694 else
695 result := BGRAPixelTransparent;
696end;
697
698function MapHeight(Color: TBGRAPixel): Single;
699var intval: integer;
700begin
701 intval := color.Green shl 16 + color.red shl 8 + color.blue;
702 result := intval*5.960464832810452e-8;
703end;
704
705function MapHeightToBGRA(Height: Single; Alpha: Byte): TBGRAPixel;
706var intval: integer;
707begin
708 if Height >= 1 then result := BGRA(255,255,255,alpha) else
709 if Height <= 0 then result := BGRA(0,0,0,alpha) else
710 begin
711 intval := round(Height*16777215);
712 {$PUSH}{$R-}
713 result := BGRA(intval shr 8,intval shr 16,intval,alpha);
714 {$POP}
715 end;
716end;
717{$ENDIF}
718
719{$IFDEF INCLUDE_INIT}
720{$UNDEF INCLUDE_INIT}
721 BGRASetGamma();
722
723 {$DEFINE INCLUDE_INITIALIZATION}
724 {$i extendedcolorspace.inc}
725{$ENDIF}
Note: See TracBrowser for help on using the repository browser.