| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- {
- Vampyre Imaging Library
- by Marek Mauder
- https://github.com/galfar/imaginglib
- https://imaginglib.sourceforge.io
- - - - - -
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at https://mozilla.org/MPL/2.0.
- }
- { This unit contains functions for loading/saving SDL surfaces using Imaging
- and for converting images to surfaces and vice versa.}
- unit ImagingSdl;
- {$I ImagingOptions.inc}
- interface
- uses
- Classes, sdl, ImagingTypes, Imaging, ImagingUtility;
- type
- { This SDL type is redefined here so ImagingExport unit does not
- need sdl unit in the uses list.}
- PSDL_Surface = sdl.PSDL_Surface;
- { LoadSDLSurfaceFromFile and similar functions use SDL_SWSURFACE as Flags when creating
- SDL surface. If you want other Flags to be used load image by standard
- LoadImageFromFile and similar functions and then call CreateSDLSurfaceFromImage
- which has more options.}
- { Creates SDL surface from image in file in format supported by Imaging.}
- function LoadSDLSurfaceFromFile(const FileName: string): PSDL_Surface;
- { Creates SDL surface from image in stream in format supported by Imaging.}
- function LoadSDLSurfaceFromStream(Stream: TStream): PSDL_Surface;
- { Creates SDL surface from image in memory in format supported by Imaging.}
- function LoadSDLSurfaceFromMemory(Data: Pointer; Size: LongInt): PSDL_Surface;
- { Converts image to SDL surface. Flags is used when creating SDL surface
- using SDL_CreateRGBSurface and is passed to it. OverrideFormat can be
- used to convert image to specified format before SDL surface is created,
- ifUnknown means no conversion.}
- function CreateSDLSurfaceFromImage(const ImageData: TImageData;
- Flags: UInt32; OverrideFormat: TImageFormat = ifUnknown): PSDL_Surface;
- { Saves SDL surface to file in one of the formats supported by Imaging.}
- function SaveSDLSurfaceToFile(const FileName: string; Surface: PSDL_Surface): Boolean;
- { Saves SDL surface to stream in one of the formats supported by Imaging defined by Ext.}
- function SaveSDLSurfaceToStream(const Ext: string; Stream: TStream; Surface: PSDL_Surface): Boolean;
- { Saves SDL surface to memory in one of the formats supported by Imaging defined
- by Ext. Size must contain size of available memory before the function
- is called and memory size taken up by the image is returned in this parameter.}
- function SaveSDLSurfaceToMemory(const Ext: string; Data: Pointer; var Size: LongInt; Surface: PSDL_Surface): Boolean;
- { Converts SDL surface to TImageData structure. OverrideFormat can be
- used to convert output image to the specified format rather than
- use the format taken from SDL surface, ifUnknown means no conversion.}
- function CreateImageFromSDLSurface(Surface: PSDL_Surface; var ImageData: TImageData;
- OverrideFormat: TImageFormat = ifUnknown): Boolean;
- implementation
- const
- DefaultFlags = SDL_SWSURFACE;
- function Iff(Condition: Boolean; const TruePart, FalsePart: TImageFormat): TImageFormat; overload;
- begin
- if Condition then
- Result := TruePart
- else
- Result := FalsePart;
- end;
- function LoadSDLSurfaceFromFile(const FileName: string): PSDL_Surface;
- var
- ImageData: TImageData;
- begin
- InitImage(ImageData);
- if LoadImageFromFile(FileName, ImageData) then
- Result := CreateSDLSurfaceFromImage(ImageData, DefaultFlags)
- else
- Result := nil;
- FreeImage(ImageData);
- end;
- function LoadSDLSurfaceFromStream(Stream: TStream): PSDL_Surface;
- var
- ImageData: TImageData;
- begin
- InitImage(ImageData);
- if LoadImageFromStream(Stream, ImageData) then
- Result := CreateSDLSurfaceFromImage(ImageData, DefaultFlags)
- else
- Result := nil;
- FreeImage(ImageData);
- end;
- function LoadSDLSurfaceFromMemory(Data: Pointer; Size: LongInt): PSDL_Surface;
- var
- ImageData: TImageData;
- begin
- InitImage(ImageData);
- if LoadImageFromMemory(Data, Size, ImageData) then
- Result := CreateSDLSurfaceFromImage(ImageData, DefaultFlags)
- else
- Result := nil;
- FreeImage(ImageData);
- end;
- function CreateSDLSurfaceFromImage(const ImageData: TImageData;
- Flags: UInt32; OverrideFormat: TImageFormat): PSDL_Surface;
- var
- WorkData: TImageData;
- Info: TImageFormatInfo;
- ConvFormat: TImageFormat;
- AMask, RMask, GMask, BMask: UInt32;
- I, LineBytes: LongInt;
- procedure DetermineSDLMasks(var AMask, RMask, GMask, BMask: UInt32);
- begin
- if Info.UsePixelFormat then
- begin
- AMask := Info.PixelFormat.ABitMask;
- RMask := Info.PixelFormat.RBitMask;
- GMask := Info.PixelFormat.GBitMask;
- BMask := Info.PixelFormat.BBitMask;
- end
- else
- begin
- AMask := IffUnsigned(Info.HasAlphaChannel, $FF000000, 0);
- RMask := $00FF0000;
- GMask := $0000FF00;
- BMask := $000000FF;
- end;
- end;
- begin
- Result := nil;
- if TestImage(ImageData) then
- begin
- InitImage(WorkData);
- CloneImage(ImageData, WorkData);
- // Image is converted to override format
- if OverrideFormat <> ifUnknown then
- ConvertImage(WorkData, OverrideFormat);
- GetImageFormatInfo(WorkData.Format, Info);
- // Image is first converted to format supported by SDL
- if Info.IsFloatingPoint or Info.IsSpecial then
- ConvFormat := ifA8R8G8B8
- else
- if Info.UsePixelFormat then
- begin
- if Info.BytesPerPixel < 2 then
- ConvFormat := Iff(Info.HasAlphaChannel, ifA4R4G4B4, ifR5G6B5)
- else
- ConvFormat := WorkData.Format;
- end
- else
- if Info.IsIndexed then
- ConvFormat := ifIndex8
- else
- ConvFormat := Iff(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8);
- ConvertImage(WorkData, ConvFormat);
- GetImageFormatInfo(WorkData.Format, Info);
- // Channel masks are determined based on image's format,
- // only 8/16/24/32bit images should be here now
- DetermineSDLMasks(AMask, RMask, GMask, BMask);
- // SDL surface is created
- Result := SDL_CreateRGBSurface(Flags, WorkData.Width, WorkData.Height,
- Info.BytesPerPixel * 8, RMask, GMask, BMask, AMask);
- if Result <> nil then
- begin
- LineBytes := Info.BytesPerPixel * WorkData.Width;
- if SDL_MustLock(Result) then
- SDL_LockSurface(Result);
- // Pixels of image are copied to SDL surface
- if LineBytes = Result.pitch then
- Move(WorkData.Bits^, Result.pixels^, WorkData.Size)
- else
- for I := 0 to WorkData.Height - 1 do
- Move(PByteArray(WorkData.Bits)[I * LineBytes],
- PByteArray(Result.pixels)[I * Result.pitch], LineBytes);
- if SDL_MustLock(Result) then
- SDL_UnlockSurface(Result);
- // If surface is in indexed format, palette is copied
- if (Info.Format = ifIndex8) and (Result.format.palette <> nil) then
- begin
- Result.format.palette.ncolors := Info.PaletteEntries;
- for I := 0 to Info.PaletteEntries - 1 do
- begin
- Result.format.palette.colors[I].r := WorkData.Palette[I].R;
- Result.format.palette.colors[I].g := WorkData.Palette[I].G;
- Result.format.palette.colors[I].b := WorkData.Palette[I].B;
- Result.format.palette.colors[I].unused := 0;
- end;
- end;
- end;
- FreeImage(WorkData);
- end;
- end;
- function SaveSDLSurfaceToFile(const FileName: string; Surface: PSDL_Surface): Boolean;
- var
- ImageData: TImageData;
- begin
- Result := False;
- if CreateImageFromSDLSurface(Surface, ImageData) then
- begin
- Result := SaveImageToFile(FileName, ImageData);
- FreeImage(ImageData);
- end;
- end;
- function SaveSDLSurfaceToStream(const Ext: string; Stream: TStream; Surface: PSDL_Surface): Boolean;
- var
- ImageData: TImageData;
- begin
- Result := False;
- if CreateImageFromSDLSurface(Surface, ImageData) then
- begin
- Result := SaveImageToStream(Ext, Stream, ImageData);
- FreeImage(ImageData);
- end;
- end;
- function SaveSDLSurfaceToMemory(const Ext: string; Data: Pointer; var Size: LongInt; Surface: PSDL_Surface): Boolean;
- var
- ImageData: TImageData;
- begin
- Result := False;
- if CreateImageFromSDLSurface(Surface, ImageData) then
- begin
- Result := SaveImageToMemory(Ext, Data, Size, ImageData);
- FreeImage(ImageData);
- end;
- end;
- function CreateImageFromSDLSurface(Surface: PSDL_Surface; var ImageData: TImageData;
- OverrideFormat: TImageFormat): Boolean;
- const
- SDL_A8R8G8B8Format: TSDL_PixelFormat = (palette: nil; BitsPerPixel: 32;
- BytesPerPixel: 4; Rloss: 0; Gloss: 0; Bloss: 0; Aloss: 0;
- Rshift: 16; Gshift: 8; Bshift: 0; Ashift: 24;
- Rmask: $00FF0000; Gmask: $0000FF00; Bmask: $000000FF; Amask: $FF000000;
- colorkey: 0; alpha: $FF);
- var
- Format: TImageFormat;
- Converted: PSDL_Surface;
- Info: TImageFormatInfo;
- I, LineBytes: LongInt;
- function DetermineImageFormat: TImageFormat;
- var
- Fmt: TImageFormat;
- begin
- Result := ifUnknown;
- case Surface.format.BitsPerPixel of
- 8: Result := ifIndex8;
- 16:
- begin
- // go trough 16bit formats supported by Imaging and
- // if there is one that matches SDL format's masks then use it
- for Fmt := ifR5G6B5 to ifX4R4G4B4 do
- begin
- GetImageFormatInfo(Fmt, Info);
- if (Info.PixelFormat.ABitMask = Surface.format.AMask) and
- (Info.PixelFormat.RBitMask = Surface.format.RMask) and
- (Info.PixelFormat.GBitMask = Surface.format.GMask) and
- (Info.PixelFormat.BBitMask = Surface.format.BMask) then
- begin
- Result := Fmt;
- Break;
- end;
- end;
- end;
- 24:
- begin
- if (Surface.format.RMask = $FF0000) and
- (Surface.format.GMask = $00FF00) and
- (Surface.format.BMask = $0000FF) then
- Result := ifR8G8B8;
- end;
- 32:
- begin
- if (Surface.format.RMask = $00FF0000) and
- (Surface.format.GMask = $0000FF00) and
- (Surface.format.BMask = $000000FF) then
- if (Surface.format.AMask = $FF000000) then
- Result := ifA8R8G8B8
- else
- Result := ifX8R8G8B8
- end;
- end;
- end;
- begin
- Result := False;
- FreeImage(ImageData);
- // See if surface is in format supported by Imaging and if it is
- // not then it is converted to A8R8G8B8
- Format := DetermineImageFormat;
- if Format = ifUnknown then
- begin
- Converted := SDL_ConvertSurface(Surface, @SDL_A8R8G8B8Format, SDL_SWSURFACE);
- Format := ifA8R8G8B8;
- end
- else
- Converted := Surface;
- if (Converted <> nil) and NewImage(Converted.w, Converted.h, Format, ImageData) then
- begin
- GetImageFormatInfo(Format, Info);
- LineBytes := Info.BytesPerPixel * ImageData.Width;
- if SDL_MustLock(Converted) then
- SDL_LockSurface(Converted);
- // New image is created and pixels are copied from SDL surface
- if LineBytes = Converted.pitch then
- Move(Converted.pixels^, ImageData.Bits^, ImageData.Size)
- else
- for I := 0 to ImageData.Height - 1 do
- Move(PByteArray(Converted.pixels)[I * Converted.pitch],
- PByteArray(ImageData.Bits)[I * LineBytes], LineBytes);
- if SDL_MustLock(Converted) then
- SDL_UnlockSurface(Converted);
- // Copy palette if necessary
- // If surface is in indexed format, palette is copied
- if (Info.Format = ifIndex8) and (Converted.format.palette <> nil) then
- begin
- for I := 0 to Min(Info.PaletteEntries, Converted.format.palette.ncolors) - 1 do
- begin
- ImageData.Palette[I].A := 255;
- ImageData.Palette[I].R := Converted.format.palette.colors[I].r;
- ImageData.Palette[I].G := Converted.format.palette.colors[I].g;
- ImageData.Palette[I].B := Converted.format.palette.colors[I].b;
- end;
- end;
- // Image is converted to override format
- if OverrideFormat <> ifUnknown then
- ConvertImage(ImageData, OverrideFormat);
- Result := True;
- end;
- if Converted <> Surface then
- SDL_FreeSurface(Converted);
- end;
- {
- File Notes:
- -- TODOS ----------------------------------------------------
- - nothing now
- -- 0.23 Changes/Bug Fixes -----------------------------------
- - Fixed possible int overflow in CreateSDLSurfaceFromImage.
- -- 0.15 Changes/Bug Fixes -----------------------------------
- - unit created and initial stuff added
- }
- end.
|