2 Vampyre Imaging Library
4 http://imaginglib.sourceforge.net
6 The contents of this file are used with permission, subject to the Mozilla
7 Public License Version 1.1 (the "License"); you may not use this file except
8 in compliance with the License. You may obtain a copy of the License at
9 http://www.mozilla.org/MPL/MPL-1.1.html
11 Software distributed under the License is distributed on an "AS IS" basis,
12 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
13 the specific language governing rights and limitations under the License.
15 Alternatively, the contents of this file may be used under the terms of the
16 GNU Lesser General Public License (the "LGPL License"), in which case the
17 provisions of the LGPL License are applicable instead of those above.
18 If you wish to allow use of your version of this file only under the terms
19 of the LGPL License and not to allow others to use your version of this file
20 under the MPL, indicate your decision by deleting the provisions above and
21 replace them with the notice and other provisions required by the LGPL
22 License. If you do not delete the provisions above, a recipient may use
23 your version of this file under either the MPL or the LGPL License.
25 For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
28 { This unit manages information about all image data formats and contains
29 low level format conversion, manipulation, and other related functions.}
32 {$I ImagingOptions.inc}
37 ImagingTypes
, Imaging
, ImagingUtility
;
40 TImageFormatInfoArray
= array[TImageFormat
] of PImageFormatInfo
;
41 PImageFormatInfoArray
= ^TImageFormatInfoArray
;
44 { Additional image manipulation functions (usually used internally by Imaging unit) }
47 { Color reduction operations.}
48 TReduceColorsAction
= (raCreateHistogram
, raUpdateHistogram
, raMakeColorMap
,
50 TReduceColorsActions
= set of TReduceColorsAction
;
52 AllReduceColorsActions
= [raCreateHistogram
, raUpdateHistogram
,
53 raMakeColorMap
, raMapImage
];
54 { Reduces the number of colors of source. Src is bits of source image
55 (ARGB or floating point) and Dst is in some indexed format. MaxColors
56 is the number of colors to which reduce and DstPal is palette to which
57 the resulting colors are written and it must be allocated to at least
58 MaxColors entries. ChannelMask is 'anded' with every pixel's channel value
59 when creating color histogram. If $FF is used all 8bits of color channels
60 are used which can be slow for large images with many colors so you can
61 use lower masks to speed it up.}
62 procedure ReduceColorsMedianCut(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
63 DstInfo
: PImageFormatInfo
; MaxColors
: LongInt; ChannelMask
: Byte;
64 DstPal
: PPalette32
; Actions
: TReduceColorsActions
= AllReduceColorsActions
);
65 { Stretches rectangle in source image to rectangle in destination image
66 using nearest neighbor filtering. It is fast but results look blocky
67 because there is no interpolation used. SrcImage and DstImage must be
68 in the same data format. Works for all data formats except special formats.}
69 procedure StretchNearest(const SrcImage
: TImageData
; SrcX
, SrcY
, SrcWidth
,
70 SrcHeight
: LongInt; var DstImage
: TImageData
; DstX
, DstY
, DstWidth
,
73 { Built-in sampling filters.}
74 TSamplingFilter
= (sfNearest
, sfLinear
, sfCosine
, sfHermite
, sfQuadratic
,
75 sfGaussian
, sfSpline
, sfLanczos
, sfMitchell
, sfCatmullRom
);
76 { Type of custom sampling function}
77 TFilterFunction
= function(Value
: Single): Single;
79 { Default resampling filter used for bicubic resizing.}
80 DefaultCubicFilter
= sfCatmullRom
;
82 { Built-in filter functions.}
83 SamplingFilterFunctions
: array[TSamplingFilter
] of TFilterFunction
;
84 { Default radii of built-in filter functions.}
85 SamplingFilterRadii
: array[TSamplingFilter
] of Single;
87 { Stretches rectangle in source image to rectangle in destination image
88 with resampling. One of built-in resampling filters defined by
89 Filter is used. Set WrapEdges to True for seamlessly tileable images.
90 SrcImage and DstImage must be in the same data format.
91 Works for all data formats except special and indexed formats.}
92 procedure StretchResample(const SrcImage
: TImageData
; SrcX
, SrcY
, SrcWidth
,
93 SrcHeight
: LongInt; var DstImage
: TImageData
; DstX
, DstY
, DstWidth
,
94 DstHeight
: LongInt; Filter
: TSamplingFilter
; WrapEdges
: Boolean = False); overload
;
95 { Stretches rectangle in source image to rectangle in destination image
96 with resampling. You can use custom sampling function and filter radius.
97 Set WrapEdges to True for seamlessly tileable images. SrcImage and DstImage
98 must be in the same data format.
99 Works for all data formats except special and indexed formats.}
100 procedure StretchResample(const SrcImage
: TImageData
; SrcX
, SrcY
, SrcWidth
,
101 SrcHeight
: LongInt; var DstImage
: TImageData
; DstX
, DstY
, DstWidth
,
102 DstHeight
: LongInt; Filter
: TFilterFunction
; Radius
: Single;
103 WrapEdges
: Boolean = False); overload
;
104 { Helper for functions that create mipmap levels. BiggerLevel is
105 valid image and SmallerLevel is empty zeroed image. SmallerLevel is created
106 with Width and Height dimensions and it is filled with pixels of BiggerLevel
107 using resampling filter specified by ImagingMipMapFilter option.
108 Uses StretchNearest and StretchResample internally so the same image data format
110 procedure FillMipMapLevel(const BiggerLevel
: TImageData
; Width
, Height
: LongInt;
111 var SmallerLevel
: TImageData
);
114 { Various helper & support functions }
116 { Copies Src pixel to Dest pixel. It is faster than System.Move procedure.}
117 procedure CopyPixel(Src
, Dest
: Pointer; BytesPerPixel
: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF}
118 { Compares Src pixel and Dest pixel. It is faster than SysUtils.CompareMem function.}
119 function ComparePixels(PixelA
, PixelB
: Pointer; BytesPerPixel
: LongInt): Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF}
120 { Translates pixel color in SrcFormat to DstFormat.}
121 procedure TranslatePixel(SrcPixel
, DstPixel
: Pointer; SrcFormat
,
122 DstFormat
: TImageFormat
; SrcPalette
, DstPalette
: PPalette32
);
123 { Clamps floating point pixel channel values to [0.0, 1.0] range.}
124 procedure ClampFloatPixel(var PixF
: TColorFPRec
); {$IFDEF USE_INLINE}inline;{$ENDIF}
125 { Helper function that converts pixel in any format to 32bit ARGB pixel.
126 For common formats it's faster than calling GetPixel32 etc.}
127 procedure ConvertToPixel32(SrcPix
: PByte; DestPix
: PColor32Rec
;
128 const SrcInfo
: TImageFormatInfo
; SrcPalette
: PPalette32
= nil); {$IFDEF USE_INLINE}inline;{$ENDIF}
130 { Adds padding bytes at the ends of scanlines. Bpp is the number of bytes per
131 pixel of source and WidthBytes is the number of bytes per scanlines of dest.}
132 procedure AddPadBytes(DataIn
: Pointer; DataOut
: Pointer; Width
, Height
,
133 Bpp
, WidthBytes
: LongInt);
134 { Removes padding from image with scanlines that have aligned sizes. Bpp is
135 the number of bytes per pixel of dest and WidthBytes is the number of bytes
136 per scanlines of source.}
137 procedure RemovePadBytes(DataIn
: Pointer; DataOut
: Pointer; Width
, Height
,
138 Bpp
, WidthBytes
: LongInt);
140 { Converts 1bit image data to 8bit. Used mostly by file loaders for formats
141 supporting 1bit images. Scaling of pixel values to 8bits is optional
142 (indexed formats don't need this).}
143 procedure Convert1To8(DataIn
, DataOut
: PByte; Width
, Height
,
144 WidthBytes
: LongInt; ScaleTo8Bits
: Boolean);
145 { Converts 2bit image data to 8bit. Used mostly by file loaders for formats
146 supporting 2bit images. Scaling of pixel values to 8bits is optional
147 (indexed formats don't need this).}
148 procedure Convert2To8(DataIn
, DataOut
: PByte; Width
, Height
,
149 WidthBytes
: LongInt; ScaleTo8Bits
: Boolean);
150 { Converts 4bit image data to 8bit. Used mostly by file loaders for formats
151 supporting 4bit images. Scaling of pixel values to 8bits is optional
152 (indexed formats don't need this).}
153 procedure Convert4To8(DataIn
, DataOut
: PByte; Width
, Height
,
154 WidthBytes
: LongInt; ScaleTo8Bits
: Boolean);
156 { Helper function for image file loaders. Some 15 bit images (targas, bitmaps)
157 may contain 1 bit alpha but there is no indication of it. This function checks
158 all 16 bit(should be X1R5G5B5 or A1R5G5B5 format) pixels and some of them have
159 alpha bit set it returns True, otherwise False.}
160 function Has16BitImageAlpha(NumPixels
: LongInt; Data
: PWord): Boolean;
161 { Helper function for image file loaders. This function checks is similar
162 to Has16BitImageAlpha but works with A8R8G8B8/X8R8G8B8 format.}
163 function Has32BitImageAlpha(NumPixels
: LongInt; Data
: PLongWord): Boolean;
164 { Checks if there is any relevant alpha data (any entry has alpha <> 255)
165 in the given palette.}
166 function PaletteHasAlpha(Palette
: PPalette32
; PaletteEntries
: Integer): Boolean;
168 { Provides indexed access to each line of pixels. Does not work with special
170 function GetScanLine(ImageBits
: Pointer; const FormatInfo
: TImageFormatInfo
;
171 LineWidth
, Index
: LongInt): Pointer; {$IFDEF USE_INLINE}inline;{$ENDIF}
172 { Returns True if Format is valid image data format identifier.}
173 function IsImageFormatValid(Format
: TImageFormat
): Boolean;
175 { Converts 16bit half floating point value to 32bit Single.}
176 function HalfToFloat(Half
: THalfFloat
): Single;
177 { Converts 32bit Single to 16bit half floating point.}
178 function FloatToHalf(Float
: Single): THalfFloat
;
180 { Converts half float color value to single-precision floating point color.}
181 function ColorHalfToFloat(ColorHF
: TColorHFRec
): TColorFPRec
; {$IFDEF USE_INLINE}inline;{$ENDIF}
182 { Converts single-precision floating point color to half float color.}
183 function ColorFloatToHalf(ColorFP
: TColorFPRec
): TColorHFRec
; {$IFDEF USE_INLINE}inline;{$ENDIF}
185 { Makes image PalEntries x 1 big where each pixel has color of one pal entry.}
186 procedure VisualizePalette(Pal
: PPalette32
; Entries
: Integer; out PalImage
: TImageData
);
193 TCluster
= array of TPointRec
;
194 TMappingTable
= array of TCluster
;
196 { Helper function for resampling.}
197 function BuildMappingTable(DstLow
, DstHigh
, SrcLow
, SrcHigh
, SrcImageWidth
: LongInt;
198 Filter
: TFilterFunction
; Radius
: Single; WrapEdges
: Boolean): TMappingTable
;
199 { Helper function for resampling.}
200 procedure FindExtremes(const Map
: TMappingTable
; var MinPos
, MaxPos
: LongInt);
203 { Pixel readers/writers for different image formats }
205 { Returns pixel of image in any ARGB format. Channel values are scaled to 16 bits.}
206 procedure ChannelGetSrcPixel(Src
: PByte; SrcInfo
: PImageFormatInfo
;
207 var Pix
: TColor64Rec
);
208 { Sets pixel of image in any ARGB format. Channel values must be scaled to 16 bits.}
209 procedure ChannelSetDstPixel(Dst
: PByte; DstInfo
: PImageFormatInfo
;
210 const Pix
: TColor64Rec
);
212 { Returns pixel of image in any grayscale format. Gray value is scaled to 64 bits
213 and alpha to 16 bits.}
214 procedure GrayGetSrcPixel(Src
: PByte; SrcInfo
: PImageFormatInfo
;
215 var Gray
: TColor64Rec
; var Alpha
: Word);
216 { Sets pixel of image in any grayscale format. Gray value must be scaled to 64 bits
217 and alpha to 16 bits.}
218 procedure GraySetDstPixel(Dst
: PByte; DstInfo
: PImageFormatInfo
;
219 const Gray
: TColor64Rec
; Alpha
: Word);
221 { Returns pixel of image in any floating point format. Channel values are
222 in range <0.0, 1.0>.}
223 procedure FloatGetSrcPixel(Src
: PByte; SrcInfo
: PImageFormatInfo
;
224 var Pix
: TColorFPRec
);
225 { Sets pixel of image in any floating point format. Channel values must be
226 in range <0.0, 1.0>.}
227 procedure FloatSetDstPixel(Dst
: PByte; DstInfo
: PImageFormatInfo
;
228 const Pix
: TColorFPRec
);
230 { Returns pixel of image in any indexed format. Returned value is index to
232 procedure IndexGetSrcPixel(Src
: PByte; SrcInfo
: PImageFormatInfo
;
233 var Index
: LongWord);
234 { Sets pixel of image in any indexed format. Index is index to the palette.}
235 procedure IndexSetDstPixel(Dst
: PByte; DstInfo
: PImageFormatInfo
;
239 { Pixel readers/writers for 32bit and FP colors}
241 { Function for getting pixel colors. Native pixel is read from Image and
242 then translated to 32 bit ARGB.}
243 function GetPixel32Generic(Bits
: Pointer; Info
: PImageFormatInfo
;
244 Palette
: PPalette32
): TColor32Rec
;
245 { Procedure for setting pixel colors. Input 32 bit ARGB color is translated to
246 native format and then written to Image.}
247 procedure SetPixel32Generic(Bits
: Pointer; Info
: PImageFormatInfo
;
248 Palette
: PPalette32
; const Color
: TColor32Rec
);
249 { Function for getting pixel colors. Native pixel is read from Image and
250 then translated to FP ARGB.}
251 function GetPixelFPGeneric(Bits
: Pointer; Info
: PImageFormatInfo
;
252 Palette
: PPalette32
): TColorFPRec
;
253 { Procedure for setting pixel colors. Input FP ARGB color is translated to
254 native format and then written to Image.}
255 procedure SetPixelFPGeneric(Bits
: Pointer; Info
: PImageFormatInfo
;
256 Palette
: PPalette32
; const Color
: TColorFPRec
);
259 { Image format conversion functions }
261 { Converts any ARGB format to any ARGB format.}
262 procedure ChannelToChannel(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
263 DstInfo
: PImageFormatInfo
);
264 { Converts any ARGB format to any grayscale format.}
265 procedure ChannelToGray(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
266 DstInfo
: PImageFormatInfo
);
267 { Converts any ARGB format to any floating point format.}
268 procedure ChannelToFloat(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
269 DstInfo
: PImageFormatInfo
);
270 { Converts any ARGB format to any indexed format.}
271 procedure ChannelToIndex(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
272 DstInfo
: PImageFormatInfo
; DstPal
: PPalette32
);
274 { Converts any grayscale format to any grayscale format.}
275 procedure GrayToGray(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
276 DstInfo
: PImageFormatInfo
);
277 { Converts any grayscale format to any ARGB format.}
278 procedure GrayToChannel(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
279 DstInfo
: PImageFormatInfo
);
280 { Converts any grayscale format to any floating point format.}
281 procedure GrayToFloat(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
282 DstInfo
: PImageFormatInfo
);
283 { Converts any grayscale format to any indexed format.}
284 procedure GrayToIndex(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
285 DstInfo
: PImageFormatInfo
; DstPal
: PPalette32
);
287 { Converts any floating point format to any floating point format.}
288 procedure FloatToFloat(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
289 DstInfo
: PImageFormatInfo
);
290 { Converts any floating point format to any ARGB format.}
291 procedure FloatToChannel(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
292 DstInfo
: PImageFormatInfo
);
293 { Converts any floating point format to any grayscale format.}
294 procedure FloatToGray(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
295 DstInfo
: PImageFormatInfo
);
296 { Converts any floating point format to any indexed format.}
297 procedure FloatToIndex(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
298 DstInfo
: PImageFormatInfo
; DstPal
: PPalette32
);
300 { Converts any indexed format to any indexed format.}
301 procedure IndexToIndex(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
302 DstInfo
: PImageFormatInfo
; SrcPal
, DstPal
: PPalette32
);
303 { Converts any indexed format to any ARGB format.}
304 procedure IndexToChannel(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
305 DstInfo
: PImageFormatInfo
; SrcPal
: PPalette32
);
306 { Converts any indexed format to any grayscale format.}
307 procedure IndexToGray(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
308 DstInfo
: PImageFormatInfo
; SrcPal
: PPalette32
);
309 { Converts any indexed format to any floating point format.}
310 procedure IndexToFloat(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
311 DstInfo
: PImageFormatInfo
; SrcPal
: PPalette32
);
314 { Color constructor functions }
316 { Constructs TColor24Rec color.}
317 function Color24(R
, G
, B
: Byte): TColor24Rec
; {$IFDEF USE_INLINE}inline;{$ENDIF}
318 { Constructs TColor32Rec color.}
319 function Color32(A
, R
, G
, B
: Byte): TColor32Rec
; {$IFDEF USE_INLINE}inline;{$ENDIF}
320 { Constructs TColor48Rec color.}
321 function Color48(R
, G
, B
: Word): TColor48Rec
; {$IFDEF USE_INLINE}inline;{$ENDIF}
322 { Constructs TColor64Rec color.}
323 function Color64(A
, R
, G
, B
: Word): TColor64Rec
; {$IFDEF USE_INLINE}inline;{$ENDIF}
324 { Constructs TColorFPRec color.}
325 function ColorFP(A
, R
, G
, B
: Single): TColorFPRec
; {$IFDEF USE_INLINE}inline;{$ENDIF}
326 { Constructs TColorHFRec color.}
327 function ColorHF(A
, R
, G
, B
: THalfFloat
): TColorHFRec
; {$IFDEF USE_INLINE}inline;{$ENDIF}
330 { Special formats conversion functions }
332 { Converts image to/from/between special image formats (dxtc, ...).}
333 procedure ConvertSpecial(var Image
: TImageData
; SrcInfo
,
334 DstInfo
: PImageFormatInfo
);
337 { Inits all image format information. Called internally on startup.}
338 procedure InitImageFormats(var Infos
: TImageFormatInfoArray
);
341 // Grayscale conversion channel weights
342 GrayConv
: TColorFPRec
= (B
: 0.114; G
: 0.587; R
: 0.299; A
: 0.0);
344 // Contants for converting integer colors to floating point
345 OneDiv8Bit
: Single = 1.0 / 255.0;
346 OneDiv16Bit
: Single = 1.0 / 65535.0;
350 { TImageFormatInfo member functions }
352 { Returns size in bytes of image in given standard format where
353 Size = Width * Height * Bpp.}
354 function GetStdPixelsSize(Format
: TImageFormat
; Width
, Height
: LongInt): LongInt; forward;
355 { Checks if Width and Height are valid for given standard format.}
356 procedure CheckStdDimensions(Format
: TImageFormat
; var Width
, Height
: LongInt); forward;
357 { Returns size in bytes of image in given DXT format.}
358 function GetDXTPixelsSize(Format
: TImageFormat
; Width
, Height
: LongInt): LongInt; forward;
359 { Checks if Width and Height are valid for given DXT format. If they are
360 not valid, they are changed to pass the check.}
361 procedure CheckDXTDimensions(Format
: TImageFormat
; var Width
, Height
: LongInt); forward;
362 { Returns size in bytes of image in BTC format.}
363 function GetBTCPixelsSize(Format
: TImageFormat
; Width
, Height
: LongInt): LongInt; forward;
364 { Returns size in bytes of image in binary format (1bit image).}
365 function GetBinaryPixelsSize(Format
: TImageFormat
; Width
, Height
: LongInt): LongInt; forward;
367 function GetBCPixelsSize(Format
: TImageFormat
; Width
, Height
: LongInt): LongInt; forward;
368 procedure CheckBCDimensions(Format
: TImageFormat
; var Width
, Height
: LongInt); forward;
371 { Optimized pixel readers/writers for 32bit and FP colors to be stored in TImageFormatInfo }
373 function GetPixel32ifA8R8G8B8(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
): TColor32Rec
; forward;
374 procedure SetPixel32ifA8R8G8B8(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
; const Color
: TColor32Rec
); forward;
375 function GetPixelFPifA8R8G8B8(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
): TColorFPRec
; forward;
376 procedure SetPixelFPifA8R8G8B8(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
; const Color
: TColorFPRec
); forward;
378 function GetPixel32Channel8Bit(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
): TColor32Rec
; forward;
379 procedure SetPixel32Channel8Bit(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
; const Color
: TColor32Rec
); forward;
380 function GetPixelFPChannel8Bit(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
): TColorFPRec
; forward;
381 procedure SetPixelFPChannel8Bit(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
; const Color
: TColorFPRec
); forward;
383 function GetPixelFPFloat32(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
): TColorFPRec
; forward;
384 procedure SetPixelFPFloat32(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
; const Color
: TColorFPRec
); forward;
387 PFR3G3B2
: TPixelFormatInfo
;
388 PFX5R1G1B1
: TPixelFormatInfo
;
389 PFR5G6B5
: TPixelFormatInfo
;
390 PFA1R5G5B5
: TPixelFormatInfo
;
391 PFA4R4G4B4
: TPixelFormatInfo
;
392 PFX1R5G5B5
: TPixelFormatInfo
;
393 PFX4R4G4B4
: TPixelFormatInfo
;
394 FInfos
: PImageFormatInfoArray
;
397 // Free Pascal generates hundreds of warnings here
401 Index8Info
: TImageFormatInfo
= (
407 HasAlphaChannel
: True;
409 GetPixelsSize
: GetStdPixelsSize
;
410 CheckDimensions
: CheckStdDimensions
;
411 GetPixel32
: GetPixel32Generic
;
412 GetPixelFP
: GetPixelFPGeneric
;
413 SetPixel32
: SetPixel32Generic
;
414 SetPixelFP
: SetPixelFPGeneric
);
417 Gray8Info
: TImageFormatInfo
= (
422 HasGrayChannel
: True;
423 GetPixelsSize
: GetStdPixelsSize
;
424 CheckDimensions
: CheckStdDimensions
;
425 GetPixel32
: GetPixel32Channel8Bit
;
426 GetPixelFP
: GetPixelFPChannel8Bit
;
427 SetPixel32
: SetPixel32Channel8Bit
;
428 SetPixelFP
: SetPixelFPChannel8Bit
);
430 A8Gray8Info
: TImageFormatInfo
= (
435 HasGrayChannel
: True;
436 HasAlphaChannel
: True;
437 GetPixelsSize
: GetStdPixelsSize
;
438 CheckDimensions
: CheckStdDimensions
;
439 GetPixel32
: GetPixel32Channel8Bit
;
440 GetPixelFP
: GetPixelFPChannel8Bit
;
441 SetPixel32
: SetPixel32Channel8Bit
;
442 SetPixelFP
: SetPixelFPChannel8Bit
);
444 Gray16Info
: TImageFormatInfo
= (
449 HasGrayChannel
: True;
450 GetPixelsSize
: GetStdPixelsSize
;
451 CheckDimensions
: CheckStdDimensions
;
452 GetPixel32
: GetPixel32Generic
;
453 GetPixelFP
: GetPixelFPGeneric
;
454 SetPixel32
: SetPixel32Generic
;
455 SetPixelFP
: SetPixelFPGeneric
);
457 Gray32Info
: TImageFormatInfo
= (
462 HasGrayChannel
: True;
463 GetPixelsSize
: GetStdPixelsSize
;
464 CheckDimensions
: CheckStdDimensions
;
465 GetPixel32
: GetPixel32Generic
;
466 GetPixelFP
: GetPixelFPGeneric
;
467 SetPixel32
: SetPixel32Generic
;
468 SetPixelFP
: SetPixelFPGeneric
);
470 Gray64Info
: TImageFormatInfo
= (
475 HasGrayChannel
: True;
476 GetPixelsSize
: GetStdPixelsSize
;
477 CheckDimensions
: CheckStdDimensions
;
478 GetPixel32
: GetPixel32Generic
;
479 GetPixelFP
: GetPixelFPGeneric
;
480 SetPixel32
: SetPixel32Generic
;
481 SetPixelFP
: SetPixelFPGeneric
);
483 A16Gray16Info
: TImageFormatInfo
= (
488 HasGrayChannel
: True;
489 HasAlphaChannel
: True;
490 GetPixelsSize
: GetStdPixelsSize
;
491 CheckDimensions
: CheckStdDimensions
;
492 GetPixel32
: GetPixel32Generic
;
493 GetPixelFP
: GetPixelFPGeneric
;
494 SetPixel32
: SetPixel32Generic
;
495 SetPixelFP
: SetPixelFPGeneric
);
498 X5R1G1B1Info
: TImageFormatInfo
= (
503 UsePixelFormat
: True;
504 PixelFormat
: @PFX5R1G1B1
;
505 GetPixelsSize
: GetStdPixelsSize
;
506 CheckDimensions
: CheckStdDimensions
;
507 GetPixel32
: GetPixel32Generic
;
508 GetPixelFP
: GetPixelFPGeneric
;
509 SetPixel32
: SetPixel32Generic
;
510 SetPixelFP
: SetPixelFPGeneric
);
512 R3G3B2Info
: TImageFormatInfo
= (
517 UsePixelFormat
: True;
518 PixelFormat
: @PFR3G3B2
;
519 GetPixelsSize
: GetStdPixelsSize
;
520 CheckDimensions
: CheckStdDimensions
;
521 GetPixel32
: GetPixel32Generic
;
522 GetPixelFP
: GetPixelFPGeneric
;
523 SetPixel32
: SetPixel32Generic
;
524 SetPixelFP
: SetPixelFPGeneric
);
526 R5G6B5Info
: TImageFormatInfo
= (
531 UsePixelFormat
: True;
532 PixelFormat
: @PFR5G6B5
;
533 GetPixelsSize
: GetStdPixelsSize
;
534 CheckDimensions
: CheckStdDimensions
;
535 GetPixel32
: GetPixel32Generic
;
536 GetPixelFP
: GetPixelFPGeneric
;
537 SetPixel32
: SetPixel32Generic
;
538 SetPixelFP
: SetPixelFPGeneric
);
540 A1R5G5B5Info
: TImageFormatInfo
= (
545 HasAlphaChannel
: True;
546 UsePixelFormat
: True;
547 PixelFormat
: @PFA1R5G5B5
;
548 GetPixelsSize
: GetStdPixelsSize
;
549 CheckDimensions
: CheckStdDimensions
;
550 GetPixel32
: GetPixel32Generic
;
551 GetPixelFP
: GetPixelFPGeneric
;
552 SetPixel32
: SetPixel32Generic
;
553 SetPixelFP
: SetPixelFPGeneric
);
555 A4R4G4B4Info
: TImageFormatInfo
= (
560 HasAlphaChannel
: True;
561 UsePixelFormat
: True;
562 PixelFormat
: @PFA4R4G4B4
;
563 GetPixelsSize
: GetStdPixelsSize
;
564 CheckDimensions
: CheckStdDimensions
;
565 GetPixel32
: GetPixel32Generic
;
566 GetPixelFP
: GetPixelFPGeneric
;
567 SetPixel32
: SetPixel32Generic
;
568 SetPixelFP
: SetPixelFPGeneric
);
570 X1R5G5B5Info
: TImageFormatInfo
= (
575 UsePixelFormat
: True;
576 PixelFormat
: @PFX1R5G5B5
;
577 GetPixelsSize
: GetStdPixelsSize
;
578 CheckDimensions
: CheckStdDimensions
;
579 GetPixel32
: GetPixel32Generic
;
580 GetPixelFP
: GetPixelFPGeneric
;
581 SetPixel32
: SetPixel32Generic
;
582 SetPixelFP
: SetPixelFPGeneric
);
584 X4R4G4B4Info
: TImageFormatInfo
= (
589 UsePixelFormat
: True;
590 PixelFormat
: @PFX4R4G4B4
;
591 GetPixelsSize
: GetStdPixelsSize
;
592 CheckDimensions
: CheckStdDimensions
;
593 GetPixel32
: GetPixel32Generic
;
594 GetPixelFP
: GetPixelFPGeneric
;
595 SetPixel32
: SetPixel32Generic
;
596 SetPixelFP
: SetPixelFPGeneric
);
598 R8G8B8Info
: TImageFormatInfo
= (
603 GetPixelsSize
: GetStdPixelsSize
;
604 CheckDimensions
: CheckStdDimensions
;
605 GetPixel32
: GetPixel32Channel8Bit
;
606 GetPixelFP
: GetPixelFPChannel8Bit
;
607 SetPixel32
: SetPixel32Channel8Bit
;
608 SetPixelFP
: SetPixelFPChannel8Bit
);
610 A8R8G8B8Info
: TImageFormatInfo
= (
615 HasAlphaChannel
: True;
616 GetPixelsSize
: GetStdPixelsSize
;
617 CheckDimensions
: CheckStdDimensions
;
618 GetPixel32
: GetPixel32ifA8R8G8B8
;
619 GetPixelFP
: GetPixelFPifA8R8G8B8
;
620 SetPixel32
: SetPixel32ifA8R8G8B8
;
621 SetPixelFP
: SetPixelFPifA8R8G8B8
);
623 X8R8G8B8Info
: TImageFormatInfo
= (
628 GetPixelsSize
: GetStdPixelsSize
;
629 CheckDimensions
: CheckStdDimensions
;
630 GetPixel32
: GetPixel32Channel8Bit
;
631 GetPixelFP
: GetPixelFPChannel8Bit
;
632 SetPixel32
: SetPixel32Channel8Bit
;
633 SetPixelFP
: SetPixelFPChannel8Bit
);
635 R16G16B16Info
: TImageFormatInfo
= (
640 RBSwapFormat
: ifB16G16R16
;
641 GetPixelsSize
: GetStdPixelsSize
;
642 CheckDimensions
: CheckStdDimensions
;
643 GetPixel32
: GetPixel32Generic
;
644 GetPixelFP
: GetPixelFPGeneric
;
645 SetPixel32
: SetPixel32Generic
;
646 SetPixelFP
: SetPixelFPGeneric
);
648 A16R16G16B16Info
: TImageFormatInfo
= (
649 Format
: ifA16R16G16B16
;
650 Name
: 'A16R16G16B16';
653 HasAlphaChannel
: True;
654 RBSwapFormat
: ifA16B16G16R16
;
655 GetPixelsSize
: GetStdPixelsSize
;
656 CheckDimensions
: CheckStdDimensions
;
657 GetPixel32
: GetPixel32Generic
;
658 GetPixelFP
: GetPixelFPGeneric
;
659 SetPixel32
: SetPixel32Generic
;
660 SetPixelFP
: SetPixelFPGeneric
);
662 B16G16R16Info
: TImageFormatInfo
= (
668 RBSwapFormat
: ifR16G16B16
;
669 GetPixelsSize
: GetStdPixelsSize
;
670 CheckDimensions
: CheckStdDimensions
;
671 GetPixel32
: GetPixel32Generic
;
672 GetPixelFP
: GetPixelFPGeneric
;
673 SetPixel32
: SetPixel32Generic
;
674 SetPixelFP
: SetPixelFPGeneric
);
676 A16B16G16R16Info
: TImageFormatInfo
= (
677 Format
: ifA16B16G16R16
;
678 Name
: 'A16B16G16R16';
681 HasAlphaChannel
: True;
683 RBSwapFormat
: ifA16R16G16B16
;
684 GetPixelsSize
: GetStdPixelsSize
;
685 CheckDimensions
: CheckStdDimensions
;
686 GetPixel32
: GetPixel32Generic
;
687 GetPixelFP
: GetPixelFPGeneric
;
688 SetPixel32
: SetPixel32Generic
;
689 SetPixelFP
: SetPixelFPGeneric
);
691 // floating point formats
692 R32FInfo
: TImageFormatInfo
= (
697 IsFloatingPoint
: True;
698 GetPixelsSize
: GetStdPixelsSize
;
699 CheckDimensions
: CheckStdDimensions
;
700 GetPixel32
: GetPixel32Generic
;
701 GetPixelFP
: GetPixelFPFloat32
;
702 SetPixel32
: SetPixel32Generic
;
703 SetPixelFP
: SetPixelFPFloat32
);
705 A32R32G32B32FInfo
: TImageFormatInfo
= (
706 Format
: ifA32R32G32B32F
;
707 Name
: 'A32R32G32B32F';
710 HasAlphaChannel
: True;
711 IsFloatingPoint
: True;
712 RBSwapFormat
: ifA32B32G32R32F
;
713 GetPixelsSize
: GetStdPixelsSize
;
714 CheckDimensions
: CheckStdDimensions
;
715 GetPixel32
: GetPixel32Generic
;
716 GetPixelFP
: GetPixelFPFloat32
;
717 SetPixel32
: SetPixel32Generic
;
718 SetPixelFP
: SetPixelFPFloat32
);
720 A32B32G32R32FInfo
: TImageFormatInfo
= (
721 Format
: ifA32B32G32R32F
;
722 Name
: 'A32B32G32R32F';
725 HasAlphaChannel
: True;
726 IsFloatingPoint
: True;
728 RBSwapFormat
: ifA32R32G32B32F
;
729 GetPixelsSize
: GetStdPixelsSize
;
730 CheckDimensions
: CheckStdDimensions
;
731 GetPixel32
: GetPixel32Generic
;
732 GetPixelFP
: GetPixelFPFloat32
;
733 SetPixel32
: SetPixel32Generic
;
734 SetPixelFP
: SetPixelFPFloat32
);
736 R16FInfo
: TImageFormatInfo
= (
741 IsFloatingPoint
: True;
742 GetPixelsSize
: GetStdPixelsSize
;
743 CheckDimensions
: CheckStdDimensions
;
744 GetPixel32
: GetPixel32Generic
;
745 GetPixelFP
: GetPixelFPGeneric
;
746 SetPixel32
: SetPixel32Generic
;
747 SetPixelFP
: SetPixelFPGeneric
);
749 A16R16G16B16FInfo
: TImageFormatInfo
= (
750 Format
: ifA16R16G16B16F
;
751 Name
: 'A16R16G16B16F';
754 HasAlphaChannel
: True;
755 IsFloatingPoint
: True;
756 RBSwapFormat
: ifA16B16G16R16F
;
757 GetPixelsSize
: GetStdPixelsSize
;
758 CheckDimensions
: CheckStdDimensions
;
759 GetPixel32
: GetPixel32Generic
;
760 GetPixelFP
: GetPixelFPGeneric
;
761 SetPixel32
: SetPixel32Generic
;
762 SetPixelFP
: SetPixelFPGeneric
);
764 A16B16G16R16FInfo
: TImageFormatInfo
= (
765 Format
: ifA16B16G16R16F
;
766 Name
: 'A16B16G16R16F';
769 HasAlphaChannel
: True;
770 IsFloatingPoint
: True;
772 RBSwapFormat
: ifA16R16G16B16F
;
773 GetPixelsSize
: GetStdPixelsSize
;
774 CheckDimensions
: CheckStdDimensions
;
775 GetPixel32
: GetPixel32Generic
;
776 GetPixelFP
: GetPixelFPGeneric
;
777 SetPixel32
: SetPixel32Generic
;
778 SetPixelFP
: SetPixelFPGeneric
);
780 R32G32B32FInfo
: TImageFormatInfo
= (
781 Format
: ifR32G32B32F
;
785 IsFloatingPoint
: True;
786 RBSwapFormat
: ifB32G32R32F
;
787 GetPixelsSize
: GetStdPixelsSize
;
788 CheckDimensions
: CheckStdDimensions
;
789 GetPixel32
: GetPixel32Generic
;
790 GetPixelFP
: GetPixelFPFloat32
;
791 SetPixel32
: SetPixel32Generic
;
792 SetPixelFP
: SetPixelFPFloat32
);
794 B32G32R32FInfo
: TImageFormatInfo
= (
795 Format
: ifB32G32R32F
;
799 IsFloatingPoint
: True;
801 RBSwapFormat
: ifR32G32B32F
;
802 GetPixelsSize
: GetStdPixelsSize
;
803 CheckDimensions
: CheckStdDimensions
;
804 GetPixel32
: GetPixel32Generic
;
805 GetPixelFP
: GetPixelFPFloat32
;
806 SetPixel32
: SetPixel32Generic
;
807 SetPixelFP
: SetPixelFPFloat32
);
810 DXT1Info
: TImageFormatInfo
= (
814 HasAlphaChannel
: True;
816 GetPixelsSize
: GetDXTPixelsSize
;
817 CheckDimensions
: CheckDXTDimensions
;
818 SpecialNearestFormat
: ifA8R8G8B8
);
820 DXT3Info
: TImageFormatInfo
= (
824 HasAlphaChannel
: True;
826 GetPixelsSize
: GetDXTPixelsSize
;
827 CheckDimensions
: CheckDXTDimensions
;
828 SpecialNearestFormat
: ifA8R8G8B8
);
830 DXT5Info
: TImageFormatInfo
= (
834 HasAlphaChannel
: True;
836 GetPixelsSize
: GetDXTPixelsSize
;
837 CheckDimensions
: CheckDXTDimensions
;
838 SpecialNearestFormat
: ifA8R8G8B8
);
840 BTCInfo
: TImageFormatInfo
= (
844 HasAlphaChannel
: False;
846 GetPixelsSize
: GetBTCPixelsSize
;
847 CheckDimensions
: CheckDXTDimensions
;
848 SpecialNearestFormat
: ifGray8
);
850 ATI1NInfo
: TImageFormatInfo
= (
854 HasAlphaChannel
: False;
856 GetPixelsSize
: GetDXTPixelsSize
;
857 CheckDimensions
: CheckDXTDimensions
;
858 SpecialNearestFormat
: ifGray8
);
860 ATI2NInfo
: TImageFormatInfo
= (
864 HasAlphaChannel
: False;
866 GetPixelsSize
: GetDXTPixelsSize
;
867 CheckDimensions
: CheckDXTDimensions
;
868 SpecialNearestFormat
: ifA8R8G8B8
);
870 BinaryInfo
: TImageFormatInfo
= (
874 HasAlphaChannel
: False;
876 GetPixelsSize
: GetBinaryPixelsSize
;
877 CheckDimensions
: CheckStdDimensions
;
878 SpecialNearestFormat
: ifGray8
);
880 {ETC1Info: TImageFormatInfo = (
884 HasAlphaChannel: False;
887 GetPixelsSize: GetBCPixelsSize;
888 CheckDimensions: CheckBCDimensions;
889 SpecialNearestFormat: ifR8G8B8);
891 ETC2RGBInfo: TImageFormatInfo = (
895 HasAlphaChannel: False;
898 GetPixelsSize: GetBCPixelsSize;
899 CheckDimensions: CheckBCDimensions;
900 SpecialNearestFormat: ifR8G8B8);
902 ETC2RGBAInfo: TImageFormatInfo = (
906 HasAlphaChannel: True;
909 GetPixelsSize: GetBCPixelsSize;
910 CheckDimensions: CheckBCDimensions;
911 SpecialNearestFormat: ifA8R8G8B8);
913 ETC2PAInfo: TImageFormatInfo = (
917 HasAlphaChannel: True;
920 GetPixelsSize: GetBCPixelsSize;
921 CheckDimensions: CheckBCDimensions;
922 SpecialNearestFormat: ifA8R8G8B8);
924 DXBC6Info: TImageFormatInfo = (
928 HasAlphaChannel: True;
931 GetPixelsSize: GetBCPixelsSize;
932 CheckDimensions: CheckBCDimensions;
933 SpecialNearestFormat: ifA8R8G8B8);
935 DXBC7Info: TImageFormatInfo = (
939 HasAlphaChannel: True;
942 GetPixelsSize: GetBCPixelsSize;
943 CheckDimensions: CheckBCDimensions;
944 SpecialNearestFormat: ifA8R8G8B8); }
946 {PVRTCInfo: TImageFormatInfo = (
950 HasAlphaChannel: True;
953 GetPixelsSize: GetBCPixelsSize;
954 CheckDimensions: CheckBCDimensions;
955 SpecialNearestFormat: ifA8R8G8B8);}
959 function PixelFormat(ABitCount
, RBitCount
, GBitCount
, BBitCount
: Byte): TPixelFormatInfo
; forward;
961 procedure InitImageFormats(var Infos
: TImageFormatInfoArray
);
965 Infos
[ifDefault
] := @A8R8G8B8Info
;
967 Infos
[ifIndex8
] := @Index8Info
;
969 Infos
[ifGray8
] := @Gray8Info
;
970 Infos
[ifA8Gray8
] := @A8Gray8Info
;
971 Infos
[ifGray16
] := @Gray16Info
;
972 Infos
[ifGray32
] := @Gray32Info
;
973 Infos
[ifGray64
] := @Gray64Info
;
974 Infos
[ifA16Gray16
] := @A16Gray16Info
;
976 Infos
[ifX5R1G1B1
] := @X5R1G1B1Info
;
977 Infos
[ifR3G3B2
] := @R3G3B2Info
;
978 Infos
[ifR5G6B5
] := @R5G6B5Info
;
979 Infos
[ifA1R5G5B5
] := @A1R5G5B5Info
;
980 Infos
[ifA4R4G4B4
] := @A4R4G4B4Info
;
981 Infos
[ifX1R5G5B5
] := @X1R5G5B5Info
;
982 Infos
[ifX4R4G4B4
] := @X4R4G4B4Info
;
983 Infos
[ifR8G8B8
] := @R8G8B8Info
;
984 Infos
[ifA8R8G8B8
] := @A8R8G8B8Info
;
985 Infos
[ifX8R8G8B8
] := @X8R8G8B8Info
;
986 Infos
[ifR16G16B16
] := @R16G16B16Info
;
987 Infos
[ifA16R16G16B16
] := @A16R16G16B16Info
;
988 Infos
[ifB16G16R16
] := @B16G16R16Info
;
989 Infos
[ifA16B16G16R16
] := @A16B16G16R16Info
;
990 // floating point formats
991 Infos
[ifR32F
] := @R32FInfo
;
992 Infos
[ifA32R32G32B32F
] := @A32R32G32B32FInfo
;
993 Infos
[ifA32B32G32R32F
] := @A32B32G32R32FInfo
;
994 Infos
[ifR16F
] := @R16FInfo
;
995 Infos
[ifA16R16G16B16F
] := @A16R16G16B16FInfo
;
996 Infos
[ifA16B16G16R16F
] := @A16B16G16R16FInfo
;
997 Infos
[ifR32G32B32F
] := @R32G32B32FInfo
;
998 Infos
[ifB32G32R32F
] := @B32G32R32FInfo
;
1000 Infos
[ifDXT1
] := @DXT1Info
;
1001 Infos
[ifDXT3
] := @DXT3Info
;
1002 Infos
[ifDXT5
] := @DXT5Info
;
1003 Infos
[ifBTC
] := @BTCInfo
;
1004 Infos
[ifATI1N
] := @ATI1NInfo
;
1005 Infos
[ifATI2N
] := @ATI2NInfo
;
1006 Infos
[ifBinary
] := @BinaryInfo
;
1008 PFR3G3B2
:= PixelFormat(0, 3, 3, 2);
1009 PFX5R1G1B1
:= PixelFormat(0, 1, 1, 1);
1010 PFR5G6B5
:= PixelFormat(0, 5, 6, 5);
1011 PFA1R5G5B5
:= PixelFormat(1, 5, 5, 5);
1012 PFA4R4G4B4
:= PixelFormat(4, 4, 4, 4);
1013 PFX1R5G5B5
:= PixelFormat(0, 5, 5, 5);
1014 PFX4R4G4B4
:= PixelFormat(0, 4, 4, 4);
1018 { Internal unit helper functions }
1020 function PixelFormat(ABitCount
, RBitCount
, GBitCount
, BBitCount
: Byte): TPixelFormatInfo
;
1022 Result
.ABitMask
:= ((1 shl ABitCount
) - 1) shl (RBitCount
+ GBitCount
+
1024 Result
.RBitMask
:= ((1 shl RBitCount
) - 1) shl (GBitCount
+ BBitCount
);
1025 Result
.GBitMask
:= ((1 shl GBitCount
) - 1) shl (BBitCount
);
1026 Result
.BBitMask
:= (1 shl BBitCount
) - 1;
1027 Result
.ABitCount
:= ABitCount
;
1028 Result
.RBitCount
:= RBitCount
;
1029 Result
.GBitCount
:= GBitCount
;
1030 Result
.BBitCount
:= BBitCount
;
1031 Result
.AShift
:= RBitCount
+ GBitCount
+ BBitCount
;
1032 Result
.RShift
:= GBitCount
+ BBitCount
;
1033 Result
.GShift
:= BBitCount
;
1035 Result
.ARecDiv
:= Max(1, Pow2Int(Result
.ABitCount
) - 1);
1036 Result
.RRecDiv
:= Max(1, Pow2Int(Result
.RBitCount
) - 1);
1037 Result
.GRecDiv
:= Max(1, Pow2Int(Result
.GBitCount
) - 1);
1038 Result
.BRecDiv
:= Max(1, Pow2Int(Result
.BBitCount
) - 1);
1041 function PixelFormatMask(ABitMask
, RBitMask
, GBitMask
, BBitMask
: LongWord): TPixelFormatInfo
;
1043 function GetBitCount(B
: LongWord): LongWord;
1048 while (I
< 31) and (((1 shl I
) and B
) = 0) do
1051 while ((1 shl I
) and B
) <> 0 do
1059 Result
:= PixelFormat(GetBitCount(ABitMask
), GetBitCount(RBitMask
),
1060 GetBitCount(GBitMask
), GetBitCount(BBitMask
));
1063 function PFSetARGB(const PF
: TPixelFormatInfo
; A
, R
, G
, B
: Byte): TColor32
;
1064 {$IFDEF USE_INLINE}inline;{$ENDIF}
1068 (A
shl ABitCount
shr 8 shl AShift
) or
1069 (R
shl RBitCount
shr 8 shl RShift
) or
1070 (G
shl GBitCount
shr 8 shl GShift
) or
1071 (B
shl BBitCount
shr 8 shl BShift
);
1074 procedure PFGetARGB(const PF
: TPixelFormatInfo
; Color
: LongWord;
1075 var A
, R
, G
, B
: Byte); {$IFDEF USE_INLINE}inline;{$ENDIF}
1079 A
:= (Color
and ABitMask
shr AShift
) * 255 div ARecDiv
;
1080 R
:= (Color
and RBitMask
shr RShift
) * 255 div RRecDiv
;
1081 G
:= (Color
and GBitMask
shr GShift
) * 255 div GRecDiv
;
1082 B
:= (Color
and BBitMask
shl BShift
) * 255 div BRecDiv
;
1086 function PFSetColor(const PF
: TPixelFormatInfo
; ARGB
: TColor32
): LongWord;
1087 {$IFDEF USE_INLINE}inline;{$ENDIF}
1091 (Byte(ARGB
shr 24) shl ABitCount
shr 8 shl AShift
) or
1092 (Byte(ARGB
shr 16) shl RBitCount
shr 8 shl RShift
) or
1093 (Byte(ARGB
shr 8) shl GBitCount
shr 8 shl GShift
) or
1094 (Byte(ARGB
) shl BBitCount
shr 8 shl BShift
);
1097 function PFGetColor(const PF
: TPixelFormatInfo
; Color
: LongWord): TColor32
;
1098 {$IFDEF USE_INLINE}inline;{$ENDIF}
1100 //with PF, TColor32Rec(Result) do
1102 TColor32Rec(Result
).A
:= (Color
and PF
.ABitMask
shr PF
.AShift
) * 255 div PF
.ARecDiv
;
1103 TColor32Rec(Result
).R
:= (Color
and PF
.RBitMask
shr PF
.RShift
) * 255 div PF
.RRecDiv
;
1104 TColor32Rec(Result
).G
:= (Color
and PF
.GBitMask
shr PF
.GShift
) * 255 div PF
.GRecDiv
;
1105 TColor32Rec(Result
).B
:= (Color
and PF
.BBitMask
shl PF
.BShift
) * 255 div PF
.BRecDiv
;
1110 { Color constructor functions }
1113 function Color24(R
, G
, B
: Byte): TColor24Rec
;
1120 function Color32(A
, R
, G
, B
: Byte): TColor32Rec
;
1128 function Color48(R
, G
, B
: Word): TColor48Rec
;
1135 function Color64(A
, R
, G
, B
: Word): TColor64Rec
;
1143 function ColorFP(A
, R
, G
, B
: Single): TColorFPRec
;
1151 function ColorHF(A
, R
, G
, B
: THalfFloat
): TColorHFRec
;
1160 { Additional image manipulation functions (usually used internally by Imaging unit) }
1163 MaxPossibleColors
= 4096;
1171 PColorBin
= ^TColorBin
;
1178 THashTable
= array[0..HashSize
- 1] of PColorBin
;
1184 BMin
, BMax
: LongInt;
1186 Represented
: TColor32Rec
;
1192 Box
: array[0..MaxPossibleColors
- 1] of TColorBox
;
1194 BoxesCreated
: Boolean = False;
1196 procedure ReduceColorsMedianCut(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
1197 DstInfo
: PImageFormatInfo
; MaxColors
: LongInt; ChannelMask
: Byte;
1198 DstPal
: PPalette32
; Actions
: TReduceColorsActions
);
1200 procedure CreateHistogram (Src
: PByte; SrcInfo
: PImageFormatInfo
;
1208 for I
:= 0 to NumPixels
- 1 do
1210 Col
:= GetPixel32Generic(Src
, SrcInfo
, nil);
1211 A
:= Col
.A
and ChannelMask
;
1212 R
:= Col
.R
and ChannelMask
;
1213 G
:= Col
.G
and ChannelMask
;
1214 B
:= Col
.B
and ChannelMask
;
1216 Addr
:= (A
+ 11 * B
+ 59 * R
+ 119 * G
) mod HashSize
;
1219 while (PC
<> nil) and ((PC
.Color
.R
<> R
) or (PC
.Color
.G
<> G
) or
1220 (PC
.Color
.B
<> B
) or (PC
.Color
.A
<> A
)) do
1231 PC
.Next
:= Table
[Addr
];
1236 Inc(Src
, SrcInfo
.BytesPerPixel
);
1240 procedure InitBox (var Box
: TColorBox
);
1254 procedure ChangeBox (var Box
: TColorBox
; const C
: TColorBin
);
1258 if A
< Box
.AMin
then Box
.AMin
:= A
;
1259 if A
> Box
.AMax
then Box
.AMax
:= A
;
1260 if B
< Box
.BMin
then Box
.BMin
:= B
;
1261 if B
> Box
.BMax
then Box
.BMax
:= B
;
1262 if G
< Box
.GMin
then Box
.GMin
:= G
;
1263 if G
> Box
.GMax
then Box
.GMax
:= G
;
1264 if R
< Box
.RMin
then Box
.RMin
:= R
;
1265 if R
> Box
.RMax
then Box
.RMax
:= R
;
1267 Inc(Box
.Total
, C
.Number
);
1270 procedure MakeColormap
;
1274 Cut
, LargestIdx
, Largest
, Size
, S
: LongInt;
1275 CutA
, CutR
, CutG
, CutB
: Boolean;
1276 SumA
, SumR
, SumG
, SumB
: LongInt;
1282 while (I
< HashSize
) and (Table
[I
] = nil) do
1284 if I
< HashSize
then
1286 // put all colors into Box[0]
1290 while CP
.Next
<> nil do
1292 ChangeBox(Box
[0], CP
^);
1295 ChangeBox(Box
[0], CP
^);
1296 CP
.Next
:= Box
[0].List
;
1297 Box
[0].List
:= Table
[I
];
1301 until (I
= HashSize
) or (Table
[I
] <> nil);
1303 // now all colors are in Box[0]
1305 // cut one color box
1307 for I
:= 0 to Boxes
- 1 do
1310 Size
:= (AMax
- AMin
) * AlphaWeight
;
1311 S
:= (RMax
- RMin
) * RedWeight
;
1314 S
:= (GMax
- GMin
) * GreenWeight
;
1317 S
:= (BMax
- BMin
) * BlueWeight
;
1320 if Size
> Largest
then
1328 // cutting Box[LargestIdx] into Box[LargestIdx] and Box[Boxes]
1333 with Box
[LargestIdx
] do
1335 if (AMax
- AMin
) * AlphaWeight
= Largest
then
1337 Cut
:= (AMax
+ AMin
) shr 1;
1341 if (RMax
- RMin
) * RedWeight
= Largest
then
1343 Cut
:= (RMax
+ RMin
) shr 1;
1347 if (GMax
- GMin
) * GreenWeight
= Largest
then
1349 Cut
:= (GMax
+ GMin
) shr 1;
1354 Cut
:= (BMax
+ BMin
) shr 1;
1359 InitBox(Box
[LargestIdx
]);
1360 InitBox(Box
[Boxes
]);
1362 // distribute one color
1366 if (CutA
and (A
<= Cut
)) or (CutR
and (R
<= Cut
)) or
1367 (CutG
and (G
<= Cut
)) or (CutB
and (B
<= Cut
)) then
1372 CP
.Next
:= Box
[i
].List
;
1374 ChangeBox(Box
[i
], CP
^);
1379 until (Boxes
= MaxColors
) or (Largest
= 0);
1380 // compute box representation
1381 for I
:= 0 to Boxes
- 1 do
1389 Inc(SumR
, CP
.Color
.R
* CP
.Number
);
1390 Inc(SumG
, CP
.Color
.G
* CP
.Number
);
1391 Inc(SumB
, CP
.Color
.B
* CP
.Number
);
1392 Inc(SumA
, CP
.Color
.A
* CP
.Number
);
1393 Box
[I
].List
:= CP
.Next
;
1395 until Box
[I
].List
= nil;
1398 Represented
.A
:= SumA
div Total
;
1399 Represented
.R
:= SumR
div Total
;
1400 Represented
.G
:= SumG
div Total
;
1401 Represented
.B
:= SumB
div Total
;
1402 AMin
:= AMin
and ChannelMask
;
1403 RMin
:= RMin
and ChannelMask
;
1404 GMin
:= GMin
and ChannelMask
;
1405 BMin
:= BMin
and ChannelMask
;
1406 AMax
:= (AMax
and ChannelMask
) + (not ChannelMask
);
1407 RMax
:= (RMax
and ChannelMask
) + (not ChannelMask
);
1408 GMax
:= (GMax
and ChannelMask
) + (not ChannelMask
);
1409 BMax
:= (BMax
and ChannelMask
) + (not ChannelMask
);
1413 for I
:= 0 to Boxes
- 2 do
1416 for J
:= I
to Boxes
- 1 do
1417 if Box
[J
].Total
> Largest
then
1419 Largest
:= Box
[J
].Total
;
1422 if LargestIdx
<> I
then
1425 Box
[I
] := Box
[LargestIdx
];
1426 Box
[LargestIdx
] := Temp
;
1432 procedure FillOutputPalette
;
1436 FillChar(DstPal
^, SizeOf(TColor32Rec
) * MaxColors
, $FF);
1437 for I
:= 0 to MaxColors
- 1 do
1440 with Box
[I
].Represented
do
1448 DstPal
[I
].Color
:= $FF000000;
1452 function MapColor(const Col
: TColor32Rec
) : LongInt;
1458 while (I
< Boxes
) and ((Box
[I
].AMin
> A
) or (Box
[I
].AMax
< A
) or
1459 (Box
[I
].RMin
> R
) or (Box
[I
].RMax
< R
) or (Box
[I
].GMin
> G
) or
1460 (Box
[I
].GMax
< G
) or (Box
[I
].BMin
> B
) or (Box
[I
].BMax
< B
)) do
1468 procedure MapImage(Src
, Dst
: PByte; SrcInfo
, DstInfo
: PImageFormatInfo
);
1473 for I
:= 0 to NumPixels
- 1 do
1475 Col
:= GetPixel32Generic(Src
, SrcInfo
, nil);
1476 IndexSetDstPixel(Dst
, DstInfo
, MapColor(Col
));
1477 Inc(Src
, SrcInfo
.BytesPerPixel
);
1478 Inc(Dst
, DstInfo
.BytesPerPixel
);
1483 MaxColors
:= ClampInt(MaxColors
, 2, MaxPossibleColors
);
1485 if (raUpdateHistogram
in Actions
) or (raMapImage
in Actions
) then
1487 Assert(not SrcInfo
.IsSpecial
);
1488 Assert(not SrcInfo
.IsIndexed
);
1491 if raCreateHistogram
in Actions
then
1492 FillChar(Table
, SizeOf(Table
), 0);
1494 if raUpdateHistogram
in Actions
then
1495 CreateHistogram(Src
, SrcInfo
, ChannelMask
);
1497 if raMakeColorMap
in Actions
then
1503 if raMapImage
in Actions
then
1504 MapImage(Src
, Dst
, SrcInfo
, DstInfo
);
1507 procedure StretchNearest(const SrcImage
: TImageData
; SrcX
, SrcY
, SrcWidth
,
1508 SrcHeight
: LongInt; var DstImage
: TImageData
; DstX
, DstY
, DstWidth
,
1509 DstHeight
: LongInt);
1511 Info
: TImageFormatInfo
;
1512 ScaleX
, ScaleY
, X
, Y
, Xp
, Yp
: LongInt;
1513 DstPixel
, SrcLine
: PByte;
1515 GetImageFormatInfo(SrcImage
.Format
, Info
);
1516 Assert(SrcImage
.Format
= DstImage
.Format
);
1517 Assert(not Info
.IsSpecial
);
1518 // Use integers instead of floats for source image pixel coords
1519 // Xp and Yp coords must be shifted right to get read source image coords
1520 ScaleX
:= (SrcWidth
shl 16) div DstWidth
;
1521 ScaleY
:= (SrcHeight
shl 16) div DstHeight
;
1523 for Y
:= 0 to DstHeight
- 1 do
1526 SrcLine
:= @PByteArray(SrcImage
.Bits
)[((SrcY
+ Yp
shr 16) * SrcImage
.Width
+ SrcX
) * Info
.BytesPerPixel
];
1527 DstPixel
:= @PByteArray(DstImage
.Bits
)[((DstY
+ Y
) * DstImage
.Width
+ DstX
) * Info
.BytesPerPixel
];
1528 for X
:= 0 to DstWidth
- 1 do
1530 case Info
.BytesPerPixel
of
1531 1: PByte(DstPixel
)^ := PByteArray(SrcLine
)[Xp
shr 16];
1532 2: PWord(DstPixel
)^ := PWordArray(SrcLine
)[Xp
shr 16];
1533 3: PColor24Rec(DstPixel
)^ := PPalette24(SrcLine
)[Xp
shr 16];
1534 4: PColor32(DstPixel
)^ := PLongWordArray(SrcLine
)[Xp
shr 16];
1535 6: PColor48Rec(DstPixel
)^ := PColor48RecArray(SrcLine
)[Xp
shr 16];
1536 8: PColor64(DstPixel
)^ := PInt64Array(SrcLine
)[Xp
shr 16];
1537 16: PColorFPRec(DstPixel
)^ := PColorFPRecArray(SrcLine
)[Xp
shr 16];
1539 Inc(DstPixel
, Info
.BytesPerPixel
);
1546 { Filter function for nearest filtering. Also known as box filter.}
1547 function FilterNearest(Value
: Single): Single;
1549 if (Value
> -0.5) and (Value
<= 0.5) then
1555 { Filter function for linear filtering. Also known as triangle or Bartlett filter.}
1556 function FilterLinear(Value
: Single): Single;
1561 Result
:= 1.0 - Value
1567 function FilterCosine(Value
: Single): Single;
1570 if Abs(Value
) < 1 then
1571 Result
:= (Cos(Value
* Pi
) + 1) / 2;
1574 { f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 }
1575 function FilterHermite(Value
: Single): Single;
1580 Result
:= (2 * Value
- 3) * Sqr(Value
) + 1
1585 { Quadratic filter. Also known as Bell.}
1586 function FilterQuadratic(Value
: Single): Single;
1591 Result
:= 0.75 - Sqr(Value
)
1595 Value
:= Value
- 1.5;
1596 Result
:= 0.5 * Sqr(Value
);
1603 function FilterGaussian(Value
: Single): Single;
1605 Result
:= Exp(-2.0 * Sqr(Value
)) * Sqrt(2.0 / Pi
);
1608 { 4th order (cubic) b-spline filter.}
1609 function FilterSpline(Value
: Single): Single;
1618 Result
:= 0.5 * Temp
* Value
- Temp
+ 2.0 / 3.0;
1623 Value
:= 2.0 - Value
;
1624 Result
:= Sqr(Value
) * Value
/ 6.0;
1630 { Lanczos-windowed sinc filter.}
1631 function FilterLanczos(Value
: Single): Single;
1633 function SinC(Value
: Single): Single;
1635 if Value
<> 0.0 then
1637 Value
:= Value
* Pi
;
1638 Result
:= Sin(Value
) / Value
;
1648 Result
:= SinC(Value
) * SinC(Value
/ 3.0)
1653 { Micthell cubic filter.}
1654 function FilterMitchell(Value
: Single): Single;
1666 Value
:= (((12.0 - 9.0 * B
- 6.0 * C
) * (Value
* Temp
)) +
1667 ((-18.0 + 12.0 * B
+ 6.0 * C
) * Temp
) +
1669 Result
:= Value
/ 6.0;
1674 Value
:= (((-B
- 6.0 * C
) * (Value
* Temp
)) +
1675 ((6.0 * B
+ 30.0 * C
) * Temp
) +
1676 ((-12.0 * B
- 48.0 * C
) * Value
) +
1677 (8.0 * B
+ 24.0 * C
));
1678 Result
:= Value
/ 6.0;
1684 { CatmullRom spline filter.}
1685 function FilterCatmullRom(Value
: Single): Single;
1690 Result
:= 0.5 * (2.0 + Sqr(Value
) * (-5.0 + 3.0 * Value
))
1693 Result
:= 0.5 * (4.0 + Value
* (-8.0 + Value
* (5.0 - Value
)))
1698 procedure StretchResample(const SrcImage
: TImageData
; SrcX
, SrcY
, SrcWidth
,
1699 SrcHeight
: LongInt; var DstImage
: TImageData
; DstX
, DstY
, DstWidth
,
1700 DstHeight
: LongInt; Filter
: TSamplingFilter
; WrapEdges
: Boolean);
1702 // Calls the other function with filter function and radius defined by Filter
1703 StretchResample(SrcImage
, SrcX
, SrcY
, SrcWidth
, SrcHeight
, DstImage
, DstX
, DstY
,
1704 DstWidth
, DstHeight
, SamplingFilterFunctions
[Filter
], SamplingFilterRadii
[Filter
],
1709 FullEdge
: Boolean = True;
1711 { The following resampling code is modified and extended code from Graphics32
1712 library by Alex A. Denisov.}
1713 function BuildMappingTable(DstLow
, DstHigh
, SrcLow
, SrcHigh
, SrcImageWidth
: LongInt;
1714 Filter
: TFilterFunction
; Radius
: Single; WrapEdges
: Boolean): TMappingTable
;
1716 I
, J
, K
, N
: LongInt;
1717 Left
, Right
, SrcWidth
, DstWidth
: LongInt;
1718 Weight
, Scale
, Center
, Count
: Single;
1722 SrcWidth
:= SrcHigh
- SrcLow
;
1723 DstWidth
:= DstHigh
- DstLow
;
1725 // Check some special cases
1726 if SrcWidth
= 1 then
1728 SetLength(Result
, DstWidth
);
1729 for I
:= 0 to DstWidth
- 1 do
1731 SetLength(Result
[I
], 1);
1732 Result
[I
][0].Pos
:= 0;
1733 Result
[I
][0].Weight
:= 1.0;
1738 if (SrcWidth
= 0) or (DstWidth
= 0) then
1742 Scale
:= DstWidth
/ SrcWidth
1744 Scale
:= (DstWidth
- 1) / (SrcWidth
- 1);
1746 SetLength(Result
, DstWidth
);
1748 // Pre-calculate filter contributions for a row or column
1751 Assert(Length(Result
) = 1);
1752 SetLength(Result
[0], 1);
1753 Result
[0][0].Pos
:= (SrcLow
+ SrcHigh
) div 2;
1754 Result
[0][0].Weight
:= 1.0;
1756 else if Scale
< 1.0 then
1758 // Sub-sampling - scales from bigger to smaller
1759 Radius
:= Radius
/ Scale
;
1760 for I
:= 0 to DstWidth
- 1 do
1763 Center
:= SrcLow
- 0.5 + (I
+ 0.5) / Scale
1765 Center
:= SrcLow
+ I
/ Scale
;
1766 Left
:= Floor(Center
- Radius
);
1767 Right
:= Ceil(Center
+ Radius
);
1769 for J
:= Left
to Right
do
1771 Weight
:= Filter((Center
- J
) * Scale
) * Scale
;
1772 if Weight
<> 0.0 then
1774 Count
:= Count
+ Weight
;
1775 K
:= Length(Result
[I
]);
1776 SetLength(Result
[I
], K
+ 1);
1777 Result
[I
][K
].Pos
:= ClampInt(J
, SrcLow
, SrcHigh
- 1);
1778 Result
[I
][K
].Weight
:= Weight
;
1781 if Length(Result
[I
]) = 0 then
1783 SetLength(Result
[I
], 1);
1784 Result
[I
][0].Pos
:= Floor(Center
);
1785 Result
[I
][0].Weight
:= 1.0;
1787 else if Count
<> 0.0 then
1788 Result
[I
][K
div 2].Weight
:= Result
[I
][K
div 2].Weight
- Count
;
1791 else // if Scale > 1.0 then
1793 // Super-sampling - scales from smaller to bigger
1794 Scale
:= 1.0 / Scale
;
1795 for I
:= 0 to DstWidth
- 1 do
1798 Center
:= SrcLow
- 0.5 + (I
+ 0.5) * Scale
1800 Center
:= SrcLow
+ I
* Scale
;
1801 Left
:= Floor(Center
- Radius
);
1802 Right
:= Ceil(Center
+ Radius
);
1804 for J
:= Left
to Right
do
1806 Weight
:= Filter(Center
- J
);
1807 if Weight
<> 0.0 then
1809 Count
:= Count
+ Weight
;
1810 K
:= Length(Result
[I
]);
1811 SetLength(Result
[I
], K
+ 1);
1816 N
:= SrcImageWidth
+ J
1817 else if J
>= SrcImageWidth
then
1818 N
:= J
- SrcImageWidth
1820 N
:= ClampInt(J
, SrcLow
, SrcHigh
- 1);
1823 N
:= ClampInt(J
, SrcLow
, SrcHigh
- 1);
1825 Result
[I
][K
].Pos
:= N
;
1826 Result
[I
][K
].Weight
:= Weight
;
1829 if Count
<> 0.0 then
1830 Result
[I
][K
div 2].Weight
:= Result
[I
][K
div 2].Weight
- Count
;
1835 procedure FindExtremes(const Map
: TMappingTable
; var MinPos
, MaxPos
: LongInt);
1839 if Length(Map
) > 0 then
1841 MinPos
:= Map
[0][0].Pos
;
1843 for I
:= 0 to Length(Map
) - 1 do
1844 for J
:= 0 to Length(Map
[I
]) - 1 do
1846 if MinPos
> Map
[I
][J
].Pos
then
1847 MinPos
:= Map
[I
][J
].Pos
;
1848 if MaxPos
< Map
[I
][J
].Pos
then
1849 MaxPos
:= Map
[I
][J
].Pos
;
1854 procedure StretchResample(const SrcImage
: TImageData
; SrcX
, SrcY
, SrcWidth
,
1855 SrcHeight
: LongInt; var DstImage
: TImageData
; DstX
, DstY
, DstWidth
,
1856 DstHeight
: LongInt; Filter
: TFilterFunction
; Radius
: Single; WrapEdges
: Boolean);
1858 Channel8BitMax
: Single = 255.0;
1860 MapX
, MapY
: TMappingTable
;
1861 I
, J
, X
, Y
: LongInt;
1862 XMinimum
, XMaximum
: LongInt;
1863 LineBufferFP
: array of TColorFPRec
;
1864 ClusterX
, ClusterY
: TCluster
;
1865 Weight
, AccumA
, AccumR
, AccumG
, AccumB
: Single;
1867 SrcFloat
: TColorFPRec
;
1868 Info
: TImageFormatInfo
;
1869 BytesPerChannel
: LongInt;
1871 GetImageFormatInfo(SrcImage
.Format
, Info
);
1872 Assert(SrcImage
.Format
= DstImage
.Format
);
1873 Assert(not Info
.IsSpecial
and not Info
.IsIndexed
);
1874 BytesPerChannel
:= Info
.BytesPerPixel
div Info
.ChannelCount
;
1876 // Create horizontal and vertical mapping tables
1877 MapX
:= BuildMappingTable(DstX
, DstX
+ DstWidth
, SrcX
, SrcX
+ SrcWidth
,
1878 SrcImage
.Width
, Filter
, Radius
, WrapEdges
);
1879 MapY
:= BuildMappingTable(DstY
, DstY
+ DstHeight
, SrcY
, SrcY
+ SrcHeight
,
1880 SrcImage
.Height
, Filter
, Radius
, WrapEdges
);
1882 if (MapX
= nil) or (MapY
= nil) then
1889 // Find min and max X coords of pixels that will contribute to target image
1890 FindExtremes(MapX
, XMinimum
, XMaximum
);
1892 SetLength(LineBufferFP
, XMaximum
- XMinimum
+ 1);
1893 // Following code works for the rest of data formats
1894 for J
:= 0 to DstHeight
- 1 do
1896 // First for each pixel in the current line sample vertically
1897 // and store results in LineBuffer. Then sample horizontally
1898 // using values in LineBuffer.
1899 ClusterY
:= MapY
[J
];
1900 for X
:= XMinimum
to XMaximum
do
1902 // Clear accumulators
1907 // For each pixel in line compute weighted sum of pixels
1908 // in source column that will contribute to this pixel
1909 for Y
:= 0 to Length(ClusterY
) - 1 do
1911 // Accumulate this pixel's weighted value
1912 Weight
:= ClusterY
[Y
].Weight
;
1913 SrcFloat
:= Info
.GetPixelFP(@PByteArray(SrcImage
.Bits
)[(ClusterY
[Y
].Pos
* SrcImage
.Width
+ X
) * Info
.BytesPerPixel
], @Info
, nil);
1914 AccumB
:= AccumB
+ SrcFloat
.B
* Weight
;
1915 AccumG
:= AccumG
+ SrcFloat
.G
* Weight
;
1916 AccumR
:= AccumR
+ SrcFloat
.R
* Weight
;
1917 AccumA
:= AccumA
+ SrcFloat
.A
* Weight
;
1919 // Store accumulated value for this pixel in buffer
1920 with LineBufferFP
[X
- XMinimum
] do
1929 DstLine
:= @PByteArray(DstImage
.Bits
)[((J
+ DstY
) * DstImage
.Width
+ DstX
) * Info
.BytesPerPixel
];
1930 // Now compute final colors for targte pixels in the current row
1931 // by sampling horizontally
1932 for I
:= 0 to DstWidth
- 1 do
1934 ClusterX
:= MapX
[I
];
1935 // Clear accumulator
1940 // Compute weighted sum of values (which are already
1941 // computed weighted sums of pixels in source columns stored in LineBuffer)
1942 // that will contribute to the current target pixel
1943 for X
:= 0 to Length(ClusterX
) - 1 do
1945 Weight
:= ClusterX
[X
].Weight
;
1946 with LineBufferFP
[ClusterX
[X
].Pos
- XMinimum
] do
1948 AccumB
:= AccumB
+ B
* Weight
;
1949 AccumG
:= AccumG
+ G
* Weight
;
1950 AccumR
:= AccumR
+ R
* Weight
;
1951 AccumA
:= AccumA
+ A
* Weight
;
1955 // Now compute final color to be written to dest image
1956 SrcFloat
.A
:= AccumA
;
1957 SrcFloat
.R
:= AccumR
;
1958 SrcFloat
.G
:= AccumG
;
1959 SrcFloat
.B
:= AccumB
;
1961 Info
.SetPixelFP(DstLine
, @Info
, nil, SrcFloat
);
1962 Inc(DstLine
, Info
.BytesPerPixel
);
1972 procedure FillMipMapLevel(const BiggerLevel
: TImageData
; Width
, Height
: LongInt;
1973 var SmallerLevel
: TImageData
);
1975 Filter
: TSamplingFilter
;
1976 Info
: TImageFormatInfo
;
1977 CompatibleCopy
: TImageData
;
1979 Assert(TestImage(BiggerLevel
));
1980 Filter
:= TSamplingFilter(GetOption(ImagingMipMapFilter
));
1982 // If we have special format image we must create copy to allow pixel access
1983 GetImageFormatInfo(BiggerLevel
.Format
, Info
);
1984 if Info
.IsSpecial
then
1986 InitImage(CompatibleCopy
);
1987 CloneImage(BiggerLevel
, CompatibleCopy
);
1988 ConvertImage(CompatibleCopy
, ifDefault
);
1991 CompatibleCopy
:= BiggerLevel
;
1993 // Create new smaller image
1994 NewImage(Width
, Height
, CompatibleCopy
.Format
, SmallerLevel
);
1995 GetImageFormatInfo(CompatibleCopy
.Format
, Info
);
1996 // If input is indexed we must copy its palette
1997 if Info
.IsIndexed
then
1998 CopyPalette(CompatibleCopy
.Palette
, SmallerLevel
.Palette
, 0, 0, Info
.PaletteEntries
);
2000 if (Filter
= sfNearest
) or Info
.IsIndexed
then
2002 StretchNearest(CompatibleCopy
, 0, 0, CompatibleCopy
.Width
, CompatibleCopy
.Height
,
2003 SmallerLevel
, 0, 0, Width
, Height
);
2007 StretchResample(CompatibleCopy
, 0, 0, CompatibleCopy
.Width
, CompatibleCopy
.Height
,
2008 SmallerLevel
, 0, 0, Width
, Height
, Filter
);
2011 // Free copy and convert result to special format if necessary
2012 if CompatibleCopy
.Format
<> BiggerLevel
.Format
then
2014 ConvertImage(SmallerLevel
, BiggerLevel
.Format
);
2015 FreeImage(CompatibleCopy
);
2020 { Various format support functions }
2022 procedure CopyPixel(Src
, Dest
: Pointer; BytesPerPixel
: LongInt);
2024 case BytesPerPixel
of
2025 1: PByte(Dest
)^ := PByte(Src
)^;
2026 2: PWord(Dest
)^ := PWord(Src
)^;
2027 3: PColor24Rec(Dest
)^ := PColor24Rec(Src
)^;
2028 4: PLongWord(Dest
)^ := PLongWord(Src
)^;
2029 6: PColor48Rec(Dest
)^ := PColor48Rec(Src
)^;
2030 8: PInt64(Dest
)^ := PInt64(Src
)^;
2031 12: PColor96FPRec(Dest
)^ := PColor96FPRec(Src
)^;
2032 16: PColorFPRec(Dest
)^ := PColorFPRec(Src
)^;
2036 function ComparePixels(PixelA
, PixelB
: Pointer; BytesPerPixel
: LongInt): Boolean;
2038 case BytesPerPixel
of
2039 1: Result
:= PByte(PixelA
)^ = PByte(PixelB
)^;
2040 2: Result
:= PWord(PixelA
)^ = PWord(PixelB
)^;
2041 3: Result
:= (PWord(PixelA
)^ = PWord(PixelB
)^) and (PColor24Rec(PixelA
).R
= PColor24Rec(PixelB
).R
);
2042 4: Result
:= PLongWord(PixelA
)^ = PLongWord(PixelB
)^;
2043 6: Result
:= (PLongWord(PixelA
)^ = PLongWord(PixelB
)^) and (PColor48Rec(PixelA
).R
= PColor48Rec(PixelB
).R
);
2044 8: Result
:= PInt64(PixelA
)^ = PInt64(PixelB
)^;
2045 12: Result
:= (PFloatHelper(PixelA
).Data
= PFloatHelper(PixelB
).Data
) and
2046 (PFloatHelper(PixelA
).Data32
= PFloatHelper(PixelB
).Data32
);
2047 16: Result
:= (PFloatHelper(PixelA
).Data
= PFloatHelper(PixelB
).Data
) and
2048 (PFloatHelper(PixelA
).Data64
= PFloatHelper(PixelB
).Data64
);
2054 procedure TranslatePixel(SrcPixel
, DstPixel
: Pointer; SrcFormat
,
2055 DstFormat
: TImageFormat
; SrcPalette
, DstPalette
: PPalette32
);
2057 SrcInfo
, DstInfo
: PImageFormatInfo
;
2060 SrcInfo
:= FInfos
[SrcFormat
];
2061 DstInfo
:= FInfos
[DstFormat
];
2063 PixFP
:= GetPixelFPGeneric(SrcPixel
, SrcInfo
, SrcPalette
);
2064 SetPixelFPGeneric(DstPixel
, DstInfo
, DstPalette
, PixFP
);
2067 procedure ClampFloatPixel(var PixF
: TColorFPRec
);
2069 if PixF
.A
> 1.0 then
2071 if PixF
.R
> 1.0 then
2073 if PixF
.G
> 1.0 then
2075 if PixF
.B
> 1.0 then
2078 if PixF
.A
< 0.0 then
2080 if PixF
.R
< 0.0 then
2082 if PixF
.G
< 0.0 then
2084 if PixF
.B
< 0.0 then
2088 procedure ConvertToPixel32(SrcPix
: PByte; DestPix
: PColor32Rec
;
2089 const SrcInfo
: TImageFormatInfo
; SrcPalette
: PPalette32
);
2091 case SrcInfo
.Format
of
2094 DestPix
^ := SrcPalette
[SrcPix
^];
2098 DestPix
.R
:= SrcPix
^;
2099 DestPix
.G
:= SrcPix
^;
2100 DestPix
.B
:= SrcPix
^;
2105 DestPix
.R
:= SrcPix
^;
2106 DestPix
.G
:= SrcPix
^;
2107 DestPix
.B
:= SrcPix
^;
2108 DestPix
.A
:= PWordRec(SrcPix
).High
;
2112 DestPix
.R
:= PWord(SrcPix
)^ shr 8;
2113 DestPix
.G
:= DestPix
.R
;
2114 DestPix
.B
:= DestPix
.R
;
2119 DestPix
.Color24Rec
:= PColor24Rec(SrcPix
)^;
2124 DestPix
^ := PColor32Rec(SrcPix
)^;
2128 DestPix
.R
:= PColor48Rec(SrcPix
).R
shr 8;
2129 DestPix
.G
:= PColor48Rec(SrcPix
).G
shr 8;
2130 DestPix
.B
:= PColor48Rec(SrcPix
).B
shr 8;
2135 DestPix
.R
:= PColor64Rec(SrcPix
).R
shr 8;
2136 DestPix
.G
:= PColor64Rec(SrcPix
).G
shr 8;
2137 DestPix
.B
:= PColor64Rec(SrcPix
).B
shr 8;
2138 DestPix
.A
:= PColor64Rec(SrcPix
).A
shr 8;
2141 DestPix
^ := SrcInfo
.GetPixel32(SrcPix
, @SrcInfo
, SrcPalette
);
2145 procedure AddPadBytes(DataIn
: Pointer; DataOut
: Pointer; Width
, Height
,
2146 Bpp
, WidthBytes
: LongInt);
2151 for I
:= 0 to Height
- 1 do
2152 Move(PByteArray(DataIn
)[I
* W
], PByteArray(DataOut
)[I
* WidthBytes
], W
);
2155 procedure RemovePadBytes(DataIn
: Pointer; DataOut
: Pointer; Width
, Height
,
2156 Bpp
, WidthBytes
: LongInt);
2161 for I
:= 0 to Height
- 1 do
2162 Move(PByteArray(DataIn
)[I
* WidthBytes
], PByteArray(DataOut
)[I
* W
], W
);
2165 procedure Convert1To8(DataIn
, DataOut
: PByte; Width
, Height
,
2166 WidthBytes
: LongInt; ScaleTo8Bits
: Boolean);
2168 Mask1
: array[0..7] of Byte = ($80, $40, $20, $10, $08, $04, $02, $01);
2169 Shift1
: array[0..7] of Byte = (7, 6, 5, 4, 3, 2, 1, 0);
2170 Scaling
: Byte = 255;
2173 InArray
: PByteArray
absolute DataIn
;
2175 for Y
:= 0 to Height
- 1 do
2176 for X
:= 0 to Width
- 1 do
2178 DataOut
^ := (InArray
[Y
* WidthBytes
+ X
shr 3] and Mask1
[X
and 7]) shr Shift1
[X
and 7];
2179 if ScaleTo8Bits
then
2180 DataOut
^ := DataOut
^ * Scaling
;
2185 procedure Convert2To8(DataIn
, DataOut
: PByte; Width
, Height
,
2186 WidthBytes
: LongInt; ScaleTo8Bits
: Boolean);
2188 Mask2
: array[0..3] of Byte = ($C0, $30, $0C, $03);
2189 Shift2
: array[0..3] of Byte = (6, 4, 2, 0);
2193 InArray
: PByteArray
absolute DataIn
;
2195 for Y
:= 0 to Height
- 1 do
2196 for X
:= 0 to Width
- 1 do
2198 DataOut
^ := (InArray
[Y
* WidthBytes
+ X
shr 2] and Mask2
[X
and 3]) shr Shift2
[X
and 3];
2199 if ScaleTo8Bits
then
2200 DataOut
^ := DataOut
^ * Scaling
;
2205 procedure Convert4To8(DataIn
, DataOut
: PByte; Width
, Height
,
2206 WidthBytes
: LongInt; ScaleTo8Bits
: Boolean);
2208 Mask4
: array[0..1] of Byte = ($F0, $0F);
2209 Shift4
: array[0..1] of Byte = (4, 0);
2213 InArray
: PByteArray
absolute DataIn
;
2215 for Y
:= 0 to Height
- 1 do
2216 for X
:= 0 to Width
- 1 do
2218 DataOut
^ := (InArray
[Y
* WidthBytes
+ X
shr 1] and Mask4
[X
and 1]) shr Shift4
[X
and 1];
2219 if ScaleTo8Bits
then
2220 DataOut
^ := DataOut
^ * Scaling
;
2225 function Has16BitImageAlpha(NumPixels
: LongInt; Data
: PWord): Boolean;
2230 for I
:= 0 to NumPixels
- 1 do
2232 if Data
^ >= 1 shl 15 then
2241 function Has32BitImageAlpha(NumPixels
: LongInt; Data
: PLongWord): Boolean;
2246 for I
:= 0 to NumPixels
- 1 do
2248 if Data
^ >= 1 shl 24 then
2257 function PaletteHasAlpha(Palette
: PPalette32
; PaletteEntries
: Integer): Boolean;
2261 for I
:= 0 to PaletteEntries
- 1 do
2263 if Palette
[I
].A
<> 255 then
2272 function GetScanLine(ImageBits
: Pointer; const FormatInfo
: TImageFormatInfo
;
2273 LineWidth
, Index
: LongInt): Pointer;
2277 Assert(not FormatInfo
.IsSpecial
);
2278 LineBytes
:= FormatInfo
.GetPixelsSize(FormatInfo
.Format
, LineWidth
, 1);
2279 Result
:= @PByteArray(ImageBits
)[Index
* LineBytes
];
2282 function IsImageFormatValid(Format
: TImageFormat
): Boolean;
2284 Result
:= FInfos
[Format
] <> nil;
2288 HalfMin
: Single = 5.96046448e-08; // Smallest positive half
2289 HalfMinNorm
: Single = 6.10351562e-05; // Smallest positive normalized half
2290 HalfMax
: Single = 65504.0; // Largest positive half
2291 HalfEpsilon
: Single = 0.00097656; // Smallest positive e for which half (1.0 + e) != half (1.0)
2292 HalfNaN
: THalfFloat
= 65535;
2293 HalfPosInf
: THalfFloat
= 31744;
2294 HalfNegInf
: THalfFloat
= 64512;
2298 Half/Float conversions inspired by half class from OpenEXR library.
2300 Float (Pascal Single type) is an IEEE 754 single-precision
2301 floating point number.
2303 Bit layout of Single:
2311 X XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX
2325 S is the sign-bit, e is the exponent and m is the significand (mantissa).
2328 function HalfToFloat(Half
: THalfFloat
): Single;
2330 Dst
, Sign
, Mantissa
: LongWord;
2333 // Extract sign, exponent, and mantissa from half number
2334 Sign
:= Half
shr 15;
2335 Exp
:= (Half
and $7C00) shr 10;
2336 Mantissa
:= Half
and 1023;
2338 if (Exp
> 0) and (Exp
< 31) then
2340 // Common normalized number
2341 Exp
:= Exp
+ (127 - 15);
2342 Mantissa
:= Mantissa
shl 13;
2343 Dst
:= (Sign
shl 31) or (LongWord(Exp
) shl 23) or Mantissa
;
2344 // Result := Power(-1, Sign) * Power(2, Exp - 15) * (1 + Mantissa / 1024);
2346 else if (Exp
= 0) and (Mantissa
= 0) then
2348 // Zero - preserve sign
2351 else if (Exp
= 0) and (Mantissa
<> 0) then
2353 // Denormalized number - renormalize it
2354 while (Mantissa
and $00000400) = 0 do
2356 Mantissa
:= Mantissa
shl 1;
2360 Mantissa
:= Mantissa
and not $00000400;
2361 // Now assemble normalized number
2362 Exp
:= Exp
+ (127 - 15);
2363 Mantissa
:= Mantissa
shl 13;
2364 Dst
:= (Sign
shl 31) or (LongWord(Exp
) shl 23) or Mantissa
;
2365 // Result := Power(-1, Sign) * Power(2, -14) * (Mantissa / 1024);
2367 else if (Exp
= 31) and (Mantissa
= 0) then
2370 Dst
:= (Sign
shl 31) or $7F800000;
2372 else //if (Exp = 31) and (Mantisa <> 0) then
2374 // Not a number - preserve sign and mantissa
2375 Dst
:= (Sign
shl 31) or $7F800000 or (Mantissa
shl 13);
2378 // Reinterpret LongWord as Single
2379 Result
:= PSingle(@Dst
)^;
2382 function FloatToHalf(Float
: Single): THalfFloat
;
2385 Sign
, Exp
, Mantissa
: LongInt;
2387 Src
:= PLongWord(@Float
)^;
2388 // Extract sign, exponent, and mantissa from Single number
2390 Exp
:= LongInt((Src
and $7F800000) shr 23) - 127 + 15;
2391 Mantissa
:= Src
and $007FFFFF;
2393 if (Exp
> 0) and (Exp
< 30) then
2395 // Simple case - round the significand and combine it with the sign and exponent
2396 Result
:= (Sign
shl 15) or (Exp
shl 10) or ((Mantissa
+ $00001000) shr 13);
2398 else if Src
= 0 then
2400 // Input float is zero - return zero
2405 // Difficult case - lengthy conversion
2410 // Input float's value is less than HalfMin, return zero
2415 // Float is a normalized Single whose magnitude is less than HalfNormMin.
2416 // We convert it to denormalized half.
2417 Mantissa
:= (Mantissa
or $00800000) shr (1 - Exp
);
2419 if (Mantissa
and $00001000) > 0 then
2420 Mantissa
:= Mantissa
+ $00002000;
2421 // Assemble Sign and Mantissa (Exp is zero to get denormalized number)
2422 Result
:= (Sign
shl 15) or (Mantissa
shr 13);
2425 else if Exp
= 255 - 127 + 15 then
2427 if Mantissa
= 0 then
2429 // Input float is infinity, create infinity half with original sign
2430 Result
:= (Sign
shl 15) or $7C00;
2434 // Input float is NaN, create half NaN with original sign and mantissa
2435 Result
:= (Sign
shl 15) or $7C00 or (Mantissa
shr 13);
2440 // Exp is > 0 so input float is normalized Single
2443 if (Mantissa
and $00001000) > 0 then
2445 Mantissa
:= Mantissa
+ $00002000;
2446 if (Mantissa
and $00800000) > 0 then
2455 // Exponent overflow - return infinity half
2456 Result
:= (Sign
shl 15) or $7C00;
2459 // Assemble normalized half
2460 Result
:= (Sign
shl 15) or (Exp
shl 10) or (Mantissa
shr 13);
2465 function ColorHalfToFloat(ColorHF
: TColorHFRec
): TColorFPRec
;
2467 Result
.A
:= HalfToFloat(ColorHF
.A
);
2468 Result
.R
:= HalfToFloat(ColorHF
.R
);
2469 Result
.G
:= HalfToFloat(ColorHF
.G
);
2470 Result
.B
:= HalfToFloat(ColorHF
.B
);
2473 function ColorFloatToHalf(ColorFP
: TColorFPRec
): TColorHFRec
;
2475 Result
.A
:= FloatToHalf(ColorFP
.A
);
2476 Result
.R
:= FloatToHalf(ColorFP
.R
);
2477 Result
.G
:= FloatToHalf(ColorFP
.G
);
2478 Result
.B
:= FloatToHalf(ColorFP
.B
);
2481 procedure VisualizePalette(Pal
: PPalette32
; Entries
: Integer; out PalImage
: TImageData
);
2486 InitImage(PalImage
);
2487 NewImage(Entries
, 1, ifA8R8G8B8
, PalImage
);
2488 Pix
:= PalImage
.Bits
;
2489 for I
:= 0 to Entries
- 1 do
2491 Pix
^ := Pal
[I
].Color
;
2497 { Pixel readers/writers for different image formats }
2499 procedure ChannelGetSrcPixel(Src
: PByte; SrcInfo
: PImageFormatInfo
;
2500 var Pix
: TColor64Rec
);
2508 FillChar(Pix
, SizeOf(Pix
), 0);
2509 // returns 64 bit color value with 16 bits for each channel
2510 case SrcInfo
.BytesPerPixel
of
2513 PFGetARGB(SrcInfo
.PixelFormat
^, Src
^, A
, R
, G
, B
);
2521 PFGetARGB(SrcInfo
.PixelFormat
^, PWord(Src
)^, A
, R
, G
, B
);
2530 R
:= MulDiv(PColor24Rec(Src
).R
, 65535, 255);
2531 G
:= MulDiv(PColor24Rec(Src
).G
, 65535, 255);
2532 B
:= MulDiv(PColor24Rec(Src
).B
, 65535, 255);
2537 A
:= MulDiv(PColor32Rec(Src
).A
, 65535, 255);
2538 R
:= MulDiv(PColor32Rec(Src
).R
, 65535, 255);
2539 G
:= MulDiv(PColor32Rec(Src
).G
, 65535, 255);
2540 B
:= MulDiv(PColor32Rec(Src
).B
, 65535, 255);
2545 R
:= PColor48Rec(Src
).R
;
2546 G
:= PColor48Rec(Src
).G
;
2547 B
:= PColor48Rec(Src
).B
;
2549 8: Pix
.Color
:= PColor64(Src
)^;
2551 // if src has no alpha, we set it to max (otherwise we would have to
2552 // test if dest has alpha or not in each ChannelToXXX function)
2553 if not SrcInfo
.HasAlphaChannel
then
2556 if SrcInfo
.IsRBSwapped
then
2557 SwapValues(Pix
.R
, Pix
.B
);
2560 procedure ChannelSetDstPixel(Dst
: PByte; DstInfo
: PImageFormatInfo
;
2561 const Pix
: TColor64Rec
);
2566 if DstInfo
.IsRBSwapped
then
2567 SwapValues(PixW
.R
, PixW
.B
);
2568 // Pix contains 64 bit color value with 16 bit for each channel
2569 case DstInfo
.BytesPerPixel
of
2570 1: Dst
^ := PFSetARGB(DstInfo
.PixelFormat
^, PixW
.A
shr 8,
2571 PixW
.R
shr 8, PixW
.G
shr 8, PixW
.B
shr 8);
2572 2: PWord(Dst
)^ := PFSetARGB(DstInfo
.PixelFormat
^, PixW
.A
shr 8,
2573 PixW
.R
shr 8, PixW
.G
shr 8, PixW
.B
shr 8);
2575 with PColor24Rec(Dst
)^ do
2577 R
:= MulDiv(PixW
.R
, 255, 65535);
2578 G
:= MulDiv(PixW
.G
, 255, 65535);
2579 B
:= MulDiv(PixW
.B
, 255, 65535);
2582 with PColor32Rec(Dst
)^ do
2584 A
:= MulDiv(PixW
.A
, 255, 65535);
2585 R
:= MulDiv(PixW
.R
, 255, 65535);
2586 G
:= MulDiv(PixW
.G
, 255, 65535);
2587 B
:= MulDiv(PixW
.B
, 255, 65535);
2590 with PColor48Rec(Dst
)^ do
2596 8: PColor64(Dst
)^ := PixW
.Color
;
2600 procedure GrayGetSrcPixel(Src
: PByte; SrcInfo
: PImageFormatInfo
;
2601 var Gray
: TColor64Rec
; var Alpha
: Word);
2603 FillChar(Gray
, SizeOf(Gray
), 0);
2604 // Source alpha is scaled to 16 bits and stored in Alpha,
2605 // grayscale value is scaled to 64 bits and stored in Gray
2606 case SrcInfo
.BytesPerPixel
of
2607 1: Gray
.A
:= MulDiv(Src
^, 65535, 255);
2609 if SrcInfo
.HasAlphaChannel
then
2610 with PWordRec(Src
)^ do
2612 Alpha
:= MulDiv(High
, 65535, 255);
2613 Gray
.A
:= MulDiv(Low
, 65535, 255);
2616 Gray
.A
:= PWord(Src
)^;
2618 if SrcInfo
.HasAlphaChannel
then
2619 with PLongWordRec(Src
)^ do
2625 with PLongWordRec(Src
)^ do
2630 8: Gray
.Color
:= PColor64(Src
)^;
2632 // if src has no alpha, we set it to max (otherwise we would have to
2633 // test if dest has alpha or not in each GrayToXXX function)
2634 if not SrcInfo
.HasAlphaChannel
then
2638 procedure GraySetDstPixel(Dst
: PByte; DstInfo
: PImageFormatInfo
;
2639 const Gray
: TColor64Rec
; Alpha
: Word);
2641 // Gray contains grayscale value scaled to 64 bits, Alpha contains
2642 // alpha value scaled to 16 bits
2643 case DstInfo
.BytesPerPixel
of
2644 1: Dst
^ := MulDiv(Gray
.A
, 255, 65535);
2646 if DstInfo
.HasAlphaChannel
then
2647 with PWordRec(Dst
)^ do
2649 High
:= MulDiv(Alpha
, 255, 65535);
2650 Low
:= MulDiv(Gray
.A
, 255, 65535);
2653 PWord(Dst
)^ := Gray
.A
;
2655 if DstInfo
.HasAlphaChannel
then
2656 with PLongWordRec(Dst
)^ do
2662 with PLongWordRec(Dst
)^ do
2667 8: PColor64(Dst
)^ := Gray
.Color
;
2671 procedure FloatGetSrcPixel(Src
: PByte; SrcInfo
: PImageFormatInfo
;
2672 var Pix
: TColorFPRec
);
2676 Assert(SrcInfo
.BytesPerPixel
in [2, 4, 8, 12, 16]);
2678 if SrcInfo
.BytesPerPixel
in [4, 12, 16] then
2680 // IEEE 754 single-precision channels
2681 FillChar(Pix
, SizeOf(Pix
), 0);
2682 case SrcInfo
.BytesPerPixel
of
2683 4: Pix
.R
:= PSingle(Src
)^;
2684 12: Pix
.Color96Rec
:= PColor96FPRec(Src
)^;
2685 16: Pix
:= PColorFPRec(Src
)^;
2690 // Half float channels
2691 FillChar(PixHF
, SizeOf(PixHF
), 0);
2692 case SrcInfo
.BytesPerPixel
of
2693 2: PixHF
.R
:= PHalfFloat(Src
)^;
2694 8: PixHF
:= PColorHFRec(Src
)^;
2696 Pix
:= ColorHalfToFloat(PixHF
);
2699 // If src has no alpha, we set it to max (otherwise we would have to
2700 // test if dest has alpha or not in each FloatToXXX function)
2701 if not SrcInfo
.HasAlphaChannel
then
2703 if SrcInfo
.IsRBSwapped
then
2704 SwapValues(Pix
.R
, Pix
.B
);
2707 procedure FloatSetDstPixel(Dst
: PByte; DstInfo
: PImageFormatInfo
;
2708 const Pix
: TColorFPRec
);
2713 Assert(DstInfo
.BytesPerPixel
in [2, 4, 8, 12, 16]);
2716 if DstInfo
.IsRBSwapped
then
2717 SwapValues(PixW
.R
, PixW
.B
);
2719 if DstInfo
.BytesPerPixel
in [4, 12, 16] then
2721 case DstInfo
.BytesPerPixel
of
2722 4: PSingle(Dst
)^ := PixW
.R
;
2723 12: PColor96FPRec(Dst
)^:= PixW
.Color96Rec
;
2724 16: PColorFPRec(Dst
)^ := PixW
;
2729 PixHF
:= ColorFloatToHalf(PixW
);
2730 case DstInfo
.BytesPerPixel
of
2731 2: PHalfFloat(Dst
)^ := PixHF
.R
;
2732 8: PColorHFRec(Dst
)^ := PixHF
;
2737 procedure IndexGetSrcPixel(Src
: PByte; SrcInfo
: PImageFormatInfo
;
2738 var Index
: LongWord);
2740 case SrcInfo
.BytesPerPixel
of
2745 procedure IndexSetDstPixel(Dst
: PByte; DstInfo
: PImageFormatInfo
;
2748 case DstInfo
.BytesPerPixel
of
2749 1: Dst
^ := Byte(Index
);
2750 2: PWord(Dst
)^ := Word(Index
);
2751 4: PLongWord(Dst
)^ := Index
;
2756 { Pixel readers/writers for 32bit and FP colors}
2758 function GetPixel32Generic(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
): TColor32Rec
;
2765 if Info
.Format
= ifA8R8G8B8
then
2767 Result
:= PColor32Rec(Bits
)^
2769 else if Info
.Format
= ifR8G8B8
then
2771 PColor24Rec(@Result
)^ := PColor24Rec(Bits
)^;
2774 else if Info
.IsFloatingPoint
then
2776 FloatGetSrcPixel(Bits
, Info
, PixF
);
2777 Result
.A
:= ClampToByte(Round(PixF
.A
* 255.0));
2778 Result
.R
:= ClampToByte(Round(PixF
.R
* 255.0));
2779 Result
.G
:= ClampToByte(Round(PixF
.G
* 255.0));
2780 Result
.B
:= ClampToByte(Round(PixF
.B
* 255.0));
2782 else if Info
.HasGrayChannel
then
2784 GrayGetSrcPixel(Bits
, Info
, Pix64
, Alpha
);
2785 Result
.A
:= MulDiv(Alpha
, 255, 65535);
2786 Result
.R
:= MulDiv(Pix64
.A
, 255, 65535);
2787 Result
.G
:= MulDiv(Pix64
.A
, 255, 65535);
2788 Result
.B
:= MulDiv(Pix64
.A
, 255, 65535);
2790 else if Info
.IsIndexed
then
2792 IndexGetSrcPixel(Bits
, Info
, Index
);
2793 Result
:= Palette
[Index
];
2797 ChannelGetSrcPixel(Bits
, Info
, Pix64
);
2798 Result
.A
:= MulDiv(Pix64
.A
, 255, 65535);
2799 Result
.R
:= MulDiv(Pix64
.R
, 255, 65535);
2800 Result
.G
:= MulDiv(Pix64
.G
, 255, 65535);
2801 Result
.B
:= MulDiv(Pix64
.B
, 255, 65535);
2805 procedure SetPixel32Generic(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
; const Color
: TColor32Rec
);
2812 if Info
.Format
= ifA8R8G8B8
then
2814 PColor32Rec(Bits
)^ := Color
2816 else if Info
.Format
= ifR8G8B8
then
2818 PColor24Rec(Bits
)^ := Color
.Color24Rec
;
2820 else if Info
.IsFloatingPoint
then
2822 PixF
.A
:= Color
.A
* OneDiv8Bit
;
2823 PixF
.R
:= Color
.R
* OneDiv8Bit
;
2824 PixF
.G
:= Color
.G
* OneDiv8Bit
;
2825 PixF
.B
:= Color
.B
* OneDiv8Bit
;
2826 FloatSetDstPixel(Bits
, Info
, PixF
);
2828 else if Info
.HasGrayChannel
then
2830 Alpha
:= MulDiv(Color
.A
, 65535, 255);
2832 Pix64
.A
:= MulDiv(Round(GrayConv
.R
* Color
.R
+ GrayConv
.G
* Color
.G
+
2833 GrayConv
.B
* Color
.B
), 65535, 255);
2834 GraySetDstPixel(Bits
, Info
, Pix64
, Alpha
);
2836 else if Info
.IsIndexed
then
2838 Index
:= FindColor(Palette
, Info
.PaletteEntries
, Color
.Color
);
2839 IndexSetDstPixel(Bits
, Info
, Index
);
2843 Pix64
.A
:= MulDiv(Color
.A
, 65535, 255);
2844 Pix64
.R
:= MulDiv(Color
.R
, 65535, 255);
2845 Pix64
.G
:= MulDiv(Color
.G
, 65535, 255);
2846 Pix64
.B
:= MulDiv(Color
.B
, 65535, 255);
2847 ChannelSetDstPixel(Bits
, Info
, Pix64
);
2851 function GetPixelFPGeneric(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
): TColorFPRec
;
2858 if Info
.IsFloatingPoint
then
2860 FloatGetSrcPixel(Bits
, Info
, Result
);
2862 else if Info
.HasGrayChannel
then
2864 GrayGetSrcPixel(Bits
, Info
, Pix64
, Alpha
);
2865 Result
.A
:= Alpha
* OneDiv16Bit
;
2866 Result
.R
:= Pix64
.A
* OneDiv16Bit
;
2867 Result
.G
:= Pix64
.A
* OneDiv16Bit
;
2868 Result
.B
:= Pix64
.A
* OneDiv16Bit
;
2870 else if Info
.IsIndexed
then
2872 IndexGetSrcPixel(Bits
, Info
, Index
);
2873 Pix32
:= Palette
[Index
];
2874 Result
.A
:= Pix32
.A
* OneDiv8Bit
;
2875 Result
.R
:= Pix32
.R
* OneDiv8Bit
;
2876 Result
.G
:= Pix32
.G
* OneDiv8Bit
;
2877 Result
.B
:= Pix32
.B
* OneDiv8Bit
;
2881 ChannelGetSrcPixel(Bits
, Info
, Pix64
);
2882 Result
.A
:= Pix64
.A
* OneDiv16Bit
;
2883 Result
.R
:= Pix64
.R
* OneDiv16Bit
;
2884 Result
.G
:= Pix64
.G
* OneDiv16Bit
;
2885 Result
.B
:= Pix64
.B
* OneDiv16Bit
;
2889 procedure SetPixelFPGeneric(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
; const Color
: TColorFPRec
);
2896 if Info
.IsFloatingPoint
then
2898 FloatSetDstPixel(Bits
, Info
, Color
);
2900 else if Info
.HasGrayChannel
then
2902 Alpha
:= ClampToWord(Round(Color
.A
* 65535.0));
2904 Pix64
.A
:= ClampToWord(Round((GrayConv
.R
* Color
.R
+ GrayConv
.G
* Color
.G
+
2905 GrayConv
.B
* Color
.B
) * 65535.0));
2906 GraySetDstPixel(Bits
, Info
, Pix64
, Alpha
);
2908 else if Info
.IsIndexed
then
2910 Pix32
.A
:= ClampToByte(Round(Color
.A
* 255.0));
2911 Pix32
.R
:= ClampToByte(Round(Color
.R
* 255.0));
2912 Pix32
.G
:= ClampToByte(Round(Color
.G
* 255.0));
2913 Pix32
.B
:= ClampToByte(Round(Color
.B
* 255.0));
2914 Index
:= FindColor(Palette
, Info
.PaletteEntries
, Pix32
.Color
);
2915 IndexSetDstPixel(Bits
, Info
, Index
);
2919 Pix64
.A
:= ClampToWord(Round(Color
.A
* 65535.0));
2920 Pix64
.R
:= ClampToWord(Round(Color
.R
* 65535.0));
2921 Pix64
.G
:= ClampToWord(Round(Color
.G
* 65535.0));
2922 Pix64
.B
:= ClampToWord(Round(Color
.B
* 65535.0));
2923 ChannelSetDstPixel(Bits
, Info
, Pix64
);
2928 { Image format conversion functions }
2930 procedure ChannelToChannel(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
2931 DstInfo
: PImageFormatInfo
);
2936 // two most common conversions (RGB->ARGB and ARGB->RGB for 24/32 bit
2937 // images) are made separately from general ARGB conversion to
2939 if (SrcInfo
.BytesPerPixel
= 3) and (DstInfo
.BytesPerPixel
= 4) then
2940 for I
:= 0 to NumPixels
- 1 do
2942 PColor24Rec(Dst
)^ := PColor24Rec(Src
)^;
2943 if DstInfo
.HasAlphaChannel
then
2944 PColor32Rec(Dst
).A
:= 255;
2945 Inc(Src
, SrcInfo
.BytesPerPixel
);
2946 Inc(Dst
, DstInfo
.BytesPerPixel
);
2949 if (SrcInfo
.BytesPerPixel
= 4) and (DstInfo
.BytesPerPixel
= 3) then
2950 for I
:= 0 to NumPixels
- 1 do
2952 PColor24Rec(Dst
)^ := PColor24Rec(Src
)^;
2953 Inc(Src
, SrcInfo
.BytesPerPixel
);
2954 Inc(Dst
, DstInfo
.BytesPerPixel
);
2957 for I
:= 0 to NumPixels
- 1 do
2959 // general ARGB conversion
2960 ChannelGetSrcPixel(Src
, SrcInfo
, Pix64
);
2961 ChannelSetDstPixel(Dst
, DstInfo
, Pix64
);
2962 Inc(Src
, SrcInfo
.BytesPerPixel
);
2963 Inc(Dst
, DstInfo
.BytesPerPixel
);
2967 procedure ChannelToGray(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
2968 DstInfo
: PImageFormatInfo
);
2974 // two most common conversions (R8G8B8->Gray8 nad A8R8G8B8->Gray8)
2975 // are made separately from general conversions to make them faster
2976 if (SrcInfo
.BytesPerPixel
in [3, 4]) and (DstInfo
.Format
= ifGray8
) then
2977 for I
:= 0 to NumPixels
- 1 do
2979 Dst
^ := Round(GrayConv
.R
* PColor24Rec(Src
).R
+ GrayConv
.G
* PColor24Rec(Src
).G
+
2980 GrayConv
.B
* PColor24Rec(Src
).B
);
2981 Inc(Src
, SrcInfo
.BytesPerPixel
);
2982 Inc(Dst
, DstInfo
.BytesPerPixel
);
2985 for I
:= 0 to NumPixels
- 1 do
2987 ChannelGetSrcPixel(Src
, SrcInfo
, Pix64
);
2989 // alpha is saved from source pixel to Alpha,
2990 // Gray value is computed and set to highest word of Pix64 so
2991 // Pix64.Color contains grayscale value scaled to 64 bits
2994 Pix64
.A
:= Round(R
* Pix64
.R
+ G
* Pix64
.G
+ B
* Pix64
.B
);
2996 GraySetDstPixel(Dst
, DstInfo
, Pix64
, Alpha
);
2997 Inc(Src
, SrcInfo
.BytesPerPixel
);
2998 Inc(Dst
, DstInfo
.BytesPerPixel
);
3002 procedure ChannelToFloat(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
3003 DstInfo
: PImageFormatInfo
);
3009 for I
:= 0 to NumPixels
- 1 do
3011 ChannelGetSrcPixel(Src
, SrcInfo
, Pix64
);
3013 // floating point channel values are scaled to 1.0
3014 PixF
.A
:= Pix64
.A
* OneDiv16Bit
;
3015 PixF
.R
:= Pix64
.R
* OneDiv16Bit
;
3016 PixF
.G
:= Pix64
.G
* OneDiv16Bit
;
3017 PixF
.B
:= Pix64
.B
* OneDiv16Bit
;
3019 FloatSetDstPixel(Dst
, DstInfo
, PixF
);
3020 Inc(Src
, SrcInfo
.BytesPerPixel
);
3021 Inc(Dst
, DstInfo
.BytesPerPixel
);
3025 procedure ChannelToIndex(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
3026 DstInfo
: PImageFormatInfo
; DstPal
: PPalette32
);
3028 ReduceColorsMedianCut(NumPixels
, Src
, Dst
, SrcInfo
, DstInfo
, DstInfo
.PaletteEntries
,
3029 GetOption(ImagingColorReductionMask
), DstPal
);
3032 procedure GrayToGray(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
3033 DstInfo
: PImageFormatInfo
);
3039 // two most common conversions (Gray8->Gray16 nad Gray16->Gray8)
3040 // are made separately from general conversions to make them faster
3041 if (SrcInfo
.Format
= ifGray8
) and (DstInfo
.Format
= ifGray16
) then
3043 for I
:= 0 to NumPixels
- 1 do
3044 PWordArray(Dst
)[I
] := PByteArray(Src
)[I
] shl 8;
3048 if (DstInfo
.Format
= ifGray8
) and (SrcInfo
.Format
= ifGray16
) then
3050 for I
:= 0 to NumPixels
- 1 do
3051 PByteArray(Dst
)[I
] := PWordArray(Src
)[I
] shr 8;
3054 for I
:= 0 to NumPixels
- 1 do
3056 // general grayscale conversion
3057 GrayGetSrcPixel(Src
, SrcInfo
, Gray
, Alpha
);
3058 GraySetDstPixel(Dst
, DstInfo
, Gray
, Alpha
);
3059 Inc(Src
, SrcInfo
.BytesPerPixel
);
3060 Inc(Dst
, DstInfo
.BytesPerPixel
);
3065 procedure GrayToChannel(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
3066 DstInfo
: PImageFormatInfo
);
3072 // two most common conversions (Gray8->R8G8B8 nad Gray8->A8R8G8B8)
3073 // are made separately from general conversions to make them faster
3074 if (DstInfo
.BytesPerPixel
in [3, 4]) and (SrcInfo
.Format
= ifGray8
) then
3075 for I
:= 0 to NumPixels
- 1 do
3077 PColor24Rec(Dst
).R
:= Src
^;
3078 PColor24Rec(Dst
).G
:= Src
^;
3079 PColor24Rec(Dst
).B
:= Src
^;
3080 if DstInfo
.HasAlphaChannel
then
3081 PColor32Rec(Dst
).A
:= $FF;
3082 Inc(Src
, SrcInfo
.BytesPerPixel
);
3083 Inc(Dst
, DstInfo
.BytesPerPixel
);
3086 for I
:= 0 to NumPixels
- 1 do
3088 GrayGetSrcPixel(Src
, SrcInfo
, Pix64
, Alpha
);
3090 // most significant word of grayscale value is used for
3091 // each channel and alpha channel is set to Alpha
3097 ChannelSetDstPixel(Dst
, DstInfo
, Pix64
);
3098 Inc(Src
, SrcInfo
.BytesPerPixel
);
3099 Inc(Dst
, DstInfo
.BytesPerPixel
);
3103 procedure GrayToFloat(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
3104 DstInfo
: PImageFormatInfo
);
3111 for I
:= 0 to NumPixels
- 1 do
3113 GrayGetSrcPixel(Src
, SrcInfo
, Gray
, Alpha
);
3114 // most significant word of grayscale value is used for
3115 // each channel and alpha channel is set to Alpha
3116 // then all is scaled to 0..1
3117 PixF
.R
:= Gray
.A
* OneDiv16Bit
;
3118 PixF
.G
:= Gray
.A
* OneDiv16Bit
;
3119 PixF
.B
:= Gray
.A
* OneDiv16Bit
;
3120 PixF
.A
:= Alpha
* OneDiv16Bit
;
3122 FloatSetDstPixel(Dst
, DstInfo
, PixF
);
3123 Inc(Src
, SrcInfo
.BytesPerPixel
);
3124 Inc(Dst
, DstInfo
.BytesPerPixel
);
3128 procedure GrayToIndex(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
3129 DstInfo
: PImageFormatInfo
; DstPal
: PPalette32
);
3136 FillGrayscalePalette(DstPal
, DstInfo
.PaletteEntries
);
3137 Shift
:= Log2Int(DstInfo
.PaletteEntries
);
3138 // most common conversion (Gray8->Index8)
3139 // is made separately from general conversions to make it faster
3140 if (SrcInfo
.Format
= ifGray8
) and (DstInfo
.Format
= ifIndex8
) then
3141 for I
:= 0 to NumPixels
- 1 do
3144 Inc(Src
, SrcInfo
.BytesPerPixel
);
3145 Inc(Dst
, DstInfo
.BytesPerPixel
);
3148 for I
:= 0 to NumPixels
- 1 do
3150 // gray value is read from src and index to precomputed
3151 // grayscale palette is computed and written to dst
3152 // (we assume here that there will be no more than 65536 palette
3153 // entries in dst format, gray value is shifted so the highest
3154 // gray value match the highest possible index in palette)
3155 GrayGetSrcPixel(Src
, SrcInfo
, Gray
, Alpha
);
3156 Idx
:= Gray
.A
shr (16 - Shift
);
3157 IndexSetDstPixel(Dst
, DstInfo
, Idx
);
3158 Inc(Src
, SrcInfo
.BytesPerPixel
);
3159 Inc(Dst
, DstInfo
.BytesPerPixel
);
3163 procedure FloatToFloat(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
3164 DstInfo
: PImageFormatInfo
);
3169 for I
:= 0 to NumPixels
- 1 do
3171 // general floating point conversion
3172 FloatGetSrcPixel(Src
, SrcInfo
, PixF
);
3173 FloatSetDstPixel(Dst
, DstInfo
, PixF
);
3174 Inc(Src
, SrcInfo
.BytesPerPixel
);
3175 Inc(Dst
, DstInfo
.BytesPerPixel
);
3179 procedure FloatToChannel(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
3180 DstInfo
: PImageFormatInfo
);
3186 for I
:= 0 to NumPixels
- 1 do
3188 FloatGetSrcPixel(Src
, SrcInfo
, PixF
);
3189 ClampFloatPixel(PixF
);
3191 // floating point channel values are scaled to 1.0
3192 Pix64
.A
:= ClampToWord(Round(PixF
.A
* 65535));
3193 Pix64
.R
:= ClampToWord(Round(PixF
.R
* 65535));
3194 Pix64
.G
:= ClampToWord(Round(PixF
.G
* 65535));
3195 Pix64
.B
:= ClampToWord(Round(PixF
.B
* 65535));
3197 ChannelSetDstPixel(Dst
, DstInfo
, Pix64
);
3198 Inc(Src
, SrcInfo
.BytesPerPixel
);
3199 Inc(Dst
, DstInfo
.BytesPerPixel
);
3203 procedure FloatToGray(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
3204 DstInfo
: PImageFormatInfo
);
3211 for I
:= 0 to NumPixels
- 1 do
3213 FloatGetSrcPixel(Src
, SrcInfo
, PixF
);
3214 ClampFloatPixel(PixF
);
3216 // alpha is saved from source pixel to Alpha,
3217 // Gray value is computed and set to highest word of Pix64 so
3218 // Pix64.Color contains grayscale value scaled to 64 bits
3219 Alpha
:= ClampToWord(Round(PixF
.A
* 65535.0));
3220 Gray
.A
:= ClampToWord(Round((GrayConv
.R
* PixF
.R
+ GrayConv
.G
* PixF
.G
+
3221 GrayConv
.B
* PixF
.B
) * 65535.0));
3223 GraySetDstPixel(Dst
, DstInfo
, Gray
, Alpha
);
3224 Inc(Src
, SrcInfo
.BytesPerPixel
);
3225 Inc(Dst
, DstInfo
.BytesPerPixel
);
3229 procedure FloatToIndex(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
3230 DstInfo
: PImageFormatInfo
; DstPal
: PPalette32
);
3232 ReduceColorsMedianCut(NumPixels
, Src
, Dst
, SrcInfo
, DstInfo
, DstInfo
.PaletteEntries
,
3233 GetOption(ImagingColorReductionMask
), DstPal
);
3236 procedure IndexToIndex(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
3237 DstInfo
: PImageFormatInfo
; SrcPal
, DstPal
: PPalette32
);
3241 // there is only one indexed format now, so it is just a copy
3242 for I
:= 0 to NumPixels
- 1 do
3245 Inc(Src
, SrcInfo
.BytesPerPixel
);
3246 Inc(Dst
, DstInfo
.BytesPerPixel
);
3248 for I
:= 0 to SrcInfo
.PaletteEntries
- 1 do
3249 DstPal
[I
] := SrcPal
[I
];
3252 procedure IndexToChannel(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
3253 DstInfo
: PImageFormatInfo
; SrcPal
: PPalette32
);
3259 // two most common conversions (Index8->R8G8B8 nad Index8->A8R8G8B8)
3260 // are made separately from general conversions to make them faster
3261 if (SrcInfo
.Format
= ifIndex8
) and (DstInfo
.Format
in [ifR8G8B8
, ifA8R8G8B8
]) then
3262 for I
:= 0 to NumPixels
- 1 do
3264 with PColor24Rec(Dst
)^ do
3266 R
:= SrcPal
[Src
^].R
;
3267 G
:= SrcPal
[Src
^].G
;
3268 B
:= SrcPal
[Src
^].B
;
3270 if DstInfo
.Format
= ifA8R8G8B8
then
3271 PColor32Rec(Dst
).A
:= SrcPal
[Src
^].A
;
3272 Inc(Src
, SrcInfo
.BytesPerPixel
);
3273 Inc(Dst
, DstInfo
.BytesPerPixel
);
3276 for I
:= 0 to NumPixels
- 1 do
3278 // index to palette is read from source and color
3279 // is retrieved from palette entry. Color is then
3280 // scaled to 16bits and written to dest
3281 IndexGetSrcPixel(Src
, SrcInfo
, Idx
);
3284 A
:= SrcPal
[Idx
].A
shl 8;
3285 R
:= SrcPal
[Idx
].R
shl 8;
3286 G
:= SrcPal
[Idx
].G
shl 8;
3287 B
:= SrcPal
[Idx
].B
shl 8;
3289 ChannelSetDstPixel(Dst
, DstInfo
, Pix64
);
3290 Inc(Src
, SrcInfo
.BytesPerPixel
);
3291 Inc(Dst
, DstInfo
.BytesPerPixel
);
3295 procedure IndexToGray(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
3296 DstInfo
: PImageFormatInfo
; SrcPal
: PPalette32
);
3303 // most common conversion (Index8->Gray8)
3304 // is made separately from general conversions to make it faster
3305 if (SrcInfo
.Format
= ifIndex8
) and (DstInfo
.Format
= ifGray8
) then
3307 for I
:= 0 to NumPixels
- 1 do
3309 Dst
^ := Round(GrayConv
.R
* SrcPal
[Src
^].R
+ GrayConv
.G
* SrcPal
[Src
^].G
+
3310 GrayConv
.B
* SrcPal
[Src
^].B
);
3311 Inc(Src
, SrcInfo
.BytesPerPixel
);
3312 Inc(Dst
, DstInfo
.BytesPerPixel
);
3316 for I
:= 0 to NumPixels
- 1 do
3318 // index to palette is read from source and color
3319 // is retrieved from palette entry. Color is then
3320 // transformed to grayscale and assigned to the highest
3321 // byte of Gray value
3322 IndexGetSrcPixel(Src
, SrcInfo
, Idx
);
3323 Alpha
:= SrcPal
[Idx
].A
shl 8;
3324 Gray
.A
:= MulDiv(Round(GrayConv
.R
* SrcPal
[Idx
].R
+ GrayConv
.G
* SrcPal
[Idx
].G
+
3325 GrayConv
.B
* SrcPal
[Idx
].B
), 65535, 255);
3326 GraySetDstPixel(Dst
, DstInfo
, Gray
, Alpha
);
3327 Inc(Src
, SrcInfo
.BytesPerPixel
);
3328 Inc(Dst
, DstInfo
.BytesPerPixel
);
3332 procedure IndexToFloat(NumPixels
: LongInt; Src
, Dst
: PByte; SrcInfo
,
3333 DstInfo
: PImageFormatInfo
; SrcPal
: PPalette32
);
3339 for I
:= 0 to NumPixels
- 1 do
3341 // index to palette is read from source and color
3342 // is retrieved from palette entry. Color is then
3343 // scaled to 0..1 and written to dest
3344 IndexGetSrcPixel(Src
, SrcInfo
, Idx
);
3347 A
:= SrcPal
[Idx
].A
* OneDiv8Bit
;
3348 R
:= SrcPal
[Idx
].R
* OneDiv8Bit
;
3349 G
:= SrcPal
[Idx
].G
* OneDiv8Bit
;
3350 B
:= SrcPal
[Idx
].B
* OneDiv8Bit
;
3352 FloatSetDstPixel(Dst
, DstInfo
, PixF
);
3353 Inc(Src
, SrcInfo
.BytesPerPixel
);
3354 Inc(Dst
, DstInfo
.BytesPerPixel
);
3359 { Special formats conversion functions }
3362 // DXT RGB color block
3363 TDXTColorBlock
= packed record
3364 Color0
, Color1
: Word;
3367 PDXTColorBlock
= ^TDXTColorBlock
;
3369 // DXT explicit alpha for a block
3370 TDXTAlphaBlockExp
= packed record
3371 Alphas
: array[0..3] of Word;
3373 PDXTAlphaBlockExp
= ^TDXTAlphaBlockExp
;
3375 // DXT interpolated alpha for a block
3376 TDXTAlphaBlockInt
= packed record
3377 Alphas
: array[0..7] of Byte;
3379 PDXTAlphaBlockInt
= ^TDXTAlphaBlockInt
;
3387 TPixelBlock
= array[0..15] of TPixelInfo
;
3389 function DecodeCol(Color
: Word): TColor32Rec
;
3390 {$IFDEF USE_INLINE} inline; {$ENDIF}
3393 { Result.R := ((Color and $F800) shr 11) shl 3;
3394 Result.G := ((Color and $07E0) shr 5) shl 2;
3395 Result.B := (Color and $001F) shl 3;}
3396 // this color expansion is slower but gives better results
3397 Result
.R
:= (Color
shr 11) * 255 div 31;
3398 Result
.G
:= ((Color
shr 5) and $3F) * 255 div 63;
3399 Result
.B
:= (Color
and $1F) * 255 div 31;
3402 procedure DecodeDXT1(SrcBits
, DestBits
: PByte; Width
, Height
: LongInt);
3404 Sel
, X
, Y
, I
, J
, K
: LongInt;
3405 Block
: TDXTColorBlock
;
3406 Colors
: array[0..3] of TColor32Rec
;
3408 for Y
:= 0 to Height
div 4 - 1 do
3409 for X
:= 0 to Width
div 4 - 1 do
3411 Block
:= PDXTColorBlock(SrcBits
)^;
3412 Inc(SrcBits
, SizeOf(Block
));
3413 // we read and decode endpoint colors
3414 Colors
[0] := DecodeCol(Block
.Color0
);
3415 Colors
[1] := DecodeCol(Block
.Color1
);
3416 // and interpolate between them
3417 if Block
.Color0
> Block
.Color1
then
3419 // interpolation for block without alpha
3421 Colors
[2].R
:= (Colors
[0].R
shl 1 + Colors
[1].R
+ 1) div 3;
3422 Colors
[2].G
:= (Colors
[0].G
shl 1 + Colors
[1].G
+ 1) div 3;
3423 Colors
[2].B
:= (Colors
[0].B
shl 1 + Colors
[1].B
+ 1) div 3;
3425 Colors
[3].R
:= (Colors
[0].R
+ Colors
[1].R
shl 1 + 1) div 3;
3426 Colors
[3].G
:= (Colors
[0].G
+ Colors
[1].G
shl 1 + 1) div 3;
3427 Colors
[3].B
:= (Colors
[0].B
+ Colors
[1].B
shl 1 + 1) div 3;
3431 // interpolation for block with alpha
3433 Colors
[2].R
:= (Colors
[0].R
+ Colors
[1].R
) shr 1;
3434 Colors
[2].G
:= (Colors
[0].G
+ Colors
[1].G
) shr 1;
3435 Colors
[2].B
:= (Colors
[0].B
+ Colors
[1].B
) shr 1;
3437 Colors
[3].R
:= (Colors
[0].R
+ Colors
[1].R
shl 1 + 1) div 3;
3438 Colors
[3].G
:= (Colors
[0].G
+ Colors
[1].G
shl 1 + 1) div 3;
3439 Colors
[3].B
:= (Colors
[0].B
+ Colors
[1].B
shl 1 + 1) div 3;
3442 // we distribute the dxt block colors across the 4x4 block of the
3443 // destination image accroding to the dxt block mask
3448 Sel
:= (Block
.Mask
and (3 shl (K
shl 1))) shr (K
shl 1);
3449 if ((X
shl 2 + I
) < Width
) and ((Y
shl 2 + J
) < Height
) then
3450 PPalette32(DestBits
)[(Y
shl 2 + J
) * Width
+ X
shl 2 + I
] :=
3457 procedure DecodeDXT3(SrcBits
, DestBits
: PByte; Width
, Height
: LongInt);
3459 Sel
, X
, Y
, I
, J
, K
: LongInt;
3460 Block
: TDXTColorBlock
;
3461 AlphaBlock
: TDXTAlphaBlockExp
;
3462 Colors
: array[0..3] of TColor32Rec
;
3465 for Y
:= 0 to Height
div 4 - 1 do
3466 for X
:= 0 to Width
div 4 - 1 do
3468 AlphaBlock
:= PDXTAlphaBlockExp(SrcBits
)^;
3469 Inc(SrcBits
, SizeOf(AlphaBlock
));
3470 Block
:= PDXTColorBlock(SrcBits
)^;
3471 Inc(SrcBits
, SizeOf(Block
));
3472 // we read and decode endpoint colors
3473 Colors
[0] := DecodeCol(Block
.Color0
);
3474 Colors
[1] := DecodeCol(Block
.Color1
);
3475 // and interpolate between them
3476 Colors
[2].R
:= (Colors
[0].R
shl 1 + Colors
[1].R
+ 1) div 3;
3477 Colors
[2].G
:= (Colors
[0].G
shl 1 + Colors
[1].G
+ 1) div 3;
3478 Colors
[2].B
:= (Colors
[0].B
shl 1 + Colors
[1].B
+ 1) div 3;
3479 Colors
[3].R
:= (Colors
[0].R
+ Colors
[1].R
shl 1 + 1) div 3;
3480 Colors
[3].G
:= (Colors
[0].G
+ Colors
[1].G
shl 1 + 1) div 3;
3481 Colors
[3].B
:= (Colors
[0].B
+ Colors
[1].B
shl 1 + 1) div 3;
3483 // we distribute the dxt block colors and alphas
3484 // across the 4x4 block of the destination image
3485 // accroding to the dxt block mask and alpha block
3489 AWord
:= AlphaBlock
.Alphas
[J
];
3492 Sel
:= (Block
.Mask
and (3 shl (K
shl 1))) shr (K
shl 1);
3493 if (X
shl 2 + I
< Width
) and (Y
shl 2 + J
< Height
) then
3495 Colors
[Sel
].A
:= AWord
and $0F;
3496 Colors
[Sel
].A
:= Colors
[Sel
].A
or (Colors
[Sel
].A
shl 4);
3497 PPalette32(DestBits
)[(Y
shl 2 + J
) * Width
+ X
shl 2 + I
] :=
3501 AWord
:= AWord
shr 4;
3507 procedure GetInterpolatedAlphas(var AlphaBlock
: TDXTAlphaBlockInt
);
3510 if Alphas
[0] > Alphas
[1] then
3512 // Interpolation of six alphas
3513 Alphas
[2] := (6 * Alphas
[0] + 1 * Alphas
[1] + 3) div 7;
3514 Alphas
[3] := (5 * Alphas
[0] + 2 * Alphas
[1] + 3) div 7;
3515 Alphas
[4] := (4 * Alphas
[0] + 3 * Alphas
[1] + 3) div 7;
3516 Alphas
[5] := (3 * Alphas
[0] + 4 * Alphas
[1] + 3) div 7;
3517 Alphas
[6] := (2 * Alphas
[0] + 5 * Alphas
[1] + 3) div 7;
3518 Alphas
[7] := (1 * Alphas
[0] + 6 * Alphas
[1] + 3) div 7;
3522 // Interpolation of four alphas, two alphas are set directly
3523 Alphas
[2] := (4 * Alphas
[0] + 1 * Alphas
[1] + 2) div 5;
3524 Alphas
[3] := (3 * Alphas
[0] + 2 * Alphas
[1] + 2) div 5;
3525 Alphas
[4] := (2 * Alphas
[0] + 3 * Alphas
[1] + 2) div 5;
3526 Alphas
[5] := (1 * Alphas
[0] + 4 * Alphas
[1] + 2) div 5;
3532 procedure DecodeDXT5(SrcBits
, DestBits
: PByte; Width
, Height
: LongInt);
3534 Sel
, X
, Y
, I
, J
, K
: LongInt;
3535 Block
: TDXTColorBlock
;
3536 AlphaBlock
: TDXTAlphaBlockInt
;
3537 Colors
: array[0..3] of TColor32Rec
;
3538 AMask
: array[0..1] of LongWord;
3540 for Y
:= 0 to Height
div 4 - 1 do
3541 for X
:= 0 to Width
div 4 - 1 do
3543 AlphaBlock
:= PDXTAlphaBlockInt(SrcBits
)^;
3544 Inc(SrcBits
, SizeOf(AlphaBlock
));
3545 Block
:= PDXTColorBlock(SrcBits
)^;
3546 Inc(SrcBits
, SizeOf(Block
));
3547 // we read and decode endpoint colors
3548 Colors
[0] := DecodeCol(Block
.Color0
);
3549 Colors
[1] := DecodeCol(Block
.Color1
);
3550 // and interpolate between them
3551 Colors
[2].R
:= (Colors
[0].R
shl 1 + Colors
[1].R
+ 1) div 3;
3552 Colors
[2].G
:= (Colors
[0].G
shl 1 + Colors
[1].G
+ 1) div 3;
3553 Colors
[2].B
:= (Colors
[0].B
shl 1 + Colors
[1].B
+ 1) div 3;
3554 Colors
[3].R
:= (Colors
[0].R
+ Colors
[1].R
shl 1 + 1) div 3;
3555 Colors
[3].G
:= (Colors
[0].G
+ Colors
[1].G
shl 1 + 1) div 3;
3556 Colors
[3].B
:= (Colors
[0].B
+ Colors
[1].B
shl 1 + 1) div 3;
3557 // 6 bit alpha mask is copied into two long words for
3559 AMask
[0] := PLongWord(@AlphaBlock
.Alphas
[2])^ and $00FFFFFF;
3560 AMask
[1] := PLongWord(@AlphaBlock
.Alphas
[5])^ and $00FFFFFF;
3561 // alpha interpolation between two endpoint alphas
3562 GetInterpolatedAlphas(AlphaBlock
);
3564 // we distribute the dxt block colors and alphas
3565 // across the 4x4 block of the destination image
3566 // accroding to the dxt block mask and alpha block mask
3571 Sel
:= (Block
.Mask
and (3 shl (K
shl 1))) shr (K
shl 1);
3572 if ((X
shl 2 + I
) < Width
) and ((Y
shl 2 + J
) < Height
) then
3574 Colors
[Sel
].A
:= AlphaBlock
.Alphas
[AMask
[J
shr 1] and 7];
3575 PPalette32(DestBits
)[(Y
shl 2 + J
) * Width
+ (X
shl 2 + I
)] :=
3579 AMask
[J
shr 1] := AMask
[J
shr 1] shr 3;
3584 procedure GetBlock(var Block
: TPixelBlock
; SrcBits
: Pointer; XPos
, YPos
,
3585 Width
, Height
: LongInt);
3591 // 4x4 pixel block is filled with information about every
3592 // pixel in the block: alpha, original color, 565 color
3596 Src
:= @PPalette32(SrcBits
)[(YPos
shl 2 + Y
) * Width
+ XPos
shl 2 + X
];
3597 Block
[I
].Color
:= ((Src
.R
shr 3) shl 11) or ((Src
.G
shr 2) shl 5) or
3599 Block
[I
].Alpha
:= Src
.A
;
3600 Block
[I
].Orig
:= Src
^;
3605 function ColorDistance(const C1
, C2
: TColor32Rec
): LongInt;
3606 {$IFDEF USE_INLINE} inline;{$ENDIF}
3608 Result
:= (C1
.R
- C2
.R
) * (C1
.R
- C2
.R
) +
3609 (C1
.G
- C2
.G
) * (C1
.G
- C2
.G
) + (C1
.B
- C2
.B
) * (C1
.B
- C2
.B
);
3612 procedure GetEndpoints(const Block
: TPixelBlock
; var Ep0
, Ep1
: Word);
3614 I
, J
, Farthest
, Dist
: LongInt;
3615 Colors
: array[0..15] of TColor32Rec
;
3617 // we choose two colors from the pixel block which has the
3618 // largest distance between them
3620 Colors
[I
] := Block
[I
].Orig
;
3623 for J
:= I
+ 1 to 15 do
3625 Dist
:= ColorDistance(Colors
[I
], Colors
[J
]);
3626 if Dist
> Farthest
then
3629 Ep0
:= Block
[I
].Color
;
3630 Ep1
:= Block
[J
].Color
;
3635 procedure GetAlphaEndpoints(const Block
: TPixelBlock
; var Min
, Max
: Byte);
3641 // we choose the lowest and the highest alpha values
3644 if Block
[I
].Alpha
< Min
then
3645 Min
:= Block
[I
].Alpha
;
3646 if Block
[I
].Alpha
> Max
then
3647 Max
:= Block
[I
].Alpha
;
3651 procedure FixEndpoints(var Ep0
, Ep1
: Word; HasAlpha
: Boolean);
3655 // if dxt block has alpha information, Ep0 must be smaller
3656 // than Ep1, if the block has no alpha Ep1 must be smaller
3675 function GetColorMask(Ep0
, Ep1
: Word; NumCols
: LongInt;
3676 const Block
: TPixelBlock
): LongWord;
3678 I
, J
, Closest
, Dist
: LongInt;
3679 Colors
: array[0..3] of TColor32Rec
;
3680 Mask
: array[0..15] of Byte;
3682 FillChar(Mask
, sizeof(Mask
), 0);
3683 // we decode endpoint colors
3684 Colors
[0] := DecodeCol(Ep0
);
3685 Colors
[1] := DecodeCol(Ep1
);
3686 // and interpolate colors between (3 for DXT1 with alpha, 4 for the others)
3689 Colors
[2].R
:= (Colors
[0].R
+ Colors
[1].R
) shr 1;
3690 Colors
[2].G
:= (Colors
[0].G
+ Colors
[1].G
) shr 1;
3691 Colors
[2].B
:= (Colors
[0].B
+ Colors
[1].B
) shr 1;
3692 Colors
[3].R
:= (Colors
[0].R
+ Colors
[1].R
) shr 1;
3693 Colors
[3].G
:= (Colors
[0].G
+ Colors
[1].G
) shr 1;
3694 Colors
[3].B
:= (Colors
[0].B
+ Colors
[1].B
) shr 1;
3698 Colors
[2].R
:= (Colors
[0].R
shl 1 + Colors
[1].R
+ 1) div 3;
3699 Colors
[2].G
:= (Colors
[0].G
shl 1 + Colors
[1].G
+ 1) div 3;
3700 Colors
[2].B
:= (Colors
[0].B
shl 1 + Colors
[1].B
+ 1) div 3;
3701 Colors
[3].R
:= (Colors
[0].R
+ Colors
[1].R
shl 1 + 1) div 3;
3702 Colors
[3].G
:= (Colors
[0].G
+ Colors
[1].G
shl 1 + 1) div 3;
3703 Colors
[3].B
:= (Colors
[0].B
+ Colors
[1].B
shl 1 + 1) div 3;
3708 // this is only for DXT1 with alpha
3709 if (Block
[I
].Alpha
< 128) and (NumCols
= 3) then
3714 // for each of the 16 input pixels the nearest color in the
3715 // 4 dxt colors is found
3717 for J
:= 0 to NumCols
- 1 do
3719 Dist
:= ColorDistance(Block
[I
].Orig
, Colors
[J
]);
3720 if Dist
< Closest
then
3730 Result
:= Result
or (Mask
[I
] shl (I
shl 1));
3733 procedure GetAlphaMask(Ep0
, Ep1
: Byte; var Block
: TPixelBlock
; Mask
: PByteArray
);
3735 Alphas
: array[0..7] of Byte;
3736 M
: array[0..15] of Byte;
3737 I
, J
, Closest
, Dist
: LongInt;
3739 FillChar(M
, sizeof(M
), 0);
3742 // interpolation between two given alpha endpoints
3743 // (I use 6 interpolated values mode)
3744 Alphas
[2] := (6 * Alphas
[0] + 1 * Alphas
[1] + 3) div 7;
3745 Alphas
[3] := (5 * Alphas
[0] + 2 * Alphas
[1] + 3) div 7;
3746 Alphas
[4] := (4 * Alphas
[0] + 3 * Alphas
[1] + 3) div 7;
3747 Alphas
[5] := (3 * Alphas
[0] + 4 * Alphas
[1] + 3) div 7;
3748 Alphas
[6] := (2 * Alphas
[0] + 5 * Alphas
[1] + 3) div 7;
3749 Alphas
[7] := (1 * Alphas
[0] + 6 * Alphas
[1] + 3) div 7;
3751 // the closest interpolated values for each of the input alpha
3758 Dist
:= Abs(Alphas
[J
] - Block
[I
].Alpha
);
3759 if Dist
< Closest
then
3767 Mask
[0] := M
[0] or (M
[1] shl 3) or ((M
[2] and 3) shl 6);
3768 Mask
[1] := ((M
[2] and 4) shr 2) or (M
[3] shl 1) or (M
[4] shl 4) or
3769 ((M
[5] and 1) shl 7);
3770 Mask
[2] := ((M
[5] and 6) shr 1) or (M
[6] shl 2) or (M
[7] shl 5);
3771 Mask
[3] := M
[8] or (M
[9] shl 3) or ((M
[10] and 3) shl 6);
3772 Mask
[4] := ((M
[10] and 4) shr 2) or (M
[11] shl 1) or (M
[12] shl 4) or
3773 ((M
[13] and 1) shl 7);
3774 Mask
[5] := ((M
[13] and 6) shr 1) or (M
[14] shl 2) or (M
[15] shl 5);
3778 procedure EncodeDXT1(SrcBits
: PByte; DestBits
: PByte; Width
, Height
: LongInt);
3782 Block
: TDXTColorBlock
;
3783 Pixels
: TPixelBlock
;
3785 for Y
:= 0 to Height
div 4 - 1 do
3786 for X
:= 0 to Width
div 4 - 1 do
3788 GetBlock(Pixels
, SrcBits
, X
, Y
, Width
, Height
);
3791 if Pixels
[I
].Alpha
< 128 then
3796 GetEndpoints(Pixels
, Block
.Color0
, Block
.Color1
);
3797 FixEndpoints(Block
.Color0
, Block
.Color1
, HasAlpha
);
3799 Block
.Mask
:= GetColorMask(Block
.Color0
, Block
.Color1
, 3, Pixels
)
3801 Block
.Mask
:= GetColorMask(Block
.Color0
, Block
.Color1
, 4, Pixels
);
3802 PDXTColorBlock(DestBits
)^ := Block
;
3803 Inc(DestBits
, SizeOf(Block
));
3807 procedure EncodeDXT3(SrcBits
: Pointer; DestBits
: PByte; Width
, Height
: LongInt);
3810 Block
: TDXTColorBlock
;
3811 AlphaBlock
: TDXTAlphaBlockExp
;
3812 Pixels
: TPixelBlock
;
3814 for Y
:= 0 to Height
div 4 - 1 do
3815 for X
:= 0 to Width
div 4 - 1 do
3817 GetBlock(Pixels
, SrcBits
, X
, Y
, Width
, Height
);
3819 PByteArray(@AlphaBlock
.Alphas
)[I
] :=
3820 (Pixels
[I
shl 1].Alpha
shr 4) or ((Pixels
[I
shl 1 + 1].Alpha
shr 4) shl 4);
3821 GetEndpoints(Pixels
, Block
.Color0
, Block
.Color1
);
3822 FixEndpoints(Block
.Color0
, Block
.Color1
, False);
3823 Block
.Mask
:= GetColorMask(Block
.Color0
, Block
.Color1
, 4, Pixels
);
3824 PDXTAlphaBlockExp(DestBits
)^ := AlphaBlock
;
3825 Inc(DestBits
, SizeOf(AlphaBlock
));
3826 PDXTColorBlock(DestBits
)^ := Block
;
3827 Inc(DestBits
, SizeOf(Block
));
3831 procedure EncodeDXT5(SrcBits
: Pointer; DestBits
: PByte; Width
, Height
: LongInt);
3834 Block
: TDXTColorBlock
;
3835 AlphaBlock
: TDXTAlphaBlockInt
;
3836 Pixels
: TPixelBlock
;
3838 for Y
:= 0 to Height
div 4 - 1 do
3839 for X
:= 0 to Width
div 4 - 1 do
3841 GetBlock(Pixels
, SrcBits
, X
, Y
, Width
, Height
);
3842 GetEndpoints(Pixels
, Block
.Color0
, Block
.Color1
);
3843 FixEndpoints(Block
.Color0
, Block
.Color1
, False);
3844 Block
.Mask
:= GetColorMask(Block
.Color0
, Block
.Color1
, 4, Pixels
);
3845 GetAlphaEndPoints(Pixels
, AlphaBlock
.Alphas
[1], AlphaBlock
.Alphas
[0]);
3846 GetAlphaMask(AlphaBlock
.Alphas
[0], AlphaBlock
.Alphas
[1], Pixels
,
3847 PByteArray(@AlphaBlock
.Alphas
[2]));
3848 PDXTAlphaBlockInt(DestBits
)^ := AlphaBlock
;
3849 Inc(DestBits
, SizeOf(AlphaBlock
));
3850 PDXTColorBlock(DestBits
)^ := Block
;
3851 Inc(DestBits
, SizeOf(Block
));
3856 TBTCBlock
= packed record
3857 MLower
, MUpper
: Byte;
3860 PBTCBlock
= ^TBTCBlock
;
3862 procedure EncodeBTC(SrcBits
: Pointer; DestBits
: PByte; Width
, Height
: Integer);
3864 X
, Y
, I
, J
: Integer;
3866 M
, MLower
, MUpper
, K
: Integer;
3867 Pixels
: array[0..15] of Byte;
3869 for Y
:= 0 to Height
div 4 - 1 do
3870 for X
:= 0 to Width
div 4 - 1 do
3875 FillChar(Block
, SizeOf(Block
), 0);
3878 // Store 4x4 pixels and compute average, lower, and upper intensity levels
3882 Pixels
[K
] := PByteArray(SrcBits
)[(Y
shl 2 + I
) * Width
+ X
shl 2 + J
];
3890 // Now compute upper and lower levels, number of upper pixels,
3891 // and update bit field (1 when pixel is above avg. level M)
3894 if Pixels
[I
] > M
then
3896 Inc(MUpper
, Pixels
[I
]);
3898 Block
.BitField
:= Block
.BitField
or (1 shl I
);
3901 Inc(MLower
, Pixels
[I
]);
3904 // Scale levels and save them to block
3906 Block
.MUpper
:= ClampToByte(MUpper
div K
)
3909 Block
.MLower
:= ClampToByte(MLower
div (16 - K
));
3911 // Finally save block to dest data
3912 PBTCBlock(DestBits
)^ := Block
;
3913 Inc(DestBits
, SizeOf(Block
));
3917 procedure GetOneChannelBlock(var Block
: TPixelBlock
; SrcBits
: Pointer; XPos
, YPos
,
3918 Width
, Height
, BytesPP
, ChannelIdx
: Integer);
3924 // 4x4 pixel block is filled with information about every pixel in the block,
3925 // but only one channel value is stored in Alpha field
3929 Src
:= @PByteArray(SrcBits
)[(YPos
* 4 + Y
) * Width
* BytesPP
+
3930 (XPos
* 4 + X
) * BytesPP
+ ChannelIdx
];
3931 Block
[I
].Alpha
:= Src
^;
3936 procedure EncodeATI1N(SrcBits
: Pointer; DestBits
: PByte; Width
, Height
: Integer);
3939 AlphaBlock
: TDXTAlphaBlockInt
;
3940 Pixels
: TPixelBlock
;
3942 for Y
:= 0 to Height
div 4 - 1 do
3943 for X
:= 0 to Width
div 4 - 1 do
3945 // Encode one channel
3946 GetOneChannelBlock(Pixels
, SrcBits
, X
, Y
, Width
, Height
, 1, 0);
3947 GetAlphaEndPoints(Pixels
, AlphaBlock
.Alphas
[1], AlphaBlock
.Alphas
[0]);
3948 GetAlphaMask(AlphaBlock
.Alphas
[0], AlphaBlock
.Alphas
[1], Pixels
,
3949 PByteArray(@AlphaBlock
.Alphas
[2]));
3950 PDXTAlphaBlockInt(DestBits
)^ := AlphaBlock
;
3951 Inc(DestBits
, SizeOf(AlphaBlock
));
3955 procedure EncodeATI2N(SrcBits
: Pointer; DestBits
: PByte; Width
, Height
: Integer);
3958 AlphaBlock
: TDXTAlphaBlockInt
;
3959 Pixels
: TPixelBlock
;
3961 for Y
:= 0 to Height
div 4 - 1 do
3962 for X
:= 0 to Width
div 4 - 1 do
3964 // Encode Red/X channel
3965 GetOneChannelBlock(Pixels
, SrcBits
, X
, Y
, Width
, Height
, 4, ChannelRed
);
3966 GetAlphaEndPoints(Pixels
, AlphaBlock
.Alphas
[1], AlphaBlock
.Alphas
[0]);
3967 GetAlphaMask(AlphaBlock
.Alphas
[0], AlphaBlock
.Alphas
[1], Pixels
,
3968 PByteArray(@AlphaBlock
.Alphas
[2]));
3969 PDXTAlphaBlockInt(DestBits
)^ := AlphaBlock
;
3970 Inc(DestBits
, SizeOf(AlphaBlock
));
3971 // Encode Green/Y channel
3972 GetOneChannelBlock(Pixels
, SrcBits
, X
, Y
, Width
, Height
, 4, ChannelGreen
);
3973 GetAlphaEndPoints(Pixels
, AlphaBlock
.Alphas
[1], AlphaBlock
.Alphas
[0]);
3974 GetAlphaMask(AlphaBlock
.Alphas
[0], AlphaBlock
.Alphas
[1], Pixels
,
3975 PByteArray(@AlphaBlock
.Alphas
[2]));
3976 PDXTAlphaBlockInt(DestBits
)^ := AlphaBlock
;
3977 Inc(DestBits
, SizeOf(AlphaBlock
));
3981 procedure EncodeBinary(SrcBits
: Pointer; DestBits
: PByte; Width
, Height
: Integer);
3983 Src
: PByte absolute SrcBits
;
3984 Bitmap
: PByteArray
absolute DestBits
;
3985 X
, Y
, WidthBytes
: Integer;
3986 PixelTresholded
, Treshold
: Byte;
3988 Treshold
:= ClampToByte(GetOption(ImagingBinaryTreshold
));
3989 WidthBytes
:= (Width
+ 7) div 8;
3991 for Y
:= 0 to Height
- 1 do
3992 for X
:= 0 to Width
- 1 do
3994 if Src
^ > Treshold
then
3995 PixelTresholded
:= 255
3997 PixelTresholded
:= 0;
3999 Bitmap
[Y
* WidthBytes
+ X
div 8] := Bitmap
[Y
* WidthBytes
+ X
div 8] or // OR current value of byte with following:
4000 (PixelTresholded
and 1) // To make 1 from 255, 0 remains 0
4001 shl (7 - (X
mod 8)); // Put current bit to proper place in byte
4007 procedure DecodeBTC(SrcBits
, DestBits
: PByte; Width
, Height
: Integer);
4009 X
, Y
, I
, J
, K
: Integer;
4013 for Y
:= 0 to Height
div 4 - 1 do
4014 for X
:= 0 to Width
div 4 - 1 do
4016 Block
:= PBTCBlock(SrcBits
)^;
4017 Inc(SrcBits
, SizeOf(Block
));
4020 // Just write MUpper when there is '1' in bit field and MLower
4021 // when there is '0'
4025 Dest
:= @PByteArray(DestBits
)[(Y
shl 2 + I
) * Width
+ X
shl 2 + J
];
4026 if Block
.BitField
and (1 shl K
) <> 0 then
4027 Dest
^ := Block
.MUpper
4029 Dest
^ := Block
.MLower
;
4035 procedure DecodeATI1N(SrcBits
, DestBits
: PByte; Width
, Height
: Integer);
4037 X
, Y
, I
, J
: Integer;
4038 AlphaBlock
: TDXTAlphaBlockInt
;
4039 AMask
: array[0..1] of LongWord;
4041 for Y
:= 0 to Height
div 4 - 1 do
4042 for X
:= 0 to Width
div 4 - 1 do
4044 AlphaBlock
:= PDXTAlphaBlockInt(SrcBits
)^;
4045 Inc(SrcBits
, SizeOf(AlphaBlock
));
4046 // 6 bit alpha mask is copied into two long words for
4048 AMask
[0] := PLongWord(@AlphaBlock
.Alphas
[2])^ and $00FFFFFF;
4049 AMask
[1] := PLongWord(@AlphaBlock
.Alphas
[5])^ and $00FFFFFF;
4050 // alpha interpolation between two endpoint alphas
4051 GetInterpolatedAlphas(AlphaBlock
);
4053 // we distribute the dxt block alphas
4054 // across the 4x4 block of the destination image
4058 PByteArray(DestBits
)[(Y
shl 2 + J
) * Width
+ (X
shl 2 + I
)] :=
4059 AlphaBlock
.Alphas
[AMask
[J
shr 1] and 7];
4060 AMask
[J
shr 1] := AMask
[J
shr 1] shr 3;
4065 procedure DecodeATI2N(SrcBits
, DestBits
: PByte; Width
, Height
: Integer);
4067 X
, Y
, I
, J
: Integer;
4069 AlphaBlock1
, AlphaBlock2
: TDXTAlphaBlockInt
;
4070 AMask1
: array[0..1] of LongWord;
4071 AMask2
: array[0..1] of LongWord;
4073 for Y
:= 0 to Height
div 4 - 1 do
4074 for X
:= 0 to Width
div 4 - 1 do
4076 // Read the first alpha block and get masks
4077 AlphaBlock1
:= PDXTAlphaBlockInt(SrcBits
)^;
4078 Inc(SrcBits
, SizeOf(AlphaBlock1
));
4079 AMask1
[0] := PLongWord(@AlphaBlock1
.Alphas
[2])^ and $00FFFFFF;
4080 AMask1
[1] := PLongWord(@AlphaBlock1
.Alphas
[5])^ and $00FFFFFF;
4081 // Read the secind alpha block and get masks
4082 AlphaBlock2
:= PDXTAlphaBlockInt(SrcBits
)^;
4083 Inc(SrcBits
, SizeOf(AlphaBlock2
));
4084 AMask2
[0] := PLongWord(@AlphaBlock2
.Alphas
[2])^ and $00FFFFFF;
4085 AMask2
[1] := PLongWord(@AlphaBlock2
.Alphas
[5])^ and $00FFFFFF;
4086 // alpha interpolation between two endpoint alphas
4087 GetInterpolatedAlphas(AlphaBlock1
);
4088 GetInterpolatedAlphas(AlphaBlock2
);
4093 // Distribute alpha block values across 4x4 pixel block,
4094 // first alpha block represents Red channel, second is Green.
4098 Color
.R
:= AlphaBlock1
.Alphas
[AMask1
[J
shr 1] and 7];
4099 Color
.G
:= AlphaBlock2
.Alphas
[AMask2
[J
shr 1] and 7];
4100 PColor32RecArray(DestBits
)[(Y
shl 2 + J
) * Width
+ (X
shl 2 + I
)] := Color
;
4101 AMask1
[J
shr 1] := AMask1
[J
shr 1] shr 3;
4102 AMask2
[J
shr 1] := AMask2
[J
shr 1] shr 3;
4107 procedure DecodeBinary(SrcBits
, DestBits
: PByte; Width
, Height
: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF}
4109 Convert1To8(SrcBits
, DestBits
, Width
, Height
, (Width
+ 7) div 8, True);
4112 procedure SpecialToUnSpecial(const SrcImage
: TImageData
; DestBits
: Pointer;
4113 SpecialFormat
: TImageFormat
);
4115 case SpecialFormat
of
4116 ifDXT1
: DecodeDXT1(SrcImage
.Bits
, DestBits
, SrcImage
.Width
, SrcImage
.Height
);
4117 ifDXT3
: DecodeDXT3(SrcImage
.Bits
, DestBits
, SrcImage
.Width
, SrcImage
.Height
);
4118 ifDXT5
: DecodeDXT5(SrcImage
.Bits
, DestBits
, SrcImage
.Width
, SrcImage
.Height
);
4119 ifBTC
: DecodeBTC (SrcImage
.Bits
, DestBits
, SrcImage
.Width
, SrcImage
.Height
);
4120 ifATI1N
: DecodeATI1N(SrcImage
.Bits
, DestBits
, SrcImage
.Width
, SrcImage
.Height
);
4121 ifATI2N
: DecodeATI2N(SrcImage
.Bits
, DestBits
, SrcImage
.Width
, SrcImage
.Height
);
4122 ifBinary
: DecodeBinary(SrcImage
.Bits
, DestBits
, SrcImage
.Width
, SrcImage
.Height
);
4126 procedure UnSpecialToSpecial(SrcBits
: Pointer; const DestImage
: TImageData
;
4127 SpecialFormat
: TImageFormat
);
4129 case SpecialFormat
of
4130 ifDXT1
: EncodeDXT1(SrcBits
, DestImage
.Bits
, DestImage
.Width
, DestImage
.Height
);
4131 ifDXT3
: EncodeDXT3(SrcBits
, DestImage
.Bits
, DestImage
.Width
, DestImage
.Height
);
4132 ifDXT5
: EncodeDXT5(SrcBits
, DestImage
.Bits
, DestImage
.Width
, DestImage
.Height
);
4133 ifBTC
: EncodeBTC (SrcBits
, DestImage
.Bits
, DestImage
.Width
, DestImage
.Height
);
4134 ifATI1N
: EncodeATI1N(SrcBits
, DestImage
.Bits
, DestImage
.Width
, DestImage
.Height
);
4135 ifATI2N
: EncodeATI2N(SrcBits
, DestImage
.Bits
, DestImage
.Width
, DestImage
.Height
);
4136 ifBinary
: EncodeBinary(SrcBits
, DestImage
.Bits
, DestImage
.Width
, DestImage
.Height
);
4140 procedure ConvertSpecial(var Image
: TImageData
;
4141 SrcInfo
, DstInfo
: PImageFormatInfo
);
4143 WorkImage
: TImageData
;
4145 procedure CheckSize(var Img
: TImageData
; Info
: PImageFormatInfo
);
4147 Width
, Height
: Integer;
4150 Height
:= Img
.Height
;
4151 DstInfo
.CheckDimensions(Info
.Format
, Width
, Height
);
4152 ResizeImage(Img
, Width
, Height
, rfNearest
);
4156 if SrcInfo
.IsSpecial
and DstInfo
.IsSpecial
then
4158 // Convert source to nearest 'normal' format
4159 InitImage(WorkImage
);
4160 NewImage(Image
.Width
, Image
.Height
, SrcInfo
.SpecialNearestFormat
, WorkImage
);
4161 SpecialToUnSpecial(Image
, WorkImage
.Bits
, SrcInfo
.Format
);
4163 // Make sure output of SpecialToUnSpecial is the same as input of
4164 // UnSpecialToSpecial
4165 if SrcInfo
.SpecialNearestFormat
<> DstInfo
.SpecialNearestFormat
then
4166 ConvertImage(WorkImage
, DstInfo
.SpecialNearestFormat
);
4167 // Convert work image to dest special format
4168 CheckSize(WorkImage
, DstInfo
);
4169 NewImage(WorkImage
.Width
, WorkImage
.Height
, DstInfo
.Format
, Image
);
4170 UnSpecialToSpecial(WorkImage
.Bits
, Image
, DstInfo
.Format
);
4171 FreeImage(WorkImage
);
4173 else if SrcInfo
.IsSpecial
and not DstInfo
.IsSpecial
then
4175 // Convert source to nearest 'normal' format
4176 InitImage(WorkImage
);
4177 NewImage(Image
.Width
, Image
.Height
, SrcInfo
.SpecialNearestFormat
, WorkImage
);
4178 SpecialToUnSpecial(Image
, WorkImage
.Bits
, SrcInfo
.Format
);
4180 // Now convert to dest format
4181 ConvertImage(WorkImage
, DstInfo
.Format
);
4184 else if not SrcInfo
.IsSpecial
and DstInfo
.IsSpecial
then
4186 // Convert source to nearest format
4188 ConvertImage(WorkImage
, DstInfo
.SpecialNearestFormat
);
4189 // Now convert from nearest to dest
4190 CheckSize(WorkImage
, DstInfo
);
4192 NewImage(WorkImage
.Width
, WorkImage
.Height
, DstInfo
.Format
, Image
);
4193 UnSpecialToSpecial(WorkImage
.Bits
, Image
, DstInfo
.Format
);
4194 FreeImage(WorkImage
);
4198 function GetStdPixelsSize(Format
: TImageFormat
; Width
, Height
: LongInt): LongInt;
4200 if FInfos
[Format
] <> nil then
4201 Result
:= Width
* Height
* FInfos
[Format
].BytesPerPixel
4206 procedure CheckStdDimensions(Format
: TImageFormat
; var Width
, Height
: LongInt);
4210 function GetDXTPixelsSize(Format
: TImageFormat
; Width
, Height
: LongInt): LongInt;
4212 // DXT can be used only for images with dimensions that are
4213 // multiples of four
4214 CheckDXTDimensions(Format
, Width
, Height
);
4215 Result
:= Width
* Height
;
4216 if Format
in [ifDXT1
, ifATI1N
] then
4217 Result
:= Result
div 2;
4220 procedure CheckDXTDimensions(Format
: TImageFormat
; var Width
, Height
: LongInt);
4222 // DXT image dimensions must be multiples of four
4223 Width
:= (Width
+ 3) and not 3; // div 4 * 4;
4224 Height
:= (Height
+ 3) and not 3; // div 4 * 4;
4227 function GetBTCPixelsSize(Format
: TImageFormat
; Width
, Height
: LongInt): LongInt;
4229 // BTC can be used only for images with dimensions that are
4230 // multiples of four
4231 CheckDXTDimensions(Format
, Width
, Height
);
4232 Result
:= Width
* Height
div 4; // 2bits/pixel
4235 function GetBCPixelsSize(Format
: TImageFormat
; Width
, Height
: LongInt): LongInt;
4238 raise ENotImplemented
.Create();
4241 procedure CheckBCDimensions(Format
: TImageFormat
; var Width
, Height
: LongInt);
4243 raise ENotImplemented
.Create();
4246 function GetBinaryPixelsSize(Format
: TImageFormat
; Width
, Height
: LongInt): LongInt;
4248 // Binary images are aligned on BYTE boundary
4249 Result
:= ((Width
+ 7) div 8) * Height
; // 1bit/pixel
4252 { Optimized pixel readers/writers for 32bit and FP colors to be stored in TImageFormatInfo }
4254 function GetPixel32ifA8R8G8B8(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
): TColor32Rec
;
4256 Result
.Color
:= PLongWord(Bits
)^;
4259 procedure SetPixel32ifA8R8G8B8(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
; const Color
: TColor32Rec
);
4261 PLongWord(Bits
)^ := Color
.Color
;
4264 function GetPixelFPifA8R8G8B8(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
): TColorFPRec
;
4266 Result
.A
:= PColor32Rec(Bits
).A
* OneDiv8Bit
;
4267 Result
.R
:= PColor32Rec(Bits
).R
* OneDiv8Bit
;
4268 Result
.G
:= PColor32Rec(Bits
).G
* OneDiv8Bit
;
4269 Result
.B
:= PColor32Rec(Bits
).B
* OneDiv8Bit
;
4272 procedure SetPixelFPifA8R8G8B8(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
; const Color
: TColorFPRec
);
4274 PColor32Rec(Bits
).A
:= ClampToByte(Round(Color
.A
* 255.0));
4275 PColor32Rec(Bits
).R
:= ClampToByte(Round(Color
.R
* 255.0));
4276 PColor32Rec(Bits
).G
:= ClampToByte(Round(Color
.G
* 255.0));
4277 PColor32Rec(Bits
).B
:= ClampToByte(Round(Color
.B
* 255.0));
4280 function GetPixel32Channel8Bit(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
): TColor32Rec
;
4287 ifR8G8B8
, ifX8R8G8B8
:
4290 PColor24Rec(@Result
)^ := PColor24Rec(Bits
)^;
4294 if Info
.HasAlphaChannel
then
4295 Result
.A
:= PWordRec(Bits
).High
4298 Result
.R
:= PWordRec(Bits
).Low
;
4299 Result
.G
:= PWordRec(Bits
).Low
;
4300 Result
.B
:= PWordRec(Bits
).Low
;
4305 procedure SetPixel32Channel8Bit(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
; const Color
: TColor32Rec
);
4308 ifR8G8B8
, ifX8R8G8B8
:
4310 PColor24Rec(Bits
)^ := PColor24Rec(@Color
)^;
4314 if Info
.HasAlphaChannel
then
4315 PWordRec(Bits
).High
:= Color
.A
;
4316 PWordRec(Bits
).Low
:= Round(GrayConv
.R
* Color
.R
+ GrayConv
.G
* Color
.G
+
4317 GrayConv
.B
* Color
.B
);
4322 function GetPixelFPChannel8Bit(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
): TColorFPRec
;
4329 ifR8G8B8
, ifX8R8G8B8
:
4332 Result
.R
:= PColor24Rec(Bits
).R
* OneDiv8Bit
;
4333 Result
.G
:= PColor24Rec(Bits
).G
* OneDiv8Bit
;
4334 Result
.B
:= PColor24Rec(Bits
).B
* OneDiv8Bit
;
4338 if Info
.HasAlphaChannel
then
4339 Result
.A
:= PWordRec(Bits
).High
* OneDiv8Bit
4342 Result
.R
:= PWordRec(Bits
).Low
* OneDiv8Bit
;
4343 Result
.G
:= PWordRec(Bits
).Low
* OneDiv8Bit
;
4344 Result
.B
:= PWordRec(Bits
).Low
* OneDiv8Bit
;
4349 procedure SetPixelFPChannel8Bit(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
; const Color
: TColorFPRec
);
4352 ifR8G8B8
, ifX8R8G8B8
:
4354 PColor24Rec(Bits
).R
:= ClampToByte(Round(Color
.R
* 255.0));
4355 PColor24Rec(Bits
).G
:= ClampToByte(Round(Color
.G
* 255.0));
4356 PColor24Rec(Bits
).B
:= ClampToByte(Round(Color
.B
* 255.0));
4360 if Info
.HasAlphaChannel
then
4361 PWordRec(Bits
).High
:= ClampToByte(Round(Color
.A
* 255.0));
4362 PWordRec(Bits
).Low
:= ClampToByte(Round((GrayConv
.R
* Color
.R
+ GrayConv
.G
* Color
.G
+
4363 GrayConv
.B
* Color
.B
) * 255.0));
4368 function GetPixelFPFloat32(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
): TColorFPRec
;
4371 ifA32R32G32B32F
, ifA32B32G32R32F
:
4373 Result
:= PColorFPRec(Bits
)^;
4375 ifR32G32B32F
, ifB32G32R32F
:
4378 Result
.Color96Rec
:= PColor96FPRec(Bits
)^;
4383 Result
.R
:= PSingle(Bits
)^;
4388 if Info
.IsRBSwapped
then
4389 SwapValues(Result
.R
, Result
.B
);
4392 procedure SetPixelFPFloat32(Bits
: Pointer; Info
: PImageFormatInfo
; Palette
: PPalette32
; const Color
: TColorFPRec
);
4395 ifA32R32G32B32F
, ifA32B32G32R32F
:
4397 PColorFPRec(Bits
)^ := Color
;
4399 ifR32G32B32F
, ifB32G32R32F
:
4401 PColor96FPRec(Bits
)^ := Color
.Color96Rec
;
4405 PSingle(Bits
)^ := Color
.R
;
4408 if Info
.IsRBSwapped
then
4409 SwapValues(PColor96FPRec(Bits
).R
, PColor96FPRec(Bits
).B
);
4413 // Initialize default sampling filter function pointers and radii
4414 SamplingFilterFunctions
[sfNearest
] := FilterNearest
;
4415 SamplingFilterFunctions
[sfLinear
] := FilterLinear
;
4416 SamplingFilterFunctions
[sfCosine
] := FilterCosine
;
4417 SamplingFilterFunctions
[sfHermite
] := FilterHermite
;
4418 SamplingFilterFunctions
[sfQuadratic
] := FilterQuadratic
;
4419 SamplingFilterFunctions
[sfGaussian
] := FilterGaussian
;
4420 SamplingFilterFunctions
[sfSpline
] := FilterSpline
;
4421 SamplingFilterFunctions
[sfLanczos
] := FilterLanczos
;
4422 SamplingFilterFunctions
[sfMitchell
] := FilterMitchell
;
4423 SamplingFilterFunctions
[sfCatmullRom
] := FilterCatmullRom
;
4424 SamplingFilterRadii
[sfNearest
] := 1.0;
4425 SamplingFilterRadii
[sfLinear
] := 1.0;
4426 SamplingFilterRadii
[sfCosine
] := 1.0;
4427 SamplingFilterRadii
[sfHermite
] := 1.0;
4428 SamplingFilterRadii
[sfQuadratic
] := 1.5;
4429 SamplingFilterRadii
[sfGaussian
] := 1.25;
4430 SamplingFilterRadii
[sfSpline
] := 2.0;
4431 SamplingFilterRadii
[sfLanczos
] := 3.0;
4432 SamplingFilterRadii
[sfMitchell
] := 2.0;
4433 SamplingFilterRadii
[sfCatmullRom
] := 2.0;
4438 -- TODOS ----------------------------------------------------
4441 -- 0.77 Changes/Bug Fixes -------------------------------------
4442 - NOT YET: Added support for Passtrough image data formats.
4443 - Added ConvertToPixel32 helper function.
4445 -- 0.26.5 Changes/Bug Fixes -----------------------------------
4446 - Removed optimized codepatch for few data formats from StretchResample
4447 function. It was quite buggy and not so much faster anyway.
4448 - Added PaletteHasAlpha function.
4449 - Added support functions for ifBinary data format.
4450 - Added optional pixel scaling to Convert1To8, Convert2To8,
4451 abd Convert4To8 functions.
4453 -- 0.26.3 Changes/Bug Fixes -----------------------------------
4454 - Filtered resampling ~10% faster now.
4455 - Fixed DXT3 alpha encoding.
4456 - ifIndex8 format now has HasAlphaChannel=True.
4458 -- 0.25.0 Changes/Bug Fixes -----------------------------------
4459 - Made some resampling stuff public so that it can be used in canvas class.
4460 - Added some color constructors.
4461 - Added VisualizePalette helper function.
4462 - Fixed ConvertSpecial, not very readable before and error when
4463 converting special->special.
4465 -- 0.24.3 Changes/Bug Fixes -----------------------------------
4466 - Some refactorings a changes to DXT based formats.
4467 - Added ifATI1N and ifATI2N image data formats support structures and functions.
4469 -- 0.23 Changes/Bug Fixes -----------------------------------
4470 - Added ifBTC image format support structures and functions.
4472 -- 0.21 Changes/Bug Fixes -----------------------------------
4473 - FillMipMapLevel now works well with indexed and special formats too.
4474 - Moved Convert1To8 and Convert4To8 functions from ImagingBitmaps here
4475 and created new Convert2To8 function. They are now used by more than one
4478 -- 0.19 Changes/Bug Fixes -----------------------------------
4479 - StretchResample now uses pixel get/set functions stored in
4480 TImageFormatInfo so it is much faster for formats that override
4481 them with optimized ones
4482 - added pixel set/get functions optimized for various image formats
4483 (to be stored in TImageFormatInfo)
4484 - bug in ConvertSpecial caused problems when converting DXTC images
4485 to bitmaps in ImagingCoponents
4486 - bug in StretchRect caused that it didn't work with ifR32F and
4488 - removed leftover code in FillMipMapLevel which disabled
4489 filtered resizing of images witch ChannelSize <> 8bits
4490 - added half float converting functions and support for half based
4491 image formats where needed
4492 - added TranslatePixel and IsImageFormatValid functions
4493 - fixed possible range overflows when converting from FP to integer images
4494 - added pixel set/get functions: GetPixel32Generic, GetPixelFPGeneric,
4495 SetPixel32Generic, SetPixelFPGeneric
4496 - fixed occasional range overflows in StretchResample
4498 -- 0.17 Changes/Bug Fixes -----------------------------------
4499 - added StretchNearest, StretchResample and some sampling functions
4500 - added ChannelCount values to TImageFormatInfo constants
4501 - added resolution validity check to GetDXTPixelsSize
4503 -- 0.15 Changes/Bug Fixes -----------------------------------
4504 - added RBSwapFormat values to some TImageFromatInfo definitions
4505 - fixed bug in ConvertSpecial (causing DXT images to convert only to 32bit)
4506 - added CopyPixel, ComparePixels helper functions
4508 -- 0.13 Changes/Bug Fixes -----------------------------------
4509 - replaced pixel format conversions for colors not to be
4510 darkened when converting from low bit counts
4511 - ReduceColorsMedianCut was updated to support creating one
4512 optimal palette for more images and it is somewhat faster
4514 - there was ugly bug in DXTC dimensions checking