2
0

GR32.ImageFormats.pas 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439
  1. unit GR32.ImageFormats;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Image Format support for Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Anders Melander <[email protected]>
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2008-2022
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * Contributor(s):
  31. *
  32. * ***** END LICENSE BLOCK ***** *)
  33. interface
  34. {$include GR32.inc}
  35. uses
  36. Classes,
  37. Generics.Defaults,
  38. Generics.Collections,
  39. {$ifdef FPC}
  40. Graphics,
  41. LCLType,
  42. {$endif FPC}
  43. GR32;
  44. {$ifndef FPC}
  45. {$define ANONYMOUS_METHODS}
  46. {$endif FPC}
  47. (*******************************************************************************
  48. **
  49. ** Interfaces implemented by the individual image formats
  50. **
  51. *******************************************************************************)
  52. //------------------------------------------------------------------------------
  53. //
  54. // IImageFormat
  55. //
  56. //------------------------------------------------------------------------------
  57. type
  58. IImageFormat = interface
  59. ['{E457B520-80B3-403D-8658-4C9ADAF3A7A0}']
  60. end;
  61. //------------------------------------------------------------------------------
  62. //
  63. // IImageFormatAdapter
  64. //
  65. //------------------------------------------------------------------------------
  66. // Handles Assign/AssignTo between TBitmap32 and other formats.
  67. //------------------------------------------------------------------------------
  68. type
  69. IImageFormatAdapter = interface
  70. ['{5C4DC69F-F3A0-4265-A855-495CF54AB808}']
  71. // Copy from image format
  72. function CanAssignFrom(Source: TPersistent): boolean;
  73. function AssignFrom(Dest: TCustomBitmap32; Source: TPersistent): boolean;
  74. // Copy to image format
  75. function CanAssignTo(Dest: TPersistent): boolean;
  76. function AssignTo(Source: TCustomBitmap32; Dest: TPersistent): boolean;
  77. end;
  78. //------------------------------------------------------------------------------
  79. //
  80. // IImageFormatWriteNotification
  81. //
  82. //------------------------------------------------------------------------------
  83. // Notifies an IImageFormatAdapter that we are about to call CanAssignTo/AssignTo.
  84. // Presently just used to Open/Close the clipboard.
  85. //------------------------------------------------------------------------------
  86. type
  87. IImageFormatWriteNotification = interface
  88. ['{C5A8BE35-5188-4801-ACB0-612E0DE897E3}']
  89. procedure BeginWriting(Source: TCustomBitmap32; Dest: TPersistent);
  90. procedure EndWriting(Source: TCustomBitmap32; Dest: TPersistent);
  91. end;
  92. //------------------------------------------------------------------------------
  93. //
  94. // IImageFormatAux
  95. //
  96. //------------------------------------------------------------------------------
  97. // An IImageFormatAdapter can use this interface to indicate that it is an
  98. // auxiliary format. An auxiliary format is an optional addition to a primary
  99. // format.
  100. // For example, when copying to the clipboard, PNG is an auxiliary format while
  101. // CF_DIBV5 is the primary format and we want them both on the clipboard.
  102. //------------------------------------------------------------------------------
  103. type
  104. IImageFormatAux = interface
  105. ['{2774D499-174D-47BC-BF9E-7FEF839C55DA}']
  106. function IsAuxFormat(Source: TCustomBitmap32; Dest: TPersistent): boolean;
  107. end;
  108. //------------------------------------------------------------------------------
  109. //
  110. // IImageFormatFileInfo
  111. //
  112. //------------------------------------------------------------------------------
  113. // File related image format info.
  114. //------------------------------------------------------------------------------
  115. type
  116. TFileTypes = array of string;
  117. IImageFormatFileInfo = interface
  118. ['{EC7037E2-DE93-43A8-AD5D-7BDD91E59E04}']
  119. function ImageFormatDescription: string;
  120. function ImageFormatFileTypes: TFileTypes;
  121. end;
  122. //------------------------------------------------------------------------------
  123. //
  124. // IImageFormatClipboardFormat
  125. //
  126. //------------------------------------------------------------------------------
  127. // Reads data from the clipboard.
  128. //------------------------------------------------------------------------------
  129. // When data is read from the clipboard, we iterate all image formats that
  130. // support IImageFormatClipboardFormat; We first try calling PasteFromClipboard
  131. // on the image format and if that isn't successful, we then iterate the
  132. // available clipboard formats and call LoadFromClipboardFormat on each in turn.
  133. // If both of the above methods return False, we fall back to using the
  134. // IImageFormatReader interface to try and read the data.
  135. //------------------------------------------------------------------------------
  136. type
  137. {$ifdef FPC}
  138. TClipboardFormat = LCLType.TClipboardFormat;
  139. {$else FPC}
  140. TClipboardFormat = Word;
  141. {$endif FPC}
  142. IImageFormatClipboardFormat = interface
  143. ['{E5550CCE-5D78-46C7-8714-11E0CF44561B}']
  144. function SupportsClipboardFormat(AFormat: TClipboardFormat): Boolean;
  145. function PasteFromClipboard(ADest: TCustomBitmap32): boolean;
  146. function LoadFromClipboardFormat(ADest: TCustomBitmap32; AFormat: TClipboardFormat; AData: THandle; APalette: THandle): boolean;
  147. end;
  148. //------------------------------------------------------------------------------
  149. //
  150. // IImageFormatReader
  151. //
  152. //------------------------------------------------------------------------------
  153. // Reads from an image format into TBitmap32.
  154. //------------------------------------------------------------------------------
  155. type
  156. IImageFormatReader = interface
  157. ['{D90E2FCD-65ED-4A1B-8A13-2D25618F7EE7}']
  158. function CanLoadFromStream(AStream: TStream): boolean;
  159. function LoadFromStream(ADest: TCustomBitmap32; AStream: TStream): boolean;
  160. end;
  161. //------------------------------------------------------------------------------
  162. //
  163. // IImageFormatFileReader
  164. //
  165. //------------------------------------------------------------------------------
  166. // Reads from an image format into TBitmap32.
  167. // The Filename parameter should be used to determine the image format.
  168. //------------------------------------------------------------------------------
  169. type
  170. IImageFormatFileReader = interface
  171. ['{F255F49D-E49A-47CE-AC7A-485FC5A4B2CE}']
  172. function LoadFromFile(ADest: TCustomBitmap32; const AFilename: string): boolean;
  173. end;
  174. //------------------------------------------------------------------------------
  175. //
  176. // IImageFormatResourceReader
  177. //
  178. //------------------------------------------------------------------------------
  179. // Reads from an image format into TBitmap32.
  180. // The ResourceType and Stream parameters should be used to determine the image
  181. // format.
  182. //------------------------------------------------------------------------------
  183. type
  184. IImageFormatResourceReader = interface
  185. ['{7DB70759-6079-4C5D-96FB-55905BE9FBEC}']
  186. function LoadFromResource(ADest: TCustomBitmap32; AResourceType: PChar; AStream: TStream): boolean;
  187. end;
  188. //------------------------------------------------------------------------------
  189. //
  190. // IImageFormatWriter
  191. //
  192. //------------------------------------------------------------------------------
  193. // Writes TBitmap32 as an image format.
  194. //------------------------------------------------------------------------------
  195. type
  196. IImageFormatWriter = interface
  197. ['{78358E48-60E3-4119-88D1-CB0CFADEE5CF}']
  198. procedure SaveToStream(ASource: TCustomBitmap32; AStream: TStream);
  199. end;
  200. (*******************************************************************************
  201. **
  202. ** Interfaces implemented by the Image Format Manager
  203. **
  204. *******************************************************************************)
  205. //------------------------------------------------------------------------------
  206. //
  207. // IImageFormatClipboardFormats
  208. //
  209. //------------------------------------------------------------------------------
  210. // Perform clipboard related stuff on all the registered image format adapters.
  211. //------------------------------------------------------------------------------
  212. type
  213. IImageFormatClipboardFormats = interface
  214. ['{EC307484-A5D2-455D-AD4A-D96263A8E775}']
  215. function SupportsClipboardFormat(AFormat: TClipboardFormat): Boolean;
  216. function CanPasteFromClipboard: boolean;
  217. function PasteFromClipboard(ADest: TCustomBitmap32): boolean;
  218. end;
  219. //------------------------------------------------------------------------------
  220. //
  221. // IImageFormatReaders
  222. //
  223. //------------------------------------------------------------------------------
  224. // List of IImageFormatReader.
  225. //------------------------------------------------------------------------------
  226. type
  227. IImageFormatReaders = interface
  228. ['{1D2B1F37-D85E-4E6F-BFEC-7C8CC02B4B9B}']
  229. function FindReader(const AFileType: string): IImageFormatReader; overload;
  230. function FindReader(AStream: TStream): IImageFormatReader; overload;
  231. function CanLoadFromStream(AStream: TStream): boolean;
  232. function LoadFromStream(ADest: TCustomBitmap32; AStream: TStream): boolean; overload;
  233. // Note: LoadFromStream(...AFilename) only uses readers that implement both
  234. // IImageFormatReader and IImageFormatFileInfo.
  235. // The file extension of the Filename parameter must match one of the values
  236. // in IImageFormatFileInfo.ImageFormatFileTypes.
  237. function LoadFromStream(ADest: TCustomBitmap32; AStream: TStream; const AFilename: string): boolean; overload;
  238. // Note: LoadFromFile only uses readers that implement IImageFormatFileReader
  239. // it does not fall back to IImageFormatReader.LoadFromStream
  240. function LoadFromFile(ADest: TCustomBitmap32; const AFilename: string): boolean;
  241. function LoadFromResource(ADest: TCustomBitmap32; AResourceType: TResourceType; AStream: TStream): boolean;
  242. end;
  243. //------------------------------------------------------------------------------
  244. //
  245. // IImageFormatWriters
  246. //
  247. //------------------------------------------------------------------------------
  248. // List of IImageFormatWriter.
  249. //------------------------------------------------------------------------------
  250. type
  251. IImageFormatWriters = interface
  252. ['{5D09FAA7-7A7F-4A7B-BFA0-1D9C16DA6444}']
  253. function FindWriter(const AFileType: string): IImageFormatWriter;
  254. end;
  255. //------------------------------------------------------------------------------
  256. //
  257. // IImageFormatManager
  258. //
  259. //------------------------------------------------------------------------------
  260. const
  261. ImageFormatPriorityWorst = 2000;
  262. ImageFormatPriorityWorse = 1000;
  263. ImageFormatPriorityNormal = 0;
  264. ImageFormatPriorityBetter = -1000;
  265. ImageFormatPriorityBest = -2000;
  266. type
  267. IImageFormatEnumerator = interface
  268. ['{68377765-DD99-49C6-868F-18A86468627B}']
  269. function GetCurrent: IImageFormat;
  270. function MoveNext: Boolean;
  271. property Current: IImageFormat read GetCurrent;
  272. end;
  273. IImageFormats = interface
  274. ['{62458797-D109-4EBA-9941-DD5872ABA202}']
  275. function GetEnumerator: IImageFormatEnumerator;
  276. end;
  277. IImageFormatManager = interface
  278. ['{91478233-7F42-4F47-AF1B-0F27D6912CC7}']
  279. function RegisterImageFormat(const AImageFormat: IImageFormat; APriority: integer = ImageFormatPriorityNormal): integer;
  280. procedure UnregisterImageFormat(const AImageFormat: IImageFormat); overload;
  281. procedure UnregisterImageFormat(const AHandle: integer); overload;
  282. function ImageFormats: IImageFormats; overload;
  283. function ImageFormats(Intf: TGUID): IImageFormats; overload;
  284. function GetAdapters: IImageFormatAdapter;
  285. property Adapters: IImageFormatAdapter read GetAdapters;
  286. function GetReaders: IImageFormatReaders;
  287. property Readers: IImageFormatReaders read GetReaders;
  288. function GetWriters: IImageFormatWriters;
  289. property Writers: IImageFormatWriters read GetWriters;
  290. function GetClipboardFormats: IImageFormatClipboardFormats;
  291. property ClipboardFormats: IImageFormatClipboardFormats read GetClipboardFormats;
  292. function BuildFileFilter(Intf: TGUID; IncludeAll: boolean = False): string;
  293. end;
  294. //------------------------------------------------------------------------------
  295. //
  296. // TCustomImageFormat
  297. //
  298. //------------------------------------------------------------------------------
  299. // Example, abstract base class for implementation of IImageFormat
  300. //------------------------------------------------------------------------------
  301. type
  302. TCustomImageFormat = class abstract(TInterfacedObject, IImageFormat)
  303. end;
  304. //------------------------------------------------------------------------------
  305. //
  306. // TCustomImageFormatAdapter
  307. //
  308. //------------------------------------------------------------------------------
  309. // Example, abstract base class for implementation of IImageFormatAdapter
  310. //------------------------------------------------------------------------------
  311. type
  312. TCustomImageFormatAdapter = class abstract(TCustomImageFormat, IImageFormatAdapter)
  313. strict protected
  314. // IImageFormatAdapter
  315. function CanAssignFrom(Source: TPersistent): boolean; virtual;
  316. function AssignFrom(Dest: TCustomBitmap32; Source: TPersistent): boolean; virtual;
  317. function CanAssignTo(Dest: TPersistent): boolean; virtual;
  318. function AssignTo(Source: TCustomBitmap32; Dest: TPersistent): boolean; virtual;
  319. end;
  320. //------------------------------------------------------------------------------
  321. //
  322. // ImageFormatManager
  323. //
  324. //------------------------------------------------------------------------------
  325. // Main entry point for the image format manager.
  326. //------------------------------------------------------------------------------
  327. function ImageFormatManager: IImageFormatManager;
  328. //------------------------------------------------------------------------------
  329. //
  330. // File signature utilities
  331. //
  332. //------------------------------------------------------------------------------
  333. function CheckFileSignature(Stream: TStream; const Signature, Mask: AnsiString; Offset: int64 = 0): boolean; overload;
  334. function CheckFileSignature(Stream: TStream; const Signature: AnsiString; Offset: int64 = 0): boolean; overload;
  335. function CheckFileSignature(Stream: TStream; const Signature; Size: Cardinal; const Mask; MaskSize: Cardinal; Offset: int64 = 0): boolean; overload;
  336. function CheckFileSignature(Stream: TStream; const Signature; Size: Cardinal; Offset: int64): boolean; overload;
  337. function CheckFileSignatureWide(Stream: TStream; const Signature: UnicodeString; Offset: int64 = 0): boolean;
  338. // Unicode string: For each WideChar in the string, lower byte contains value, upper byte contains mask
  339. function CheckFileSignatureComposite(Stream: TStream; const Signature: UnicodeString; Offset: int64 = 0): boolean;
  340. //------------------------------------------------------------------------------
  341. resourcestring
  342. sUnknownImageFormat = 'Unknown image format';
  343. //------------------------------------------------------------------------------
  344. //
  345. // FPC compatibility
  346. //
  347. //------------------------------------------------------------------------------
  348. {$ifdef FPC}
  349. type
  350. TGraphicHelper = class helper for TGraphic
  351. class function CanLoadFromStream(Stream: TStream): Boolean;
  352. end;
  353. {$endif FPC}
  354. //------------------------------------------------------------------------------
  355. //------------------------------------------------------------------------------
  356. //------------------------------------------------------------------------------
  357. implementation
  358. uses
  359. {$ifndef FPC}
  360. Consts,
  361. IOUtils,
  362. Windows,
  363. {$endif FPC}
  364. ClipBrd,
  365. SysUtils,
  366. GR32_Clipboard;
  367. //------------------------------------------------------------------------------
  368. //
  369. // FPC compatibility
  370. //
  371. //------------------------------------------------------------------------------
  372. {$ifdef FPC}
  373. resourcestring
  374. sAllFilter = 'All';
  375. type
  376. EClipboardException = Exception;
  377. type
  378. TPath = class
  379. public
  380. class function GetExtension(const APath: string): string; static;
  381. end;
  382. class function TPath.GetExtension(const APath: string): string;
  383. begin
  384. Result := ExtractFileExt(APath);
  385. end;
  386. class function TGraphicHelper.CanLoadFromStream(Stream: TStream): Boolean;
  387. begin
  388. Result := IsStreamFormatSupported(Stream);
  389. end;
  390. {$endif FPC}
  391. //------------------------------------------------------------------------------
  392. //
  393. // File signature utilities
  394. //
  395. //------------------------------------------------------------------------------
  396. function CheckFileSignature(Stream: TStream; const Signature; Size: Cardinal; const Mask; MaskSize: Cardinal; Offset: int64): boolean; overload;
  397. var
  398. Buffer: TBytes;
  399. Count: Cardinal;
  400. SavePos: int64;
  401. BufferByte, SigByte, MaskByte: PByte;
  402. begin
  403. ASSERT(Size >= MaskSize);
  404. ASSERT(Size > 0);
  405. SetLength(Buffer, Size);
  406. SavePos := Stream.Position;
  407. try
  408. Stream.Position := Offset;
  409. if (Stream.Read(Buffer[0], Size) = Int64(Size)) then
  410. begin
  411. Result := True;
  412. BufferByte := @Buffer[0];
  413. SigByte := PByte(@Signature);
  414. MaskByte := PByte(@Mask);
  415. Count := 1;
  416. while (Result) and (Count <= Size) do
  417. begin
  418. if (Count <= MaskSize) then
  419. Result := ((BufferByte^ and MaskByte^) = (SigByte^ and MaskByte^))
  420. else
  421. Result := (BufferByte^ = SigByte^);
  422. inc(Count);
  423. inc(BufferByte);
  424. inc(SigByte);
  425. inc(MaskByte);
  426. end;
  427. end else
  428. Result := False;
  429. finally
  430. Stream.Position := SavePos;
  431. end;
  432. end;
  433. function CheckFileSignature(Stream: TStream; const Signature; Size: Cardinal; Offset: int64): boolean;
  434. begin
  435. Result := CheckFileSignature(Stream, Signature, Size, nil^, 0, Offset);
  436. end;
  437. function CheckFileSignature(Stream: TStream; const Signature, Mask: AnsiString; Offset: int64): boolean;
  438. begin
  439. Result := CheckFileSignature(Stream, Signature[1], Length(Signature), Mask[1], Length(Mask), Offset);
  440. end;
  441. function CheckFileSignature(Stream: TStream; const Signature: AnsiString; Offset: int64): boolean;
  442. begin
  443. Result := CheckFileSignature(Stream, Signature[1], Length(Signature), Offset);
  444. end;
  445. function CheckFileSignatureWide(Stream: TStream; const Signature: UnicodeString; Offset: int64): boolean;
  446. begin
  447. Result := CheckFileSignature(Stream, Signature[1], Length(Signature)*SizeOf(WideChar), nil^, 0, Offset);
  448. end;
  449. function CheckFileSignatureComposite(Stream: TStream; const Signature: UnicodeString; Offset: int64 = 0): boolean;
  450. var
  451. Values: AnsiString;
  452. Mask: AnsiString;
  453. i: integer;
  454. p: PAnsiChar;
  455. begin
  456. SetLength(Values, Length(Signature));
  457. SetLength(Mask, Length(Signature));
  458. p := @(Signature[1]);
  459. for i := 1 to Length(Signature) do
  460. begin
  461. Values[i] := p^;
  462. inc(p);
  463. Mask[i] := p^;
  464. inc(p);
  465. end;
  466. Result := CheckFileSignature(Stream, Values, Mask, Offset);
  467. end;
  468. //------------------------------------------------------------------------------
  469. //
  470. // TCustomImageFormatAdapter
  471. //
  472. //------------------------------------------------------------------------------
  473. function TCustomImageFormatAdapter.CanAssignFrom(Source: TPersistent): boolean;
  474. begin
  475. Result := False;
  476. end;
  477. function TCustomImageFormatAdapter.AssignFrom(Dest: TCustomBitmap32; Source: TPersistent): boolean;
  478. begin
  479. if (CanAssignFrom(Source)) then
  480. begin
  481. Dest.Assign(Source);
  482. Result := True;
  483. end else
  484. Result := False;
  485. end;
  486. //------------------------------------------------------------------------------
  487. function TCustomImageFormatAdapter.CanAssignTo(Dest: TPersistent): boolean;
  488. begin
  489. Result := False;
  490. end;
  491. function TCustomImageFormatAdapter.AssignTo(Source: TCustomBitmap32; Dest: TPersistent): boolean;
  492. begin
  493. if (CanAssignTo(Dest)) then
  494. begin
  495. Dest.Assign(Source);
  496. Result := True;
  497. end else
  498. Result := False;
  499. end;
  500. //------------------------------------------------------------------------------
  501. //
  502. // IImageFormatManagerInternal
  503. //
  504. //------------------------------------------------------------------------------
  505. type
  506. IImageFormatManagerInternal = interface
  507. ['{3A0A7985-6DE5-4D8A-99AF-560735712E26}']
  508. procedure Shutdown;
  509. end;
  510. //------------------------------------------------------------------------------
  511. //
  512. // TImageFormatManager
  513. //
  514. //------------------------------------------------------------------------------
  515. // Implements IImageFormatManager.
  516. //------------------------------------------------------------------------------
  517. type
  518. TImageFormatManager = class(TInterfacedObject, IImageFormatManager,
  519. IImageFormatManagerInternal,
  520. IImageFormatAdapter,
  521. IImageFormatReaders,
  522. IImageFormatWriters,
  523. IImageFormatClipboardFormats)
  524. {$ifdef ANONYMOUS_METHODS}
  525. strict private type
  526. {$else ANONYMOUS_METHODS}
  527. private type
  528. {$endif ANONYMOUS_METHODS}
  529. TImageFormatItem = record
  530. Priority: integer;
  531. ImageFormat: IImageFormat;
  532. Handle: integer;
  533. end;
  534. {$ifdef FPC}
  535. // FPC's TList<T>.BinarySearch doesn't return insertion point and doesn't handle search in empty list...
  536. TImageFormatList = class(TList<TImageFormatItem>)
  537. private
  538. FComparer: IComparer<TImageFormatItem>;
  539. public
  540. constructor Create(const AComparer: IComparer<TImageFormatItem>);
  541. function BinarySearch(const Item: TImageFormatItem; out FoundIndex: Integer): Boolean;
  542. end;
  543. {$else FPC}
  544. TImageFormatList = TList<TImageFormatItem>;
  545. {$endif FPC}
  546. TImageFormatEnumerator = class(TInterfacedObject, IImageFormats, IImageFormatEnumerator)
  547. private
  548. FList: TImageFormatList;
  549. FGUID: TGUID;
  550. FIndex: Integer;
  551. private
  552. // IImageFormats
  553. function GetEnumerator: IImageFormatEnumerator;
  554. // IImageFormatEnumerator
  555. function GetCurrent: IImageFormat;
  556. function MoveNext: Boolean;
  557. public
  558. constructor Create(AList: TImageFormatList; const AGUID: TGUID);
  559. end;
  560. strict private
  561. // List of image format, ordered by priority
  562. FFormats: TImageFormatList;
  563. // Image format handle counter
  564. FImageFormatHandle: integer;
  565. class var FInstance: IImageFormatManager;
  566. strict private
  567. class function GetInstance: IImageFormatManager; static;
  568. private
  569. // IImageFormatManagerInternal
  570. procedure Shutdown;
  571. private
  572. // IImageFormatManager
  573. function RegisterImageFormat(const AImageFormat: IImageFormat; APriority: integer): integer;
  574. procedure UnregisterImageFormat(const AImageFormat: IImageFormat); overload;
  575. procedure UnregisterImageFormat(const AHandle: integer); overload;
  576. function ImageFormats: IImageFormats; overload;
  577. function ImageFormats(Intf: TGUID): IImageFormats; overload;
  578. function GetAdapters: IImageFormatAdapter;
  579. function GetReaders: IImageFormatReaders;
  580. function GetWriters: IImageFormatWriters;
  581. function GetClipboardFormats: IImageFormatClipboardFormats;
  582. function BuildFileFilter(Intf: TGUID; IncludeAll: boolean): string;
  583. private
  584. // IImageFormatAdapter
  585. function CanAssignFrom(Source: TPersistent): boolean;
  586. function AssignFrom(Dest: TCustomBitmap32; Source: TPersistent): boolean;
  587. function CanAssignTo(Dest: TPersistent): boolean;
  588. function AssignTo(Source: TCustomBitmap32; Dest: TPersistent): boolean;
  589. private
  590. // IImageFormatReaders
  591. function FindReader(const AFileType: string): IImageFormatReader; overload;
  592. function FindReader(AStream: TStream): IImageFormatReader; overload;
  593. function CanLoadFromStream(AStream: TStream): boolean;
  594. function LoadFromStream(ADest: TCustomBitmap32; AStream: TStream): boolean; overload;
  595. function LoadFromStream(ADest: TCustomBitmap32; AStream: TStream; const AFilename: string): boolean; overload;
  596. function LoadFromFile(ADest: TCustomBitmap32; const AFilename: string): boolean;
  597. function LoadFromResource(ADest: TCustomBitmap32; AResourceType: TResourceType; AStream: TStream): boolean;
  598. private
  599. // IImageFormatWriters
  600. function FindWriter(const AFileType: string): IImageFormatWriter;
  601. private
  602. // IImageFormatClipboardFormats
  603. function SupportsClipboardFormat(AFormat: TClipboardFormat): Boolean;
  604. function CanPasteFromClipboard: boolean;
  605. function PasteFromClipboard(ADest: TCustomBitmap32): boolean;
  606. private
  607. class destructor Destroy;
  608. public
  609. destructor Destroy; override;
  610. class property Instance: IImageFormatManager read GetInstance;
  611. end;
  612. //------------------------------------------------------------------------------
  613. class destructor TImageFormatManager.Destroy;
  614. begin
  615. if (FInstance <> nil) then
  616. {$ifdef CAST_INTF_TO_CLASS}
  617. TImageFormatManager(FInstance).Shutdown;
  618. {$else}
  619. (FInstance as IImageFormatManagerInternal).Shutdown;
  620. {$endif}
  621. FInstance := nil;
  622. end;
  623. class function TImageFormatManager.GetInstance: IImageFormatManager;
  624. begin
  625. if (FInstance = nil) then
  626. FInstance := TImageFormatManager.Create;
  627. Result := FInstance;
  628. end;
  629. destructor TImageFormatManager.Destroy;
  630. begin
  631. FreeAndNil(FFormats);
  632. inherited;
  633. end;
  634. procedure TImageFormatManager.Shutdown;
  635. begin
  636. if (FFormats <> nil) then
  637. FFormats.Clear;
  638. end;
  639. //------------------------------------------------------------------------------
  640. // IImageFormatAdapter
  641. //------------------------------------------------------------------------------
  642. function TImageFormatManager.AssignFrom(Dest: TCustomBitmap32; Source: TPersistent): boolean;
  643. var
  644. Item: TImageFormatItem;
  645. Adapter: IImageFormatAdapter;
  646. begin
  647. if (FFormats = nil) then
  648. exit(False);
  649. for Item in FFormats do
  650. if (Supports(Item.ImageFormat, IImageFormatAdapter, Adapter)) and (Adapter.AssignFrom(Dest, Source)) then
  651. exit(True);
  652. Result := False;
  653. end;
  654. function TImageFormatManager.AssignTo(Source: TCustomBitmap32; Dest: TPersistent): boolean;
  655. var
  656. Item: TImageFormatItem;
  657. Adapter: IImageFormatAdapter;
  658. WriteNotification: IImageFormatWriteNotification;
  659. ImageFormatAux: IImageFormatAux;
  660. HasAuxFormats: boolean;
  661. begin
  662. Result := False;
  663. if (FFormats = nil) then
  664. Exit;
  665. HasAuxFormats := False;
  666. for Item in FFormats do
  667. if (Supports(Item.ImageFormat, IImageFormatAdapter)) then
  668. begin
  669. if (Supports(Item.ImageFormat, IImageFormatWriteNotification, WriteNotification)) then
  670. WriteNotification.BeginWriting(Source, Dest);
  671. if (not HasAuxFormats) and (Supports(Item.ImageFormat, IImageFormatAux, ImageFormatAux)) then
  672. HasAuxFormats := ImageFormatAux.IsAuxFormat(Source, Dest);
  673. end;
  674. try
  675. for Item in FFormats do
  676. if (Supports(Item.ImageFormat, IImageFormatAdapter, Adapter)) and (Adapter.AssignTo(Source, Dest)) then
  677. begin
  678. Result := True;
  679. // If we have auxiliary formats then we need to continue so
  680. // all supported formats can be copied.
  681. if (not HasAuxFormats) then
  682. break;
  683. end;
  684. finally
  685. for Item in FFormats do
  686. if (Supports(Item.ImageFormat, IImageFormatAdapter)) and
  687. (Supports(Item.ImageFormat, IImageFormatWriteNotification, WriteNotification)) then
  688. WriteNotification.EndWriting(Source, Dest);
  689. end;
  690. end;
  691. function TImageFormatManager.CanAssignFrom(Source: TPersistent): boolean;
  692. var
  693. Item: TImageFormatItem;
  694. Adapter: IImageFormatAdapter;
  695. begin
  696. if (FFormats = nil) then
  697. exit(False);
  698. for Item in FFormats do
  699. if (Supports(Item.ImageFormat, IImageFormatAdapter, Adapter)) and (Adapter.CanAssignFrom(Source)) then
  700. exit(True);
  701. Result := False;
  702. end;
  703. function TImageFormatManager.CanAssignTo(Dest: TPersistent): boolean;
  704. var
  705. Item: TImageFormatItem;
  706. Adapter: IImageFormatAdapter;
  707. begin
  708. if (FFormats = nil) then
  709. exit(False);
  710. for Item in FFormats do
  711. if (Supports(Item.ImageFormat, IImageFormatAdapter, Adapter)) and (Adapter.CanAssignTo(Dest)) then
  712. exit(True);
  713. Result := False;
  714. end;
  715. //------------------------------------------------------------------------------
  716. // IImageFormatReaders
  717. //------------------------------------------------------------------------------
  718. function TImageFormatManager.FindReader(const AFileType: string): IImageFormatReader;
  719. var
  720. Item: TImageFormatItem;
  721. Reader: IImageFormatReader;
  722. FileInfo: IImageFormatFileInfo;
  723. FileType: string;
  724. begin
  725. Result := nil;
  726. if (FFormats = nil) then
  727. exit;
  728. for Item in FFormats do
  729. if (Supports(Item.ImageFormat, IImageFormatReader, Reader)) and
  730. (Supports(Item.ImageFormat, IImageFormatFileInfo, FileInfo)) then
  731. begin
  732. for FileType in FileInfo.ImageFormatFileTypes do
  733. if (SameText(AFileType, FileType)) then
  734. exit(Reader);
  735. end;
  736. end;
  737. function TImageFormatManager.FindReader(AStream: TStream): IImageFormatReader;
  738. var
  739. Item: TImageFormatItem;
  740. Reader: IImageFormatReader;
  741. SavePos: Int64;
  742. begin
  743. Result := nil;
  744. if (FFormats = nil) then
  745. exit;
  746. SavePos := AStream.Position;
  747. for Item in FFormats do
  748. if (Supports(Item.ImageFormat, IImageFormatReader, Reader)) then
  749. begin
  750. if (Reader.CanLoadFromStream(AStream)) then
  751. begin
  752. AStream.Position := SavePos;
  753. exit(Reader);
  754. end;
  755. AStream.Position := SavePos;
  756. end;
  757. end;
  758. function TImageFormatManager.CanLoadFromStream(AStream: TStream): boolean;
  759. var
  760. Reader: IImageFormatReader;
  761. begin
  762. Reader := FindReader(AStream);
  763. Result := (Reader <> nil);
  764. end;
  765. function TImageFormatManager.LoadFromFile(ADest: TCustomBitmap32; const AFilename: string): boolean;
  766. var
  767. Item: TImageFormatItem;
  768. Reader: IImageFormatFileReader;
  769. begin
  770. for Item in FFormats do
  771. if (Supports(Item.ImageFormat, IImageFormatFileReader, Reader)) then
  772. begin
  773. if (Reader.LoadFromFile(ADest, AFilename)) then
  774. exit(True);
  775. end;
  776. Result := False;
  777. end;
  778. function TImageFormatManager.LoadFromResource(ADest: TCustomBitmap32; AResourceType: TResourceType;
  779. AStream: TStream): boolean;
  780. var
  781. Item: TImageFormatItem;
  782. ResourceReader: IImageFormatResourceReader;
  783. Reader: IImageFormatReader;
  784. SavePos: Int64;
  785. begin
  786. SavePos := AStream.Position;
  787. // First try reading resource format
  788. for Item in FFormats do
  789. if (Supports(Item.ImageFormat, IImageFormatResourceReader, ResourceReader)) then
  790. begin
  791. if (ResourceReader.LoadFromResource(ADest, AResourceType, AStream)) then
  792. exit(True);
  793. AStream.Position := SavePos; // Restore pos after LoadFromResource
  794. end;
  795. // Fall back to reading in file format
  796. for Item in FFormats do
  797. if (Supports(Item.ImageFormat, IImageFormatReader, Reader)) then
  798. begin
  799. if (Reader.LoadFromStream(ADest, AStream)) then
  800. exit(True);
  801. AStream.Position := SavePos; // Restore pos after LoadFromStream
  802. end;
  803. Result := False;
  804. end;
  805. function TImageFormatManager.LoadFromStream(ADest: TCustomBitmap32; AStream: TStream): boolean;
  806. var
  807. Item: TImageFormatItem;
  808. Reader: IImageFormatReader;
  809. SavePos: Int64;
  810. begin
  811. SavePos := AStream.Position;
  812. for Item in FFormats do
  813. if (Supports(Item.ImageFormat, IImageFormatReader, Reader)) then
  814. begin
  815. if (Reader.CanLoadFromStream(AStream)) and (Reader.LoadFromStream(ADest, AStream)) then
  816. exit(True);
  817. AStream.Position := SavePos;
  818. end;
  819. Result := False;
  820. end;
  821. function TImageFormatManager.LoadFromStream(ADest: TCustomBitmap32; AStream: TStream;
  822. const AFilename: string): boolean;
  823. var
  824. Item: TImageFormatItem;
  825. Reader: IImageFormatReader;
  826. FileInfo: IImageFormatFileInfo;
  827. Extension: string;
  828. FileType: string;
  829. SavePos: Int64;
  830. begin
  831. SavePos := AStream.Position;
  832. Extension := Copy(TPath.GetExtension(AFilename), 2, MaxInt);
  833. for Item in FFormats do
  834. if (Supports(Item.ImageFormat, IImageFormatReader, Reader)) and
  835. (Supports(Item.ImageFormat, IImageFormatFileInfo, FileInfo)) then
  836. begin
  837. for FileType in FileInfo.ImageFormatFileTypes do
  838. if (SameText(Extension, FileType)) then
  839. begin
  840. if (Reader.CanLoadFromStream(AStream)) then
  841. begin
  842. AStream.Position := SavePos; // Restore pos after CanLoadFromStream
  843. if (Reader.LoadFromStream(ADest, AStream)) then
  844. exit(True);
  845. end;
  846. AStream.Position := SavePos; // Restore pos after CanLoadFromStream or LoadFromStream
  847. end;
  848. end;
  849. Result := False;
  850. end;
  851. //------------------------------------------------------------------------------
  852. // IImageFormatWriters
  853. //------------------------------------------------------------------------------
  854. function TImageFormatManager.FindWriter(const AFileType: string): IImageFormatWriter;
  855. var
  856. Item: TImageFormatItem;
  857. Writer: IImageFormatWriter;
  858. FileInfo: IImageFormatFileInfo;
  859. FileType: string;
  860. begin
  861. Result := nil;
  862. if (FFormats = nil) then
  863. exit;
  864. for Item in FFormats do
  865. if (Supports(Item.ImageFormat, IImageFormatWriter, Writer)) and
  866. (Supports(Item.ImageFormat, IImageFormatFileInfo, FileInfo)) then
  867. begin
  868. for FileType in FileInfo.ImageFormatFileTypes do
  869. if (SameText(AFileType, FileType)) then
  870. exit(Writer);
  871. end;
  872. end;
  873. //------------------------------------------------------------------------------
  874. // IImageFormatClipboardFormat
  875. //------------------------------------------------------------------------------
  876. function TImageFormatManager.SupportsClipboardFormat(AFormat: TClipboardFormat): Boolean;
  877. var
  878. Item: TImageFormatItem;
  879. ImageFormatClipboard: IImageFormatClipboardFormat;
  880. begin
  881. Result := False;
  882. if (FFormats = nil) then
  883. exit;
  884. for Item in FFormats do
  885. if (Supports(Item.ImageFormat, IImageFormatClipboardFormat, ImageFormatClipboard)) and
  886. (Supports(Item.ImageFormat, IImageFormatReader)) then
  887. if (ImageFormatClipboard.SupportsClipboardFormat(AFormat)) then
  888. Exit(True);
  889. end;
  890. function TImageFormatManager.CanPasteFromClipboard: boolean;
  891. var
  892. i: integer;
  893. begin
  894. Result := False;
  895. try
  896. // FPC doesn't actually read from the clipboard within Open and Close so we
  897. // can't acquire it while we're reading from it. This is clearly a bug.
  898. {$ifndef FPC}
  899. Clipboard.Open;
  900. {$endif FPC}
  901. except
  902. on E: EClipboardException do
  903. exit; // Something else has the clipboard open
  904. end;
  905. try
  906. // For some reason EnumClipboardFormats doesn't work with FPC, so we have to
  907. // use the incredibly inefficient (but more portable) Clipboard.Formats[]
  908. for i := 0 to Clipboard.FormatCount-1 do
  909. if (SupportsClipboardFormat(Clipboard.Formats[i])) then
  910. Exit(True);
  911. finally
  912. {$ifndef FPC}
  913. Clipboard.Close;
  914. {$endif FPC}
  915. end;
  916. end;
  917. function TImageFormatManager.PasteFromClipboard(ADest: TCustomBitmap32): boolean;
  918. var
  919. Item: TImageFormatItem;
  920. ImageFormatClipboard: IImageFormatClipboardFormat;
  921. Reader: IImageFormatReader;
  922. ClipboardFormat: TClipboardFormat;
  923. Stream: TStream;
  924. i: integer;
  925. {$ifndef FPC}
  926. var
  927. Data: HGlobal;
  928. Palette: HPALETTE;
  929. {$else FPC}
  930. const
  931. Palette = 0;
  932. Data = 0;
  933. {$endif FPC}
  934. begin
  935. Result := False;
  936. if (FFormats = nil) then
  937. exit;
  938. // Attempt to paste from clipboard in image format order instead of clipboard
  939. // format order; We want to give priority to the most important image formats.
  940. try
  941. // FPC doesn't actually read from the clipboard within Open and Close so we
  942. // can't acquire it while we're reading from it. This is clearly a bug.
  943. {$ifndef FPC}
  944. Clipboard.Open;
  945. {$endif FPC}
  946. except
  947. on E: EClipboardException do
  948. exit; // Something else has the clipboard open
  949. end;
  950. try
  951. {$ifndef FPC}
  952. Palette := GetClipboardData(CF_PALETTE);
  953. {$endif FPC}
  954. for Item in FFormats do
  955. if (Supports(Item.ImageFormat, IImageFormatClipboardFormat, ImageFormatClipboard)) then
  956. begin
  957. // First let image format give it a go directly...
  958. if (ImageFormatClipboard.PasteFromClipboard(ADest)) then
  959. exit(True);
  960. // ...then try to load the individual formats
  961. for i := 0 to Clipboard.FormatCount-1 do
  962. begin
  963. ClipboardFormat := Clipboard.Formats[i];
  964. if (ImageFormatClipboard.SupportsClipboardFormat(ClipboardFormat)) then
  965. begin
  966. {$ifndef FPC}
  967. Data := GetClipboardData(ClipboardFormat);
  968. if (Data = 0) then
  969. RaiseLastOSError;
  970. {$endif FPC}
  971. if (ImageFormatClipboard.LoadFromClipboardFormat(ADest, ClipboardFormat, Data, Palette)) then
  972. Exit(True)
  973. end;
  974. end;
  975. end;
  976. // ...finally give it a last go with the individual formats via a stream
  977. for Item in FFormats do
  978. if (Supports(Item.ImageFormat, IImageFormatReader, Reader)) then
  979. begin
  980. for i := 0 to Clipboard.FormatCount-1 do
  981. begin
  982. ClipboardFormat := Clipboard.Formats[i];
  983. if (ImageFormatClipboard.SupportsClipboardFormat(ClipboardFormat)) then
  984. begin
  985. {$ifndef FPC}
  986. Stream := TClipboardMemoryStream.Create(ClipboardFormat);
  987. try
  988. {$else FPC}
  989. Stream := TMemoryStream.Create;
  990. try
  991. if (not Clipboard.GetFormat(ClipboardFormat, Stream)) then
  992. continue;
  993. {$endif FPC}
  994. Result := Reader.LoadFromStream(ADest, Stream);
  995. if (Result) then
  996. exit;
  997. finally
  998. Stream.Free;
  999. end;
  1000. end;
  1001. end;
  1002. end;
  1003. finally
  1004. {$ifndef FPC}
  1005. Clipboard.Close;
  1006. {$endif FPC}
  1007. end;
  1008. end;
  1009. //------------------------------------------------------------------------------
  1010. // IImageFormatManager
  1011. //------------------------------------------------------------------------------
  1012. function TImageFormatManager.GetAdapters: IImageFormatAdapter;
  1013. begin
  1014. Result := Self;
  1015. end;
  1016. function TImageFormatManager.GetClipboardFormats: IImageFormatClipboardFormats;
  1017. begin
  1018. Result := Self;
  1019. end;
  1020. function TImageFormatManager.GetReaders: IImageFormatReaders;
  1021. begin
  1022. Result := Self;
  1023. end;
  1024. function TImageFormatManager.GetWriters: IImageFormatWriters;
  1025. begin
  1026. Result := Self;
  1027. end;
  1028. function TImageFormatManager.ImageFormats: IImageFormats;
  1029. begin
  1030. Result := TImageFormatEnumerator.Create(FFormats, IImageFormat);
  1031. end;
  1032. function TImageFormatManager.ImageFormats(Intf: TGUID): IImageFormats;
  1033. begin
  1034. Result := TImageFormatEnumerator.Create(FFormats, Intf);
  1035. end;
  1036. {$ifndef ANONYMOUS_METHODS}
  1037. function ImageFormatItemComparer(const A, B: TImageFormatManager.TImageFormatItem): integer;
  1038. begin
  1039. Result := A.Priority - B.Priority;
  1040. end;
  1041. {$endif ANONYMOUS_METHODS}
  1042. function TImageFormatManager.RegisterImageFormat(const AImageFormat: IImageFormat; APriority: integer): integer;
  1043. var
  1044. Index: integer;
  1045. Item: TImageFormatItem;
  1046. begin
  1047. if (FFormats = nil) then
  1048. begin
  1049. FFormats := TImageFormatList.Create(TComparer<TImageFormatItem>.Construct(
  1050. {$ifdef ANONYMOUS_METHODS}
  1051. function(const A, B: TImageFormatItem): integer
  1052. begin
  1053. Result := A.Priority - B.Priority;
  1054. end
  1055. {$else ANONYMOUS_METHODS}
  1056. @ImageFormatItemComparer
  1057. {$endif ANONYMOUS_METHODS}
  1058. ));
  1059. end;
  1060. Inc(FImageFormatHandle);
  1061. Item.Priority := APriority;
  1062. Item.ImageFormat := AImageFormat;
  1063. Item.Handle := FImageFormatHandle;
  1064. FFormats.BinarySearch(Item, Index);
  1065. FFormats.Insert(Index, Item);
  1066. Result := FImageFormatHandle;
  1067. end;
  1068. procedure TImageFormatManager.UnregisterImageFormat(const AHandle: integer);
  1069. var
  1070. i: integer;
  1071. begin
  1072. if (FFormats = nil) or (AHandle <= 0) then
  1073. exit;
  1074. for i := 0 to FFormats.Count-1 do
  1075. if (FFormats[i].Handle = AHandle) then
  1076. begin
  1077. FFormats.Delete(i);
  1078. break;
  1079. end;
  1080. end;
  1081. procedure TImageFormatManager.UnregisterImageFormat(const AImageFormat: IImageFormat);
  1082. var
  1083. i: integer;
  1084. begin
  1085. if (FFormats = nil) then
  1086. exit;
  1087. for i := 0 to FFormats.Count-1 do
  1088. if (FFormats[i].ImageFormat = AImageFormat) then
  1089. begin
  1090. FFormats.Delete(i);
  1091. break;
  1092. end;
  1093. end;
  1094. {$ifdef FPC}
  1095. constructor TImageFormatManager.TImageFormatList.Create(const AComparer: IComparer<TImageFormatItem>);
  1096. begin
  1097. inherited Create;
  1098. FComparer := AComparer;
  1099. end;
  1100. function DoBinarySearch<T>(const Values: array of T; const Item: T;
  1101. out FoundIndex: Integer; const Comparer: IComparer<T>; Index, Count: Integer): Boolean;
  1102. var
  1103. L, H: Integer;
  1104. mid, cmp: Integer;
  1105. begin
  1106. if (Index < Low(Values)) or ((Index > High(Values)) and (Count > 0))
  1107. or (Index + Count - 1 > High(Values)) or (Count < 0)
  1108. or (Index + Count < 0) then
  1109. Assert(False);
  1110. if Count = 0 then
  1111. begin
  1112. FoundIndex := Index;
  1113. Exit(False);
  1114. end;
  1115. Result := False;
  1116. L := Index;
  1117. H := Index + Count - 1;
  1118. while L <= H do
  1119. begin
  1120. mid := L + (H - L) shr 1;
  1121. cmp := Comparer.Compare(Values[mid], Item);
  1122. if cmp < 0 then
  1123. L := mid + 1
  1124. else if cmp > 0 then
  1125. H := mid - 1
  1126. else
  1127. begin
  1128. repeat
  1129. Dec(mid);
  1130. until (mid < Index) or (Comparer.Compare(Values[mid], Item) <> 0);
  1131. FoundIndex := mid + 1;
  1132. Exit(True);
  1133. end;
  1134. end;
  1135. FoundIndex := L;
  1136. end;
  1137. function TImageFormatManager.TImageFormatList.BinarySearch(const Item: TImageFormatManager.TImageFormatItem; out FoundIndex: Integer): Boolean;
  1138. begin
  1139. Result := DoBinarySearch<TImageFormatManager.TImageFormatItem>(FItems, Item, FoundIndex, FComparer, 0, Count);
  1140. end;
  1141. {$endif FPC}
  1142. function TImageFormatManager.BuildFileFilter(Intf: TGUID; IncludeAll: boolean): string;
  1143. var
  1144. ImageFormat: IImageFormat;
  1145. FileInfo: IImageFormatFileInfo;
  1146. AllFilter: string;
  1147. Extensions: TDictionary<string, boolean>;
  1148. FileType: string;
  1149. Count: integer;
  1150. FileTypeCount: integer;
  1151. FileTypes: string;
  1152. begin
  1153. Result := '';
  1154. AllFilter := '';
  1155. Count := 0;
  1156. Extensions := TDictionary<string, boolean>.Create;
  1157. try
  1158. for ImageFormat in ImageFormats(Intf) do
  1159. if (Supports(ImageFormat, IImageFormatFileInfo, FileInfo)) then
  1160. begin
  1161. FileTypeCount := 0;
  1162. FileTypes := '';
  1163. for FileType in FileInfo.ImageFormatFileTypes do
  1164. begin
  1165. if (FileType = '') then
  1166. continue;
  1167. // Avoid duplicate extensions
  1168. if (Extensions.ContainsKey(FileType.ToUpper)) then
  1169. continue;
  1170. Extensions.Add(FileType.ToUpper, False);
  1171. if (FileTypeCount > 0) then
  1172. FileTypes := FileTypes + ';';
  1173. FileTypes := FileTypes + '*.' + FileType;
  1174. Inc(FileTypeCount);
  1175. end;
  1176. if (FileTypeCount = 0) then
  1177. continue;
  1178. Result := Result + Format('%0:s (%1:s)|%1:s|', [FileInfo.ImageFormatDescription, FileTypes]);
  1179. Inc(Count);
  1180. if (IncludeAll) then
  1181. begin
  1182. if (AllFilter <> '') then
  1183. AllFilter := AllFilter + ';';
  1184. AllFilter := AllFilter + Format('%s', [FileTypes]);
  1185. end;
  1186. end;
  1187. if (Result <> '') then
  1188. SetLength(Result, Length(Result)-1);
  1189. finally
  1190. Extensions.Free;
  1191. end;
  1192. if (AllFilter <> '') and (Count > 1) then
  1193. Result := Format('%0:s (%1:s)|%1:s|', [sAllFilter, AllFilter]) + Result;
  1194. end;
  1195. //------------------------------------------------------------------------------
  1196. // TImageFormatManager.TImageFormatEnumerator
  1197. //------------------------------------------------------------------------------
  1198. constructor TImageFormatManager.TImageFormatEnumerator.Create(AList: TImageFormatList; const AGUID: TGUID);
  1199. begin
  1200. inherited Create;
  1201. FList := AList;
  1202. FGUID := AGUID;
  1203. FIndex := -1;
  1204. end;
  1205. function TImageFormatManager.TImageFormatEnumerator.GetCurrent: IImageFormat;
  1206. begin
  1207. Result := FList[FIndex].ImageFormat;
  1208. end;
  1209. function TImageFormatManager.TImageFormatEnumerator.GetEnumerator: IImageFormatEnumerator;
  1210. begin
  1211. Result := Self;
  1212. end;
  1213. function TImageFormatManager.TImageFormatEnumerator.MoveNext: Boolean;
  1214. begin
  1215. if (FList = nil) or (FIndex >= FList.Count) then
  1216. exit(False);
  1217. Inc(FIndex);
  1218. while (FIndex < FList.Count) and (not Supports(GetCurrent, FGUID)) do
  1219. Inc(FIndex);
  1220. Result := (FIndex < FList.Count);
  1221. end;
  1222. //------------------------------------------------------------------------------
  1223. //
  1224. // ImageFormatManager
  1225. //
  1226. //------------------------------------------------------------------------------
  1227. function ImageFormatManager: IImageFormatManager;
  1228. begin
  1229. Result := TImageFormatManager.Instance;
  1230. end;
  1231. //------------------------------------------------------------------------------
  1232. //------------------------------------------------------------------------------
  1233. //------------------------------------------------------------------------------
  1234. initialization
  1235. finalization
  1236. // FImageFormatManager := nil;
  1237. end.