uraw.pas 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // SPDX-License-Identifier: GPL-3.0-only
  2. unit URaw;
  3. {$mode objfpc}{$H+}
  4. interface
  5. uses
  6. Classes, SysUtils, FPimage, BGRABitmap, BGRABitmapTypes, Controls;
  7. type
  8. TRawExtension = record
  9. ext: string;
  10. brand: string;
  11. end;
  12. const
  13. RawFileExtensions: array[0..28] of TRawExtension =
  14. ((ext:'3fr'; brand:'Hasselblad'),
  15. (ext:'ari'; brand:'Arri_Alexa'),
  16. (ext:'arw;srf;sr2'; brand:'Sony'),
  17. (ext:'bay'; brand:'Casio'),
  18. (ext:'braw'; brand:'Blackmagic Design'),
  19. (ext:'cri'; brand:'Cintel'),
  20. (ext:'crw;cr2;cr3'; brand:'Canon'),
  21. (ext:'cap;iiq;eip'; brand:'Phase_One'),
  22. (ext:'dcs;dcr;drf;k25;kdc'; brand:'Kodak'),
  23. (ext:'dng'; brand:'Adobe'),
  24. (ext:'erf'; brand:'Epson'),
  25. (ext:'fff'; brand:'Imacon/Hasselblad raw'),
  26. (ext:'gpr'; brand:'GoPro'),
  27. (ext:'mef'; brand:'Mamiya'),
  28. (ext:'mdc'; brand:'Minolta, Agfa'),
  29. (ext:'mos'; brand:'Leaf'),
  30. (ext:'mrw'; brand:'Minolta, Konica Minolta'),
  31. (ext:'nef;nrw'; brand:'Nikon'),
  32. (ext:'orf'; brand:'Olympus'),
  33. (ext:'pef;ptx'; brand:'Pentax'),
  34. (ext:'pxn'; brand:'Logitech'),
  35. (ext:'R3D'; brand:'RED Digital Cinema'),
  36. (ext:'raf'; brand:'Fuji'),
  37. (ext:'raw'; brand:'Panasonic/Leica'),
  38. (ext:'rw2'; brand:'Panasonic'),
  39. (ext:'rwl;dng'; brand:'Leica'),
  40. (ext:'rwz'; brand:'Rawzor'),
  41. (ext:'srw'; brand:'Samsung'),
  42. (ext:'x3f'; brand:'Sigma'));
  43. var
  44. AllRawExtensions: string;
  45. function GetRawStreamThumbnail(AStream: TStream; AWidth,AHeight: integer;
  46. ABackColor: TBGRAPixel; ACheckers: boolean; ADest: TBGRABitmap= nil): TBGRABitmap;
  47. function GetRawStreamImage(AStream: TStream): TBGRABitmap;
  48. function IsRawFilename(AFilename: string): boolean;
  49. function GetRawFileImage(AFilename: string): TBGRABitmap;
  50. implementation
  51. uses process, BGRAThumbnail, UResourceStrings, UFileSystem, Forms, LazFileUtils;
  52. var
  53. RawCriticalSection: TRTLCriticalSection;
  54. function GetAllRawExtensions: string;
  55. var
  56. i: Integer;
  57. begin
  58. result := '';
  59. for i := low(RawFileExtensions) to high(RawFileExtensions) do
  60. begin
  61. if result <> '' then result += ';';
  62. result += RawFileExtensions[i].ext;
  63. end;
  64. end;
  65. procedure RunDCRaw(AOptions: array of string;
  66. AInputStream, AOutputStream: TStream);
  67. var
  68. tempName,tempOutName: String;
  69. s: TFileStream;
  70. p: TProcess;
  71. available: DWord;
  72. i: Integer;
  73. consoleOut, tiffOut: boolean;
  74. begin
  75. tempName := '';
  76. p := nil;
  77. try
  78. EnterCriticalsection(RawCriticalSection);
  79. try
  80. tempName := GetTempFileName;
  81. s := TFileStream.Create(tempName, fmCreate);
  82. try
  83. s.CopyFrom(AInputStream, AInputStream.Size);
  84. finally
  85. s.Free;
  86. end;
  87. finally
  88. LeaveCriticalsection(RawCriticalSection);
  89. end;
  90. p := TProcess.Create(nil);
  91. try
  92. p.Options:= p.Options+[poStderrToOutPut, poNoConsole];
  93. {$IFDEF WINDOWS}
  94. p.CurrentDirectory:= ExtractFilePath(Application.ExeName);
  95. p.Executable:= 'dcraw.exe';
  96. if not FileExistsUTF8(p.CurrentDirectory+p.Executable) then
  97. raise exception.Create('Cannot find DCRaw binary');
  98. {$ELSE}
  99. p.Executable:= 'dcraw';
  100. {$ENDIF}
  101. consoleOut := false;
  102. tiffOut := false;
  103. for i := 0 to High(AOptions) do
  104. begin
  105. p.Parameters.Add(AOptions[i]);
  106. if AOptions[i] = '-c' then consoleOut := true;
  107. if AOptions[i] = '-T' then tiffOut := true;
  108. end;
  109. p.Parameters.Add(tempName);
  110. if consoleOut then
  111. begin
  112. p.Options:= p.Options+[poUsePipes];
  113. p.PipeBufferSize:= 524288;
  114. p.Execute;
  115. while p.Running do
  116. begin
  117. available:=P.Output.NumBytesAvailable;
  118. if available > 0 then
  119. AOutputStream.CopyFrom(P.Output, available)
  120. else
  121. sleep(30);
  122. end;
  123. available:=P.Output.NumBytesAvailable;
  124. if available > 0 then
  125. AOutputStream.CopyFrom(P.Output, available);
  126. end else
  127. begin
  128. if tiffOut then
  129. tempOutName := ChangeFileExt(tempName, '.tiff')
  130. else
  131. tempOutName := ChangeFileExt(tempName, '.ppm');
  132. p.Execute;
  133. try
  134. p.WaitOnExit;
  135. if not FileExists(tempOutName) then
  136. raise exception.Create(rsErrorDecodingRaw);
  137. s := TFileStream.Create(tempOutName, fmOpenRead);
  138. try
  139. AOutputStream.CopyFrom(s, s.Size);
  140. finally
  141. s.Free;
  142. end;
  143. finally
  144. if FileExists(tempOutName) then DeleteFile(tempOutName);
  145. end;
  146. end;
  147. finally
  148. FreeAndNil(p);
  149. end;
  150. finally
  151. if FileExists(tempName) then DeleteFile(tempName);
  152. end;
  153. end;
  154. function GetRawStreamThumbnail(AStream: TStream; AWidth, AHeight: integer;
  155. ABackColor: TBGRAPixel; ACheckers: boolean; ADest: TBGRABitmap): TBGRABitmap;
  156. var
  157. thumbData: TMemoryStream;
  158. begin
  159. result := nil;
  160. thumbData := TMemoryStream.Create;
  161. try
  162. RunDCRaw(['-c','-e'],AStream,thumbData);
  163. thumbData.Position:= 0;
  164. result := GetStreamThumbnail(thumbData, AWidth,AHeight, ABackColor,ACheckers,'',ADest);
  165. finally
  166. thumbData.Free;
  167. end;
  168. end;
  169. function GetRawStreamImage(AStream: TStream): TBGRABitmap;
  170. var
  171. imageData: TMemoryStream;
  172. prevCursor: TCursor;
  173. begin
  174. prevCursor := Screen.Cursor;
  175. Screen.Cursor:= crHourGlass;
  176. result := nil;
  177. imageData := TMemoryStream.Create;
  178. try
  179. RunDCRaw(['-T'],AStream,imageData);
  180. imageData.Position:= 0;
  181. result := TBGRABitmap.Create(imageData);
  182. finally
  183. imageData.Free;
  184. Screen.Cursor:= prevCursor;
  185. end;
  186. end;
  187. function IsRawFilename(AFilename: string): boolean;
  188. var
  189. ext: String;
  190. begin
  191. ext := LowerCase(ExtractFileExt(AFilename));
  192. delete(ext,1,1);
  193. result := Pos(';'+ext+';',';'+AllRawExtensions+';') <> 0;
  194. end;
  195. function GetRawFileImage(AFilename: string): TBGRABitmap;
  196. var
  197. s: TStream;
  198. begin
  199. s := FileManager.CreateFileStream(AFilename, fmOpenRead);
  200. result := nil;
  201. try
  202. result := GetRawStreamImage(s);
  203. finally
  204. s.Free;
  205. end;
  206. end;
  207. initialization
  208. AllRawExtensions := GetAllRawExtensions;
  209. InitCriticalSection(RawCriticalSection);
  210. finalization
  211. DoneCriticalsection(RawCriticalSection);
  212. end.