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
1097 {$IF Defined(USE_ASM) and (not Defined(USE_INLINE))}
1098 asm
1100 end;
1101 {$ELSE}
1102 begin
1106 {$IFEND}
1109 {$IFDEF USE_ASM}
1110 asm
1111 @Loop:
1118 end;
1119 {$ELSE}
1120 var
1123 begin
1125 begin
1131 {$ENDIF}
1134 {$IF Defined(USE_ASM) and (not Defined(USE_INLINE))}
1135 asm
1137 end;
1138 {$ELSE}
1139 begin
1145 {$IFEND}
1148 {$IFDEF USE_ASM}
1149 asm
1150 @Loop:
1157 end;
1158 {$ELSE}
1159 var
1162 begin
1164 begin
1172 {$ENDIF}
1174 type
1176 var
1180 const
1182 var
1185 begin
1187 begin
1190 begin
1193 else
1201 var
1204 begin
1207 begin
1210 end
1214 {$IFDEF USE_ASM}
1215 asm
1226 REP STOSD
1229 REP STOSB
1231 @Exit:
1232 end;
1233 {$ELSE}
1234 begin
1237 {$ENDIF}
1240 {$IFDEF USE_ASM}
1241 asm
1253 REP STOSD
1254 @Word:
1260 @Byte:
1265 @Exit:
1268 end;
1269 {$ELSE}
1270 var
1272 begin
1280 begin
1286 {$ENDIF}
1289 {$IFDEF USE_ASM}
1290 asm
1299 REP STOSD
1300 @Word:
1306 @Byte:
1311 @Exit:
1314 end;
1315 {$ELSE}
1316 var
1318 begin
1325 begin
1331 {$ENDIF}
1334 begin
1339 begin
1342 begin
1345 begin
1356 var
1358 begin
1365 begin
1373 begin
1381 begin
1391 begin
1393 begin
1400 begin
1405 procedure ClipCopyBounds(var SrcX, SrcY, Width, Height, DstX, DstY: LongInt; SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect);
1409 var
1412 begin
1415 begin
1422 begin
1431 begin
1441 var
1445 begin
1448 begin
1456 begin
1463 begin
1469 begin
1476 begin
1482 var
1489 begin
1496 begin
1500 end
1501 else
1502 begin
1504 Result := BoundsToRect(TargetRect.Left, TargetRect.Top + ((TargetHeight - ScaledHeight) div 2),
1510 var
1512 begin
1521 begin
1526 begin
1531 begin
1532 Result:=
1540 begin
1541 Result :=
1549 begin
1554 begin
1559 begin
1561 begin
1570 begin
1575 begin
1580 begin
1585 var
1587 begin
1589 {$IFDEF MSWINDOWS}
1592 else
1594 {$ENDIF}
1595 {$IFDEF UNIX}
1597 {$ENDIF}
1598 {$IFDEF MSDOS}
1600 {$ENDIF}
1603 initialization
1604 InitCrcTable;
1605 {$IFDEF MSWINDOWS}
1608 {$ENDIF}
1610 {$IF Defined(DELPHI)}
1611 {$IF CompilerVersion >= 23}
1613 {$ELSE}
1615 {$IFEND}
1616 {$ELSE FPC}
1619 {$IFEND}
1621 {
1622 File Notes:
1624 -- TODOS ----------------------------------------------------
1625 - nothing now
1627 -- 0.77.1 ----------------------------------------------------
1628 - Added GetFileName, GetFileDir, RectWidth, RectHeight function.
1629 - Added ScaleSizeToFit function.
1630 - Added ZeroMemory and SwapValues for Booleans.
1631 - Added Substring function.
1632 - Renamed MatchFileNameMask to StrMaskMatch (it's for general use not
1633 just filenames).
1634 - Delphi XE2 new targets (Win64, OSX32) compatibility changes.
1635 - Added GetFormatSettingsForFloats function.
1637 -- 0.26.5 Changes/Bug Fixes -----------------------------------
1638 - Added Log10 function.
1639 - Added TFloatRect type and helper functions FloatRect, FloatRectWidth,
1640 FloatRectHeight.
1641 - Added string function ContainsAnySubStr.
1642 - Added functions PixelSizeToDpi, DpiToPixelSize.
1644 -- 0.26.1 Changes/Bug Fixes -----------------------------------
1645 - Some formatting changes.
1646 - Changed some string functions to work with localized strings.
1647 - ASM version of PosEx had bugs, removed it.
1648 - Added StrTokensToList function.
1650 -- 0.25.0 Changes/Bug Fixes -----------------------------------
1651 - Fixed error in ClipCopyBounds which was causing ... bad clipping!
1653 -- 0.24.3 Changes/Bug Fixes -----------------------------------
1654 - Added GetTimeMilliseconds function.
1655 - Added IntToStrFmt and FloatToStrFmt helper functions.
1657 -- 0.23 Changes/Bug Fixes -----------------------------------
1658 - Added RectInRect and RectIntersects functions
1659 - Added some string utils: StrToken, StrTokenEnd, PosEx, PosNoCase.
1660 - Moved BuildFileList here from DemoUtils.
1662 -- 0.21 Changes/Bug Fixes -----------------------------------
1663 - Moved GetVolumeLevelCount from ImagingDds here.
1664 - Renamed FillMemory to FillMemoryByte to avoid name collision in C++ Builder.
1665 - Added Iff function for Char, Pointer, and Int64 types.
1666 - Added IsLittleEndian function.
1667 - Added array types for TWordRec, TLongWordRec, and TInt64Rec.
1668 - Added MatchFileNameMask function.
1670 -- 0.19 Changes/Bug Fixes -----------------------------------
1671 - added ScaleRectToRect (thanks to Paul Michell)
1672 - added BoundsToRect, ClipBounds, ClipCopyBounds, ClipStretchBounds functions
1673 - added MulDiv function
1674 - FreeAndNil is not inline anymore - caused AV in one program
1676 -- 0.17 Changes/Bug Fixes -----------------------------------
1678 - GetAppExe didn't return absolute path in FreeBSD, fixed
1679 - added debug message output
1680 - fixed Unix compatibility issues (thanks to Ales Katona).
1681 Imaging now compiles in FreeBSD and maybe in other Unixes as well.
1683 -- 0.15 Changes/Bug Fixes -----------------------------------
1684 - added some new utility functions
1686 -- 0.13 Changes/Bug Fixes -----------------------------------
1687 - added many new utility functions
1688 - minor change in SwapEndian to avoid range check error
1690 }