1 {
2 Vampyre Imaging Library
3 by Marek Mauder
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
26 }
28 { This unit contains utility functions and types for Imaging library.}
31 {$I ImagingOptions.inc}
33 interface
35 uses
38 const
42 type
76 { Array variants - Index 0 means lowest significant byte (word, ...).}
88 { Array variants - Index 0 means lowest significant byte (word, ...).}
116 public
120 { Options for BuildFileList function:
121 flFullNames - file names in result will have full path names
122 (ExtractFileDir(Path) + FileName)
123 flRelNames - file names in result will have names relative to
124 ExtractFileDir(Path) dir
125 flRecursive - adds files in subdirectories found in Path.}
130 { Frees class instance and sets its reference to nil.}
132 { Frees pointer and sets it to nil.}
134 { Replacement of standard System.FreeMem procedure which checks if P is nil
135 (this is only needed for Free Pascal, Delphi makes checks in its FreeMem).}
137 { Returns current exception object. Do not call outside exception handler.}
139 { Returns time value with microsecond resolution.}
141 { Returns time value with milisecond resolution.}
144 { Returns file extension (without "." dot)}
146 { Returns file name of application's executable.}
148 { Returns directory where application's exceutable is located without
149 path delimiter at the end.}
151 { Works like SysUtils.ExtractFileName but supports '/' and '\' dir delimiters
152 at the same time (whereas ExtractFileName supports on default delimiter on current platform).}
154 { Works like SysUtils.ExtractFileDir but supports '/' and '\' dir delimiters
155 at the same time (whereas ExtractFileDir supports on default delimiter on current platform).}
157 { Returns True if Subject matches given Mask with optional case sensitivity.
158 Mask can contain ? and * special characters: ? matches
159 one character, * matches zero or more characters.}
161 { This function fills Files string list with names of files found
162 with FindFirst/FindNext functions (See details on Path/Atrr here).
163 - BuildFileList('c:\*.*', faAnyFile, List, [flRecursive]) returns
164 list of all files (only name.ext - no path) on C drive
165 - BuildFileList('d:\*.*', faDirectory, List, [flFullNames]) returns
166 list of all directories (d:\dirxxx) in root of D drive.}
169 { Similar to RTL's Pos function but with optional Offset where search will start.
170 This function is in the RTL StrUtils unit but }
172 { Same as PosEx but without case sensitivity.}
173 function PosNoCase(const SubStr, S: string; Offset: LongInt = 1): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
174 { Returns a sub-string from S which is followed by
175 Sep separator and deletes the sub-string from S including the separator.}
177 { Same as StrToken but searches from the end of S string.}
179 { Fills instance of TStrings with tokens from string S where tokens are separated by
180 one of Seps characters.}
182 { Returns string representation of integer number (with digit grouping).
183 Uses current locale.}
185 { Returns string representation of float number (with digit grouping).
186 Uses current locale.}
187 function FloatToStrFmt(const F: Double; Precision: Integer = 2): string; {$IFDEF USE_INLINE}inline;{$ENDIF}
188 { Returns format settings for parsing floats (dot as decimal separator).
189 Useful when fomatting/parsing floats etc.}
191 { Returns True if S contains at least one of the substrings in SubStrs array. Case sensitive.}
193 { Extracts substring starting at IdxStart ending at IdxEnd.
194 S[IdxEnd] is not included in the result.}
195 function SubString(const S: string; IdxStart, IdxEnd: Integer): string; {$IFDEF USE_INLINE}inline;{$ENDIF}
197 { Clamps integer value to range <Min, Max>}
198 function ClampInt(Number: LongInt; Min, Max: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
199 { Clamps float value to range <Min, Max>}
200 function ClampFloat(Number: Single; Min, Max: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF}
201 { Clamps integer value to Byte boundaries.}
203 { Clamps integer value to Word boundaries.}
205 { Returns True if Num is power of 2.}
207 { Returns next power of 2 greater than or equal to Num
208 (if Num itself is power of 2 then it retuns Num).}
210 { Raises 2 to the given integer power (in range [0, 30]).}
212 { Raises Base to any power.}
214 { Returns log base 2 of integer X (max 2^30) or -1 if X is not power of 2.}
216 { Returns log base 2 of X.}
218 { Returns log base 10 of X.}
220 { Returns largest integer <= Val (for 5.9 returns 5).}
222 { Returns smallest integer >= Val (for 5.1 returns 6).}
224 { Returns lesser of two integer numbers.}
226 { Returns lesser of two float numbers.}
228 { Returns greater of two integer numbers.}
230 { Returns greater of two float numbers.}
232 { Returns result from multiplying Number by Numerator and then dividing by Denominator.
233 Denominator must be greater than 0.}
236 { Switches Boolean value.}
238 { If Condition is True then TruePart is retured, otherwise
239 FalsePart is returned.}
240 function Iff(Condition: Boolean; TruePart, FalsePart: LongInt): LongInt; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
241 { If Condition is True then TruePart is retured, otherwise
242 FalsePart is returned.}
243 function IffUnsigned(Condition: Boolean; TruePart, FalsePart: LongWord): LongWord; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
244 { If Condition is True then TruePart is retured, otherwise
245 FalsePart is returned.}
246 function Iff(Condition, TruePart, FalsePart: Boolean): Boolean; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
247 { If Condition is True then TruePart is retured, otherwise
248 FalsePart is returned.}
249 function Iff(Condition: Boolean; const TruePart, FalsePart: string): string; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
250 { If Condition is True then TruePart is retured, otherwise
251 FalsePart is returned.}
252 function Iff(Condition: Boolean; TruePart, FalsePart: Char): Char; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
253 { If Condition is True then TruePart is retured, otherwise
254 FalsePart is returned.}
255 function Iff(Condition: Boolean; TruePart, FalsePart: Pointer): Pointer; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
256 { If Condition is True then TruePart is retured, otherwise
257 FalsePart is returned.}
258 function Iff(Condition: Boolean; const TruePart, FalsePart: Int64): Int64; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
259 { If Condition is True then TruePart is retured, otherwise
260 FalsePart is returned.}
261 function IffFloat(Condition: Boolean; TruePart, FalsePart: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF}
262 { Swaps two Boolean values}
264 { Swaps two Byte values}
266 { Swaps two Word values}
268 { Swaps two LongInt values}
270 { Swaps two Single values}
272 { Swaps two LongInt values if necessary to ensure that Min <= Max.}
274 { This function returns True if running on little endian machine.}
276 { Swaps byte order of Word value.}
278 { Swaps byte order of multiple Word values.}
280 { Swaps byte order of LongWord value.}
281 function SwapEndianLongWord(Value: LongWord): LongWord; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
282 { Swaps byte order of multiple LongWord values.}
285 { Calculates CRC32 for the given data.}
287 { Fills given memory with given Byte value. Size is size of buffer in bytes.}
289 { Fills given memory with given Word value. Size is size of buffer in bytes.}
291 { Fills given memory with given LongWord value. Size is size of buffer in bytes.}
293 { Fills given memory zeroes.}
297 { Returns how many mipmap levels can be created for image of given size.}
299 { Returns total number of levels of volume texture with given depth and
300 mipmap count (this is not depth * mipmaps!).}
302 { Returns rectangle (X, Y, X + Width, Y + Height).}
303 function BoundsToRect(X, Y, Width, Height: LongInt): TRect; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
304 { Returns rectangle (R.Left, R.Top, R.Left + R.Right, R.Top + R.Bottom).}
306 { Returns rectangle (R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top).}
308 { Clips given bounds to Clip rectangle.}
310 { Clips given source bounds and dest position. It is used by various CopyRect
311 functions that copy rect from one image to another. It handles clipping the same way
312 as Win32 BitBlt function. }
315 { Clips given source bounds and dest bounds. It is used by various StretchRect
316 functions that stretch rectangle of pixels from one image to another.
317 It handles clipping the same way as Win32 StretchBlt function. }
320 { Scales one rectangle to fit into another. Proportions are preserved so
321 it could be used for 'Stretch To Fit Window' image drawing for instance.}
323 { Scales given size to fit into max size while keeping the original ascpect ration.
324 Useful for calculating thumbnail dimensions etc.}
326 { Returns width of given rect. Part of RTL in newer Delphi.}
328 { Returns height of given rect. Part of RTL in newer Delphi.}
330 { Returns True if R1 fits into R2.}
332 { Returns True if R1 and R2 intersects.}
335 { Converts pixel size in micrometers to corrensponding DPI.}
337 { Converts DPI to corrensponding pixel size in micrometers.}
344 { Formats given message for usage in Exception.Create(..). Use only
345 in except block - returned message contains message of last raised exception.}
347 { Outputs debug message - shows message dialog in Windows and writes to console
348 in Linux/Unix.}
351 implementation
353 uses
354 {$IF Defined(MSWINDOWS)}
355 Windows;
356 {$ELSEIF Defined(FPC)}
358 {$ELSEIF Defined(DELPHI)}
360 {$IFEND}
362 var
366 begin
371 var
373 begin
380 begin
386 begin
392 begin
396 {$IF Defined(MSWINDOWS)}
397 var
402 var
404 begin
408 {$ELSEIF Defined(DELPHI)}
410 var
412 begin
416 {$ELSEIF Defined(FPC)}
418 var
420 begin
424 {$IFEND}
427 begin
432 begin
439 {$IF Defined(MSWINDOWS)}
440 var
442 begin
446 var
448 begin
451 {$ELSE}
452 begin
454 {$IFEND}
458 begin
463 var
465 begin
471 const
473 var
475 begin
484 var
488 begin
491 else
496 begin
498 begin
501 begin
506 begin
510 begin
512 Exit;
514 repeat
516 begin
518 Exit;
523 Exit;
525 else
527 begin
529 Exit;
530 end
531 else
532 begin
542 begin
544 Exit;
550 begin
554 begin
556 Exit;
563 var
572 var
575 begin
579 begin
580 // Searching for subfolders
582 try
584 begin
590 finally
599 var
603 begin
608 try
610 begin
612 begin
615 else
620 finally
625 begin
631 {$IFDEF DCC}
632 {$WARN SYMBOL_PLATFORM OFF}
633 {$ENDIF}
636 else
638 {$IFDEF DCC}
639 {$WARN SYMBOL_PLATFORM ON}
640 {$ENDIF}
641 // Here's the recursive search for nested folders
643 BuildFolderList;
647 else
654 var
657 begin
662 begin
664 begin
669 begin
671 Exit;
680 begin
685 var
687 begin
690 begin
693 end
694 else
695 begin
702 var
704 begin
708 begin
713 begin
716 end
717 else
718 begin
725 var
727 begin
731 begin
738 begin
743 begin
748 begin
753 var
755 begin
758 begin
761 Exit;
766 begin
771 begin
774 Result := Min
780 begin
783 Result := Min
789 begin
798 begin
807 begin
812 begin
819 begin
824 begin
829 else
834 begin
867 else
873 {$IFDEF USE_ASM}
874 asm
875 FLD1
876 FLD X
877 FYL2X
878 FWAIT
879 end;
880 {$ELSE}
881 const
883 begin
886 {$ENDIF}
889 {$IFDEF USE_ASM}
890 asm
891 FLDLG2
892 FLD X
893 FYL2X
894 FWAIT
895 end;
896 {$ELSE}
897 const
899 begin
902 {$ENDIF}
905 begin
912 begin
919 begin
924 begin
926 Result := TruePart
927 else
932 begin
934 Result := TruePart
935 else
940 begin
942 Result := TruePart
943 else
948 begin
950 Result := TruePart
951 else
956 begin
958 Result := TruePart
959 else
964 begin
966 Result := TruePart
967 else
972 begin
974 Result := TruePart
975 else
980 begin
982 Result := TruePart
983 else
988 var
990 begin
997 var
999 begin
1006 var
1008 begin
1015 var
1017 begin
1024 var
1026 begin
1033 var
1035 begin
1037 begin
1045 begin
1047 Result := A
1048 else
1053 begin
1055 Result := A
1056 else
1061 begin
1063 Result := A
1064 else
1069 begin
1071 Result := A
1072 else
1077 {$IF Defined(USE_ASM) and (not Defined(USE_INLINE))}
1078 asm
1081 end;
1082 {$ELSE}
1083 begin
1086 {$IFEND}
1089 var
1091 begin
1096 (* Vampimp wrongly use swaps for converting big-endian to little-endian anywhere *)
1097 {$IF DEFINED(FPC_LITTLE_ENDIAN)}
1099 {$IF Defined(USE_ASM) and (not Defined(USE_INLINE))}
1100 asm
1102 end;
1103 {$ELSE}
1104 begin
1108 {$IFEND}
1111 {$IFDEF USE_ASM}
1112 asm
1113 @Loop:
1120 end;
1121 {$ELSE}
1122 var
1125 begin
1127 begin
1133 {$ENDIF}
1136 {$IF Defined(USE_ASM) and (not Defined(USE_INLINE))}
1137 asm
1139 end;
1140 {$ELSE}
1141 begin
1147 {$IFEND}
1150 {$IFDEF USE_ASM}
1151 asm
1152 @Loop:
1159 end;
1160 {$ELSE}
1161 var
1164 begin
1166 begin
1174 {$ENDIF}
1175 {$ELSEIF DEFINED(FPC_BIG_ENDIAN)}
1177 begin
1178 Result := Value
1182 begin
1186 begin
1187 Result := Value
1191 begin
1193 {$ELSE}
1194 {$ERROR Unsupported endianness!}
1195 {$ENDIF}
1197 type
1199 var
1203 const
1205 var
1208 begin
1210 begin
1213 begin
1216 else
1224 var
1227 begin
1230 begin
1233 end
1237 {$IFDEF USE_ASM}
1238 asm
1249 REP STOSD
1252 REP STOSB
1254 @Exit:
1255 end;
1256 {$ELSE}
1257 begin
1260 {$ENDIF}
1263 {$IFDEF USE_ASM}
1264 asm
1276 REP STOSD
1277 @Word:
1283 @Byte:
1288 @Exit:
1291 end;
1292 {$ELSE}
1293 var
1295 begin
1303 begin
1309 {$ENDIF}
1312 {$IFDEF USE_ASM}
1313 asm
1322 REP STOSD
1323 @Word:
1329 @Byte:
1334 @Exit:
1337 end;
1338 {$ELSE}
1339 var
1341 begin
1348 begin
1354 {$ENDIF}
1357 begin
1362 begin
1365 begin
1368 begin
1379 var
1381 begin
1388 begin
1396 begin
1404 begin
1414 begin
1416 begin
1423 begin
1428 procedure ClipCopyBounds(var SrcX, SrcY, Width, Height, DstX, DstY: LongInt; SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect);
1432 var
1435 begin
1438 begin
1445 begin
1454 begin
1464 var
1468 begin
1471 begin
1479 begin
1486 begin
1492 begin
1499 begin
1505 var
1512 begin
1519 begin
1523 end
1524 else
1525 begin
1527 Result := BoundsToRect(TargetRect.Left, TargetRect.Top + ((TargetHeight - ScaledHeight) div 2),
1533 var
1535 begin
1544 begin
1549 begin
1554 begin
1555 Result:=
1563 begin
1564 Result :=
1572 begin
1577 begin
1582 begin
1584 begin
1593 begin
1598 begin
1603 begin
1608 var
1610 begin
1612 {$IFDEF MSWINDOWS}
1615 else
1617 {$ENDIF}
1618 {$IFDEF UNIX}
1620 {$ENDIF}
1621 {$IFDEF MSDOS}
1623 {$ENDIF}
1626 initialization
1627 InitCrcTable;
1628 {$IFDEF MSWINDOWS}
1631 {$ENDIF}
1633 {$IF Defined(DELPHI)}
1634 {$IF CompilerVersion >= 23}
1636 {$ELSE}
1638 {$IFEND}
1639 {$ELSE FPC}
1642 {$IFEND}
1644 {
1645 File Notes:
1647 -- TODOS ----------------------------------------------------
1648 - nothing now
1650 -- 0.77.1 ----------------------------------------------------
1651 - Added GetFileName, GetFileDir, RectWidth, RectHeight function.
1652 - Added ScaleSizeToFit function.
1653 - Added ZeroMemory and SwapValues for Booleans.
1654 - Added Substring function.
1655 - Renamed MatchFileNameMask to StrMaskMatch (it's for general use not
1656 just filenames).
1657 - Delphi XE2 new targets (Win64, OSX32) compatibility changes.
1658 - Added GetFormatSettingsForFloats function.
1660 -- 0.26.5 Changes/Bug Fixes -----------------------------------
1661 - Added Log10 function.
1662 - Added TFloatRect type and helper functions FloatRect, FloatRectWidth,
1663 FloatRectHeight.
1664 - Added string function ContainsAnySubStr.
1665 - Added functions PixelSizeToDpi, DpiToPixelSize.
1667 -- 0.26.1 Changes/Bug Fixes -----------------------------------
1668 - Some formatting changes.
1669 - Changed some string functions to work with localized strings.
1670 - ASM version of PosEx had bugs, removed it.
1671 - Added StrTokensToList function.
1673 -- 0.25.0 Changes/Bug Fixes -----------------------------------
1674 - Fixed error in ClipCopyBounds which was causing ... bad clipping!
1676 -- 0.24.3 Changes/Bug Fixes -----------------------------------
1677 - Added GetTimeMilliseconds function.
1678 - Added IntToStrFmt and FloatToStrFmt helper functions.
1680 -- 0.23 Changes/Bug Fixes -----------------------------------
1681 - Added RectInRect and RectIntersects functions
1682 - Added some string utils: StrToken, StrTokenEnd, PosEx, PosNoCase.
1683 - Moved BuildFileList here from DemoUtils.
1685 -- 0.21 Changes/Bug Fixes -----------------------------------
1686 - Moved GetVolumeLevelCount from ImagingDds here.
1687 - Renamed FillMemory to FillMemoryByte to avoid name collision in C++ Builder.
1688 - Added Iff function for Char, Pointer, and Int64 types.
1689 - Added IsLittleEndian function.
1690 - Added array types for TWordRec, TLongWordRec, and TInt64Rec.
1691 - Added MatchFileNameMask function.
1693 -- 0.19 Changes/Bug Fixes -----------------------------------
1694 - added ScaleRectToRect (thanks to Paul Michell)
1695 - added BoundsToRect, ClipBounds, ClipCopyBounds, ClipStretchBounds functions
1696 - added MulDiv function
1697 - FreeAndNil is not inline anymore - caused AV in one program
1699 -- 0.17 Changes/Bug Fixes -----------------------------------
1701 - GetAppExe didn't return absolute path in FreeBSD, fixed
1702 - added debug message output
1703 - fixed Unix compatibility issues (thanks to Ales Katona).
1704 Imaging now compiles in FreeBSD and maybe in other Unixes as well.
1706 -- 0.15 Changes/Bug Fixes -----------------------------------
1707 - added some new utility functions
1709 -- 0.13 Changes/Bug Fixes -----------------------------------
1710 - added many new utility functions
1711 - minor change in SwapEndian to avoid range check error
1713 }