ImagingSDL.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. {
  2. $Id: ImagingSDL.pas,v 1.2 2006/10/26 13:29:28 galfar Exp $
  3. Vampyre Imaging Library
  4. by Marek Mauder ([email protected])
  5. 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
  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 for
  12. the specific language governing rights and limitations under the License.
  13. Alternatively, the contents of this file may be used under the terms of the
  14. GNU Lesser General Public License (the "LGPL License"), in which case the
  15. provisions of the LGPL License are applicable instead of those above.
  16. If you wish to allow use of your version of this file only under the terms
  17. of the LGPL License and not to allow others to use your version of this file
  18. under the MPL, indicate your decision by deleting the provisions above and
  19. replace them with the notice and other provisions required by the LGPL
  20. License. If you do not delete the provisions above, a recipient may use
  21. your version of this file under either the MPL or the LGPL License.
  22. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
  23. }
  24. { This unit contains functions for loading/saving SDL surfaces using Imaging
  25. and for converting images to surfaces and vice versa.}
  26. unit ImagingSDL;
  27. {$I ImagingOptions.inc}
  28. interface
  29. uses
  30. Classes, sdl, ImagingTypes, Imaging, ImagingUtility;
  31. type
  32. { This SDL type is redefined here so ImagingExport unit does not
  33. need sdl unit in the uses list.}
  34. PSDL_Surface = sdl.PSDL_Surface;
  35. { LoadSDLSurfaceFromFile and similar functions use SDL_SWSURFACE as Flags when creating
  36. SDL surface. If you want other Flags to be used load image by standard
  37. LoadImageFromFile and similar functions and then call CreateSDLSurfaceFromImage
  38. which has more options.}
  39. { Creates SDL surface from image in file in format supported by Imaging.}
  40. function LoadSDLSurfaceFromFile(const FileName: string): PSDL_Surface;
  41. { Creates SDL surface from image in stream in format supported by Imaging.}
  42. function LoadSDLSurfaceFromStream(Stream: TStream): PSDL_Surface;
  43. { Creates SDL surface from image in memory in format supported by Imaging.}
  44. function LoadSDLSurfaceFromMemory(Data: Pointer; Size: LongInt): PSDL_Surface;
  45. { Converts image to SDL surface. Flags is used when creating SDL surface
  46. using SDL_CreateRGBSurface and is passed to it. OverrideFormat can be
  47. used to convert image to specified format before SDL surface is created,
  48. ifUnknown means no conversion.}
  49. function CreateSDLSurfaceFromImage(const ImageData: TImageData;
  50. Flags: LongWord; OverrideFormat: TImageFormat = ifUnknown): PSDL_Surface;
  51. { Saves SDL surface to file in one of the formats supported by Imaging.}
  52. function SaveSDLSurfaceToFile(const FileName: string; Surface: PSDL_Surface): Boolean;
  53. { Saves SDL surface to stream in one of the formats supported by Imaging defined by Ext.}
  54. function SaveSDLSurfaceToStream(const Ext: string; Stream: TStream; Surface: PSDL_Surface): Boolean;
  55. { Saves SDL surface to memory in one of the formats supported by Imaging defined
  56. by Ext. Size must contain size of available memory before the function
  57. is called and memory size taken up by the image is returned in this parameter.}
  58. function SaveSDLSurfaceToMemory(const Ext: string; Data: Pointer; var Size: LongInt; Surface: PSDL_Surface): Boolean;
  59. { Converts SDL surface to TImageData structure. OverrideFormat can be
  60. used to convert output image to the specified format rather than
  61. use the format taken from SDL surface, ifUnknown means no conversion.}
  62. function CreateImageFromSDLSurface(Surface: PSDL_Surface; var ImageData: TImageData;
  63. OverrideFormat: TImageFormat = ifUnknown): Boolean;
  64. implementation
  65. const
  66. DefaultFlags = SDL_SWSURFACE;
  67. function Iff(Condition: Boolean; const TruePart, FalsePart: TImageFormat): TImageFormat; overload;
  68. begin
  69. if Condition then
  70. Result := TruePart
  71. else
  72. Result := FalsePart;
  73. end;
  74. function LoadSDLSurfaceFromFile(const FileName: string): PSDL_Surface;
  75. var
  76. ImageData: TImageData;
  77. begin
  78. InitImage(ImageData);
  79. if LoadImageFromFile(FileName, ImageData) then
  80. Result := CreateSDLSurfaceFromImage(ImageData, DefaultFlags)
  81. else
  82. Result := nil;
  83. FreeImage(ImageData);
  84. end;
  85. function LoadSDLSurfaceFromStream(Stream: TStream): PSDL_Surface;
  86. var
  87. ImageData: TImageData;
  88. begin
  89. InitImage(ImageData);
  90. if LoadImageFromStream(Stream, ImageData) then
  91. Result := CreateSDLSurfaceFromImage(ImageData, DefaultFlags)
  92. else
  93. Result := nil;
  94. FreeImage(ImageData);
  95. end;
  96. function LoadSDLSurfaceFromMemory(Data: Pointer; Size: LongInt): PSDL_Surface;
  97. var
  98. ImageData: TImageData;
  99. begin
  100. InitImage(ImageData);
  101. if LoadImageFromMemory(Data, Size, ImageData) then
  102. Result := CreateSDLSurfaceFromImage(ImageData, DefaultFlags)
  103. else
  104. Result := nil;
  105. FreeImage(ImageData);
  106. end;
  107. function CreateSDLSurfaceFromImage(const ImageData: TImageData;
  108. Flags: LongWord; OverrideFormat: TImageFormat): PSDL_Surface;
  109. var
  110. WorkData: TImageData;
  111. Info: TImageFormatInfo;
  112. ConvFormat: TImageFormat;
  113. AMask, RMask, GMask, BMask: LongWord;
  114. I, LineBytes: LongInt;
  115. procedure DetermineSDLMasks(var AMask, RMask, GMask, BMask: LongWord);
  116. begin
  117. if Info.UsePixelFormat then
  118. begin
  119. AMask := Info.PixelFormat.ABitMask;
  120. RMask := Info.PixelFormat.RBitMask;
  121. GMask := Info.PixelFormat.GBitMask;
  122. BMask := Info.PixelFormat.BBitMask;
  123. end
  124. else
  125. begin
  126. AMask := IffUnsigned(Info.HasAlphaChannel, $FF000000, 0);
  127. RMask := $00FF0000;
  128. GMask := $0000FF00;
  129. BMask := $000000FF;
  130. end;
  131. end;
  132. begin
  133. Result := nil;
  134. if TestImage(ImageData) then
  135. begin
  136. CloneImage(ImageData, WorkData);
  137. // Image is converted to override format
  138. if OverrideFormat <> ifUnknown then
  139. ConvertImage(WorkData, OverrideFormat);
  140. GetImageFormatInfo(WorkData.Format, Info);
  141. // Image is first converted to format supported by SDL
  142. if Info.IsFloatingPoint or Info.IsSpecial then
  143. ConvFormat := ifA8R8G8B8
  144. else
  145. if Info.UsePixelFormat then
  146. begin
  147. if Info.BytesPerPixel < 2 then
  148. ConvFormat := Iff(Info.HasAlphaChannel, ifA4R4G4B4, ifR5G6B5)
  149. else
  150. ConvFormat := WorkData.Format;
  151. end
  152. else
  153. if Info.IsIndexed then
  154. ConvFormat := ifIndex8
  155. else
  156. ConvFormat := Iff(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8);
  157. ConvertImage(WorkData, ConvFormat);
  158. GetImageFormatInfo(WorkData.Format, Info);
  159. // Channel masks are determined based on image's format,
  160. // only 8/16/24/32bit images should be here now
  161. DetermineSDLMasks(AMask, RMask, GMask, BMask);
  162. // SDL surface is created
  163. Result := SDL_CreateRGBSurface(Flags, WorkData.Width, WorkData.Height,
  164. Info.BytesPerPixel * 8, RMask, GMask, BMask, AMask);
  165. if Result <> nil then
  166. begin
  167. LineBytes := Info.BytesPerPixel * WorkData.Width;
  168. if SDL_MustLock(Result) then
  169. SDL_LockSurface(Result);
  170. // Pixels of image are copied to SDL surface
  171. if LineBytes = Result.pitch then
  172. Move(WorkData.Bits^, Result.pixels^, WorkData.Size)
  173. else
  174. for I := 0 to WorkData.Height - 1 do
  175. Move(PByteArray(WorkData.Bits)[I * LineBytes],
  176. PByteArray(Result.pixels)[I * Result.pitch], LineBytes);
  177. if SDL_MustLock(Result) then
  178. SDL_UnlockSurface(Result);
  179. // If surface is in indexed format, palette is copied
  180. if (Info.Format = ifIndex8) and (Result.format.palette <> nil) then
  181. begin
  182. Result.format.palette.ncolors := Info.PaletteEntries;
  183. for I := 0 to Info.PaletteEntries - 1 do
  184. begin
  185. Result.format.palette.colors[I].r := WorkData.Palette[I].R;
  186. Result.format.palette.colors[I].g := WorkData.Palette[I].G;
  187. Result.format.palette.colors[I].b := WorkData.Palette[I].B;
  188. Result.format.palette.colors[I].unused := 0;
  189. end;
  190. end;
  191. end;
  192. FreeImage(WorkData);
  193. end;
  194. end;
  195. function SaveSDLSurfaceToFile(const FileName: string; Surface: PSDL_Surface): Boolean;
  196. var
  197. ImageData: TImageData;
  198. begin
  199. Result := False;
  200. if CreateImageFromSDLSurface(Surface, ImageData) then
  201. begin
  202. Result := SaveImageToFile(FileName, ImageData);
  203. FreeImage(ImageData);
  204. end;
  205. end;
  206. function SaveSDLSurfaceToStream(const Ext: string; Stream: TStream; Surface: PSDL_Surface): Boolean;
  207. var
  208. ImageData: TImageData;
  209. begin
  210. Result := False;
  211. if CreateImageFromSDLSurface(Surface, ImageData) then
  212. begin
  213. Result := SaveImageToStream(Ext, Stream, ImageData);
  214. FreeImage(ImageData);
  215. end;
  216. end;
  217. function SaveSDLSurfaceToMemory(const Ext: string; Data: Pointer; var Size: LongInt; Surface: PSDL_Surface): Boolean;
  218. var
  219. ImageData: TImageData;
  220. begin
  221. Result := False;
  222. if CreateImageFromSDLSurface(Surface, ImageData) then
  223. begin
  224. Result := SaveImageToMemory(Ext, Data, Size, ImageData);
  225. FreeImage(ImageData);
  226. end;
  227. end;
  228. function CreateImageFromSDLSurface(Surface: PSDL_Surface; var ImageData: TImageData;
  229. OverrideFormat: TImageFormat): Boolean;
  230. const
  231. SDL_A8R8G8B8Format: TSDL_PixelFormat = (palette: nil; BitsPerPixel: 32;
  232. BytesPerPixel: 4; Rloss: 0; Gloss: 0; Bloss: 0; Aloss: 0;
  233. Rshift: 16; Gshift: 8; Bshift: 0; Ashift: 24;
  234. Rmask: $00FF0000; Gmask: $0000FF00; Bmask: $000000FF; Amask: $FF000000;
  235. colorkey: 0; alpha: $FF);
  236. var
  237. Format: TImageFormat;
  238. Converted: PSDL_Surface;
  239. Info: TImageFormatInfo;
  240. I, LineBytes: LongInt;
  241. function DetermineImageFormat: TImageFormat;
  242. var
  243. Fmt: TImageFormat;
  244. begin
  245. Result := ifUnknown;
  246. case Surface.format.BitsPerPixel of
  247. 8: Result := ifIndex8;
  248. 16:
  249. begin
  250. // go trough 16bit formats supported by Imaging and
  251. // if there is one that matches SDL format's masks then use it
  252. for Fmt := ifR5G6B5 to ifX4R4G4B4 do
  253. begin
  254. GetImageFormatInfo(Fmt, Info);
  255. if (Info.PixelFormat.ABitMask = Surface.format.AMask) and
  256. (Info.PixelFormat.RBitMask = Surface.format.RMask) and
  257. (Info.PixelFormat.GBitMask = Surface.format.GMask) and
  258. (Info.PixelFormat.BBitMask = Surface.format.BMask) then
  259. begin
  260. Result := Fmt;
  261. Break;
  262. end;
  263. end;
  264. end;
  265. 24:
  266. begin
  267. if (Surface.format.RMask = $FF0000) and
  268. (Surface.format.GMask = $00FF00) and
  269. (Surface.format.BMask = $0000FF) then
  270. Result := ifR8G8B8;
  271. end;
  272. 32:
  273. begin
  274. if (Surface.format.RMask = $00FF0000) and
  275. (Surface.format.GMask = $0000FF00) and
  276. (Surface.format.BMask = $000000FF) then
  277. if (Surface.format.AMask = $FF000000) then
  278. Result := ifA8R8G8B8
  279. else
  280. Result := ifX8R8G8B8
  281. end;
  282. end;
  283. end;
  284. begin
  285. Result := False;
  286. FreeImage(ImageData);
  287. // See if surface is in format supported by Imaging and if it is
  288. // not then it is converted to A8R8G8B8
  289. Format := DetermineImageFormat;
  290. if Format = ifUnknown then
  291. begin
  292. Converted := SDL_ConvertSurface(Surface, @SDL_A8R8G8B8Format, SDL_SWSURFACE);
  293. Format := ifA8R8G8B8;
  294. end
  295. else
  296. Converted := Surface;
  297. if (Converted <> nil) and NewImage(Converted.w, Converted.h, Format, ImageData) then
  298. begin
  299. GetImageFormatInfo(Format, Info);
  300. LineBytes := Info.BytesPerPixel * ImageData.Width;
  301. if SDL_MustLock(Converted) then
  302. SDL_LockSurface(Converted);
  303. // New image is created and pixels are copied from SDL surface
  304. if LineBytes = Converted.pitch then
  305. Move(Converted.pixels^, ImageData.Bits^, ImageData.Size)
  306. else
  307. for I := 0 to ImageData.Height - 1 do
  308. Move(PByteArray(Converted.pixels)[I * Converted.pitch],
  309. PByteArray(ImageData.Bits)[I * LineBytes], LineBytes);
  310. if SDL_MustLock(Converted) then
  311. SDL_UnlockSurface(Converted);
  312. // Copy palette if necessary
  313. // If surface is in indexed format, palette is copied
  314. if (Info.Format = ifIndex8) and (Converted.format.palette <> nil) then
  315. begin
  316. for I := 0 to Min(Info.PaletteEntries, Converted.format.palette.ncolors) - 1 do
  317. begin
  318. ImageData.Palette[I].A := 255;
  319. ImageData.Palette[I].R := Converted.format.palette.colors[I].r;
  320. ImageData.Palette[I].G := Converted.format.palette.colors[I].g;
  321. ImageData.Palette[I].B := Converted.format.palette.colors[I].b;
  322. end;
  323. end;
  324. // Image is converted to override format
  325. if OverrideFormat <> ifUnknown then
  326. ConvertImage(ImageData, OverrideFormat);
  327. Result := True;
  328. end;
  329. if Converted <> Surface then
  330. SDL_FreeSurface(Converted);
  331. end;
  332. {
  333. File Notes:
  334. -- TODOS ----------------------------------------------------
  335. - nothing now
  336. -- 0.15 Changes/Bug Fixes -----------------------------------
  337. - unit created and initial stuff added
  338. }
  339. end.