From dffbbbdf81fb0a01b57b59d09ccad15ebe986220 Mon Sep 17 00:00:00 2001 From: "Adonis S. Deliannis" Date: Fri, 9 May 2025 12:17:25 -0700 Subject: [PATCH 1/2] Updated SDL_image.cs to comply with >=.net8. Added Docs to current functions. --- src/SDL2_image.cs | 890 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 682 insertions(+), 208 deletions(-) diff --git a/src/SDL2_image.cs b/src/SDL2_image.cs index 8795c95..1778835 100644 --- a/src/SDL2_image.cs +++ b/src/SDL2_image.cs @@ -1,4 +1,5 @@ #region License + /* SDL2# - C# Wrapper for SDL2 * * Copyright (c) 2013-2020 Ethan Lee. @@ -24,217 +25,690 @@ * Ethan "flibitijibibo" Lee * */ + #endregion #region Using Statements -using System; + using System.Runtime.InteropServices; + #endregion -namespace SDL2 -{ - public static class Image - { - #region SDL2# Variables - - /* Used by DllImport to load the native library. */ - private const string nativeLibName = "SDL2_image"; - - #endregion - - #region SDL_image.h - - /* Similar to the headers, this is the version we're expecting to be - * running with. You will likely want to check this somewhere in your - * program! - */ - public const int ImageMajorVersion = 2; - public const int ImageMinorVersion = 0; - public const int PatchLevel = 2; - - [Flags] - public enum InitFlags - { - Jpg = 0x00000001, - Png = 0x00000002, - Tif = 0x00000004, - Webp = 0x00000008 - } - - public static void ImageVersion(out Version X) - { - X.Major = ImageMajorVersion; - X.Minor = ImageMinorVersion; - X.Patch = PatchLevel; - } - - [DllImport(nativeLibName, EntryPoint = "IMG_Linked_Version", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr INTERNAL_IMG_Linked_Version(); - public static Version LinkedVersion() - { - Version result; - IntPtr result_ptr = INTERNAL_IMG_Linked_Version(); - result = (Version) Marshal.PtrToStructure( - result_ptr, - typeof(Version) - ); - return result; - } - - [DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "IMG_Init")] - public static extern int Init(InitFlags flags); - - [DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "IMG_Quit")] - public static extern void Quit(); - - /* IntPtr refers to an SDL_Surface* */ - [DllImport(nativeLibName, EntryPoint = "IMG_Load", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr INTERNAL_IMG_Load( - byte[] file - ); - public static IntPtr Load(string file) - { - return INTERNAL_IMG_Load(SDL.UTF8_ToNative(file)); - } - - /* src refers to an SDL_RWops*, IntPtr to an SDL_Surface* */ - /* THIS IS A PUBLIC RWops FUNCTION! */ - [DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "IMG_Load_RW")] - public static extern IntPtr LoadRw ( - IntPtr src, - int freeSrc - ); - - /* src refers to an SDL_RWops*, IntPtr to an SDL_Surface* */ - /* THIS IS A PUBLIC RWops FUNCTION! */ - [DllImport(nativeLibName, EntryPoint = "IMG_LoadTyped_RW", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr INTERNAL_IMG_LoadTyped_RW( - IntPtr src, - int freeSrc, - byte[] type - ); - public static IntPtr LoadTypedRw( - IntPtr src, - int freeSrc, - string type - ) { - return INTERNAL_IMG_LoadTyped_RW( - src, - freeSrc, - SDL.UTF8_ToNative(type) - ); - } - - /* IntPtr refers to an SDL_Texture*, renderer to an SDL_Renderer* */ - [DllImport(nativeLibName, EntryPoint = "IMG_LoadTexture", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr INTERNAL_IMG_LoadTexture( - IntPtr renderer, - byte[] file - ); - public static IntPtr LoadTexture( - IntPtr renderer, - string file - ) { - return INTERNAL_IMG_LoadTexture( - renderer, - SDL.UTF8_ToNative(file) - ); - } - - /* renderer refers to an SDL_Renderer*. - * src refers to an SDL_RWops*. - * IntPtr to an SDL_Texture*. - */ - /* THIS IS A PUBLIC RWops FUNCTION! */ - [DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "IMG_LoadTexture_RW")] - public static extern IntPtr LoadTextureRw( - IntPtr renderer, - IntPtr src, - int freeSrc - ); - - /* renderer refers to an SDL_Renderer*. - * src refers to an SDL_RWops*. - * IntPtr to an SDL_Texture*. - */ - /* THIS IS A PUBLIC RWops FUNCTION! */ - [DllImport(nativeLibName, EntryPoint = "IMG_LoadTextureTyped_RW", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr INTERNAL_IMG_LoadTextureTyped_RW( - IntPtr renderer, - IntPtr src, - int freeSrc, - byte[] type - ); - public static IntPtr LoadTextureTypedRw( - IntPtr renderer, - IntPtr src, - int freeSrc, - string type - ) { - return INTERNAL_IMG_LoadTextureTyped_RW( - renderer, - src, - freeSrc, - SDL.UTF8_ToNative(type) - ); - } - - /* IntPtr refers to an SDL_Surface* */ - [DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "IMG_ReadXPMFromArray")] - public static extern IntPtr ReadXPMFromArray( - [In()] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] - string[] xpm - ); - - /* surface refers to an SDL_Surface* */ - [DllImport(nativeLibName, EntryPoint = "IMG_SavePNG", CallingConvention = CallingConvention.Cdecl)] - private static extern int INTERNAL_IMG_SavePNG( - IntPtr surface, - byte[] file - ); - public static int SavePng(IntPtr surface, string file) - { - return INTERNAL_IMG_SavePNG( - surface, - SDL.UTF8_ToNative(file) - ); - } - - /* surface refers to an SDL_Surface*, dst to an SDL_RWops* */ - /* THIS IS A PUBLIC RWops FUNCTION! */ - [DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "IMG_SavePNG_RW")] - public static extern int SavePngRw( - IntPtr surface, - IntPtr dst, - int freeDst - ); - - /* surface refers to an SDL_Surface* */ - [DllImport(nativeLibName, EntryPoint = "IMG_SaveJPG", CallingConvention = CallingConvention.Cdecl)] - private static extern int INTERNAL_IMG_SaveJPG( - IntPtr surface, - byte[] file, - int quality - ); - public static int SaveJpg(IntPtr surface, string file, int quality) - { - return INTERNAL_IMG_SaveJPG( - surface, - SDL.UTF8_ToNative(file), - quality - ); - } - - /* surface refers to an SDL_Surface*, dst to an SDL_RWops* */ - /* THIS IS A PUBLIC RWops FUNCTION! */ - [DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "IMG_SaveJPG_RW")] - public static extern int SaveJpgRw( - IntPtr surface, - IntPtr dst, - int freeDst, - int quality - ); - - #endregion - } -} +namespace SDL2 { + + [Flags] + public enum InitOptions { + Jpg = 0x00000001, + Png = 0x00000002, + Tif = 0x00000004, + Webp = 0x00000008 + } + + public static partial class Image { + + #region SDL2# Variables + + /* Used by DllImport to load the native library. */ + private const string nativeLibName = "SDL2_image"; + + #endregion + + #region SDL_image.h + + /* Similar to the headers, this is the version we're expecting to be + * running with. You will likely want to check this somewhere in your + * program! + */ + public const int ImageMajorVersion = 2; + public const int ImageMinorVersion = 0; + public const int PatchLevel = 28; + + /// + /// Initialization Flags + /// + [Flags] + public enum InitOptions { + Jpg = 0x00000001, + Png = 0x00000002, + Tif = 0x00000004, + Webp = 0x00000008 + } + + /// + /// This macro can be used to fill a version structure with the compile-time version of the library. + /// + public static void ImageVersion(out Version X) { + X.Major = ImageMajorVersion; + X.Minor = ImageMinorVersion; + X.Patch = PatchLevel; + } + + /// + /// Initialize SDL_image. + /// + /// Initialization flags, OR'd together. + /// + /// + /// This function loads dynamic libraries that needs and prepares them for use. + /// This must be the first function you call in , and if it fails, you should not continue with the library. + /// + /// + /// Flags should be one or more values from OR'd together. It returns the flags that were successfully + /// initialized, or 0 on failure. More flags may be added in future SDL_image releases. + /// + /// + /// This function may need to load external shared libraries to support various codecs. As a result, it can fail even on + /// otherwise-reasonable systems if those libraries are missing. This is not limited to rare errors like running out of memory. + /// + /// + /// You may call this function more than once to initialize additional flags. The return value reflects both newly-initialized flags + /// and any previously-initialized ones. Because of this behavior, it's safe to call this with zero (no flags set) as a way to + /// query the current initialization state without changing it. + /// + /// + /// Since it returns all previously-initialized flags, do not check for a zero return value to determine an error. Instead, + /// verify that all required flags are set in the return value. + /// + /// + /// If your app depends on a specific image format, missing support may be fatal. But a general image viewer could continue + /// operating even if some formats (e.g., WEBP) are unavailable. + /// + /// + /// Unlike other SDL satellite libraries, calls to do not stack. A single call to + /// deinitializes everything. It is best practice to have one and one call + /// per program, though not strictly required. + /// + /// + /// After initializing , the app may begin loading images into SDL_Surfaces or SDL_Textures. + /// + /// + /// This function is available since SDL_image 2.0.0. + /// + /// + /// All currently initialized flags. + public static int Init(InitOptions flags) { + // Validate the flags to ensure they are within the expected range + if (!Enum.IsDefined(flags)) { + throw new ArgumentException("Invalid initialization flags provided.", nameof(flags)); + } + + // Call the native method and check the result + int result = INTERNAL_Init(flags); + if (result == 0) { + throw new InvalidOperationException("Failed to initialize SDL2_image with the provided flags."); + } + + return result; + } + + /// + /// This function gets the version of the dynamically linked SDL_image library. + /// + /// (const SDL_version *) Returns SDL_image version. + public static Version LinkedVersion() { + Version result; + nint result_ptr = INTERNAL_IMG_Linked_Version(); + result = Marshal.PtrToStructure(result_ptr); + return result; + } + + /// + /// Load an image from a filesystem path into a software surface. + /// + /// A path on the filesystem to load an image from. + /// + /// + /// An SDL_Surface is a buffer of pixels in memory accessible by the CPU. + /// Use this if you plan to hand the data to something else or manipulate it further in code. + /// + /// + /// There are no guarantees about what format the new SDL_Surface data will be; in many cases, will attempt to supply a + /// surface that exactly matches the provided image, but in others it might have to convert + /// (either because the image is in a format that SDL doesn't directly support or because it's compressed data + /// that could reasonably uncompress to various formats and had to pick one). + /// + /// You can inspect an SDL_Surface for its specifics, and use to then migrate to any supported format. + /// If the image format supports a transparent pixel, SDL will set the colorkey for the surface. + /// + /// + /// You can enable RLE acceleration on the surface afterwards by calling: + /// There is a separate function to read files from an SDL_RWops, if you need an i/o abstraction to provide data from anywhere + /// instead of a simple filesystem read; that function is . + /// + /// + /// If you are using SDL's 2D rendering API, there is an equivalent call to load images directly into an SDL_Texture for use + /// by the GPU without using a software surface: call instead. + /// + /// + /// When done with the returned surface, the app should dispose of it with a call to . + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (SDL_Surface *) Returns a new SDL surface, or NULL on error. + public static nint Load(string file) { + if (!File.Exists(file)) { + throw new FileNotFoundException("File not found", file); + } + return INTERNAL_IMG_Load(SDL.UTF8_ToNative(file)); + } + + /// + /// Load an image from an SDL data source into a software surface. + /// + /// an SDL_RWops that data will be read from. nint refers to a SDL_RWops * + /// True whether to free the or not + /// + /// + /// A is a buffer of pixels in memory accessible by the CPU. + /// Use this if you plan to hand the data to something else or manipulate it further in code. + /// + /// + /// There are no guarantees about what format the new data will be; in many cases, will attempt + /// to supply a surface that exactly matches the provided image, but in others it might have to convert + /// (either because the image is in a format that SDL doesn't directly support or because it's compressed data that could + /// reasonably uncompress to various formats and had to pick one). You can inspect a for its specifics, + /// and use to then migrate to any supported format. + /// + /// + /// If the image format supports a transparent pixel, SDL will set the colorkey for the surface. + /// You can enable RLE acceleration on the surface afterwards by calling: . + /// + /// + /// If freesrc is non-zero, the RWops will be closed before returning, whether this function succeeds or not. + /// reads everything it needs from the RWops during this call in any case. + /// + /// + /// There is a separate function to read files from disk without having to deal with SDL_RWops: + /// will call this function and manage those details for you, determining the file type from the filename's extension. + /// + /// + /// There is also , which is equivalent to this function except a file extension (like "BMP", "JPG", etc) + /// can be specified, in case cannot autodetect the file format. + /// + /// + /// If you are using SDL's 2D rendering API, there is an equivalent call to load images directly into a Texture for use by the GPU without using + /// a software surface: call instead. + /// When done with the returned surface, the app should dispose of it with a call to . + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (SDL_Surface *) Returns a new SDL surface, or NULL on error. + public static nint LoadRw(nint src, bool freeSrc) { + // Validate the source pointer to ensure it is not null + if (src == nint.Zero) { + throw new ArgumentNullException(nameof(src), "Source pointer cannot be null."); + } + + // Call the internal native method and handle any potential errors + nint result = INTERNAL_LoadRw(src, freeSrc ? 1 : 0); + if (result == nint.Zero) { + throw new InvalidOperationException("Failed to load RW. SDL2_image returned a null pointer."); + } + + return result; + } + + /// + /// Load an image from a filesystem path into a GPU texture. + /// + /// the SDL_Renderer to use to create the GPU texture. nint refers to a SDL_Renderer * + /// a path on the filesystem to load an image from. + /// + /// + /// An SDL_Texture represents an image in GPU memory, usable by SDL's 2D Render API. + /// This can be significantly more efficient than using a CPU-bound if you don't need to manipulate the image directly after loading it. + /// + /// + /// If the loaded image has transparency or a colorkey, a texture with an alpha channel will be created. Otherwise, will attempt to create + /// an SDL_Texture in the most format that most reasonably represents the image data (but in many cases, this will just end up being 32-bit RGB or 32-bit RGBA). + /// + /// + /// There is a separate function to read files from an SDL_RWops, if you need an i/o abstraction to provide data from anywhere instead of a simple filesystem read; + /// that function is . + /// If you would rather decode an image to an (a buffer of pixels in CPU memory), call instead. + /// When done with the returned texture, the app should dispose of it with a call to . + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (SDL_Texture *) Returns a new texture, or NULL on error. + public static nint LoadTexture( + nint renderer, + string file + ) { + return INTERNAL_IMG_LoadTexture( + renderer, + SDL.UTF8_ToNative(file) + ); + } + + /// + /// Load an image from an SDL data source into a GPU texture. + /// + /// the SDL_Renderer to use to create the GPU texture. nint refers to a SDL_Renderer * + /// an SDL_RWops that data will be read from. nint refers to a SDL_RWops * + /// + /// + /// An SDL_Texture represents an image in GPU memory, usable by SDL's 2D Render API. + /// This can be significantly more efficient than using a CPU-bound if you don't need to manipulate the image directly after loading it. + /// + /// + /// If the loaded image has transparency or a colorkey, a texture with an alpha channel will be created. Otherwise, will attempt to create + /// an SDL_Texture in the most format that most reasonably represents the image data (but in many cases, this will just end up being 32-bit RGB or 32-bit RGBA). + /// + /// + /// If freesrc is true, the RWops will be closed before returning, whether this function succeeds or not. reads everything it + /// needs from the RWops during this call in any case. There is a separate function to read files from disk without having to deal + /// with SDL_RWops: will call this function and manage those details for you, determining the file type from the filename's extension. + /// + /// + /// There is also , which is equivalent to this function except a file extension (like "BMP", "JPG", etc) + /// can be specified, in case cannot autodetect the file format. + /// If you would rather decode an image to an (a buffer of pixels in CPU memory), call instead. + /// When done with the returned texture, the app should dispose of it with a call to . + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (SDL_Texture *) Returns a new texture, or NULL on error. + public static nint LoadTextureRw(nint renderer, nint src, bool freeSrc) { + return INTERNAL_LoadTextureRw(renderer, src, freeSrc ? 1 : 0); + } + + /// + /// Load an image from an SDL data source into a GPU texture. + /// + /// the SDL_Renderer to use to create the GPU texture. nint refers to a SDL_Renderer * + /// an SDL_RWops that data will be read from. nint refers to a SDL_RWops * + /// a filename extension that represent this data ("BMP", "GIF", "PNG", etc). + /// + /// + /// An SDL_Texture represents an image in GPU memory, usable by SDL's 2D Render API. This can be significantly more efficient + /// than using a CPU-bound SDL_Surface if you don't need to manipulate the image directly after loading it. + /// + /// + /// If the loaded image has transparency or a colorkey, a texture with an alpha channel will be created. Otherwise, will attempt to + /// create an SDL_Texture in the most format that most reasonably represents the image data (but in many cases, this will just end up being 32-bit RGB or 32-bit RGBA). + /// If freesrc is true, the RWops will be closed before returning, whether this function succeeds or not. reads everything it needs from the RWops during this call in any case. + /// + /// + /// Even though this function accepts a file type, may still try other decoders that are capable of detecting file type from the contents of the image data, + /// but may rely on the caller-provided type string for formats that it cannot autodetect. + /// If type is NULL, will rely solely on its ability to guess the format. + /// + /// + /// There is a separate function to read files from disk without having to deal with SDL_RWops: will call this function and manage those details for you, + /// determining the file type from the filename's extension. + /// There is also , which is equivalent to this function except that it will rely on to + /// determine what type of data it is loading, much like passing a NULL for type. + /// + /// + /// If you would rather decode an image to an (a buffer of pixels in CPU memory), call instead. + /// When done with the returned texture, the app should dispose of it with a call to . + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (SDL_Texture *) Returns a new texture, or NULL on error. + public static nint LoadTextureTypedRw( + nint renderer, + nint src, + int freeSrc, + string? type + ) { + return INTERNAL_IMG_LoadTextureTyped_RW( + renderer, + src, + freeSrc, + SDL.UTF8_ToNative(type!) + ); + } + + /// + /// Load an image from an SDL data source into a software surface. + /// + /// an SDL_RWops that data will be read from. nint refers to a SDL_RWops * + /// a filename extension that represent this data ("BMP", "GIF", "PNG", etc). + /// True whether to free the or not. + /// + /// + /// A is a buffer of pixels in memory accessible by the CPU. + /// Use this if you plan to hand the data to something else or manipulate it further in code. + /// + /// + /// There are no guarantees about what format the new data will be; in many cases, will attempt to supply + /// a surface that exactly matches the provided image, but in others it might have to convert + /// (either because the image is in a format that SDL doesn't directly support or because it's compressed data that + /// could reasonably uncompress to various formats and had to pick one). + /// + /// + /// You can inspect an for its specifics, and use to then migrate to any supported format. + /// If the image format supports a transparent pixel, SDL will set the colorkey for the surface. + /// + /// + /// You can enable RLE acceleration on the surface afterwards by calling: + /// If freesrc is true, the RWops will be closed before returning, whether this function succeeds or not. + /// + /// + /// reads everything it needs from the RWops during this call in any case. + /// Even though this function accepts a file type, may still try other decoders that are capable of + /// detecting file type from the contents of the image data, but may rely on the caller-provided type string for formats that it cannot autodetect. + /// If type is NULL, will rely solely on its ability to guess the format. + /// + /// + /// There is a separate function to read files from disk without having to deal with SDL_RWops: will call this function + /// and manage those details for you, determining the file type from the filename's extension. + /// There is also which is equivalent to this function except that it will rely on to determine what type of data it is loading, much like passing a NULL for type. + /// + /// + /// If you are using SDL's 2D rendering API, there is an equivalent call to load images directly into an SDL_Texture for use by the GPU without using a software surface: callIMG_LoadTextureTyped_RW() instead. + /// When done with the returned surface, the app should dispose of it with a call to SDL_FreeSurface(). + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (SDL_Surface *) Returns a new SDL surface, or NULL on error. + public static nint LoadTypedRw( + nint src, + bool freeSrc, + string? type + ) { + return INTERNAL_IMG_LoadTyped_RW( + src, + freeSrc ? 1 : 0, + SDL.UTF8_ToNative(type!) + ); + } + + /// + /// DeInitialize + /// + /// + /// + /// This should be the last function you call in , after freeing all other resources. + /// This will unload any shared libraries it is using for various codecs. + /// + /// + /// After this call, a call to Init(0) will return 0 (no codecs loaded). + /// You can safely call to reload various codec support after this call. + /// + /// + /// Unlike other SDL satellite libraries, calls to do not stack; a single call to + /// will deinitialize everything and does not have to be paired with a matching call. + /// + /// + /// For that reason, it's considered best practices to have a single and call in your program. + /// While this isn't required, be aware of the risks of deviating from that behavior. + /// + /// + public static void Quit() { + INTERNAL_Quit(); + } + + /// + /// Load an XPM image from a memory array. + /// + /// a null-terminated array of strings that comprise XPM data. + /// + /// + /// The returned will be an 8bpp indexed surface, if possible, otherwise it will be 32bpp. + /// If you always want 32-bit data, use instead. + /// When done with the returned surface, the app should dispose of it with a call to . + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (SDL_Surface *) Returns a new SDL surface, or NULL on error. + public static nint ReadXPMFromArray(string[] xpm) { + // Validate the input array to ensure it is not null or empty + if (xpm == null || xpm.Length == 0) { + throw new ArgumentException("XPM array cannot be null or empty.", nameof(xpm)); + } + + // Call the internal native method + nint result = INTERNAL_ReadXPMFromArray(xpm); + + // Check if the result is a null pointer, indicating an error + if (result == nint.Zero) { + throw new InvalidOperationException("Failed to read XPM from array. SDL2_image returned a null pointer."); + } + + return result; + } + + /// + /// Load an XPM image from a memory array. + /// + /// a null-terminated array of strings that comprise XPM data. + /// + /// + /// The returned surface will always be a 32-bit RGB surface. If you want 8-bit indexed colors (and the XPM data allows it), use instead. + /// When done with the returned surface, the app should dispose of it with a call to . + /// + /// This function is available since SDL_image 2.6.0. + /// + /// (SDL_Surface *) Returns a new SDL surface, or NULL on error. + public static nint ReadXPMFromArrayToRGB888(string[] xpm) { + // Validate the input array to ensure it is not null or empty + if (xpm == null || xpm.Length == 0) { + throw new ArgumentException("XPM array cannot be null or empty.", nameof(xpm)); + } + + // Call the internal native method + nint result = INTERNAL_ReadXPMFromArrayToRGB888(xpm); + + // Check if the result is a null pointer, indicating an error + if (result == nint.Zero) { + throw new InvalidOperationException("Failed to read XPM from array to RGB888. SDL2_image returned a null pointer."); + } + + return result; + } + + /// + /// Save an SDL_Surface into a JPEG image file. + /// + /// the SDL surface to save. nint refers to a SDL_Surface * + /// path on the filesystem to write new file to. + /// + /// + /// If the file already exists, it will be overwritten. + /// + /// This function is available since SDL_image 2.0.2. + /// + /// (int) Returns 0 if successful, -1 on error. + public static int SaveJpg(nint surface, string file, int quality) { + return INTERNAL_IMG_SaveJPG( + surface, + SDL.UTF8_ToNative(file), + quality + ); + } + + /// + /// Save an SDL_Surface into JPEG image data, via an SDL_RWops. + /// + /// the SDL surface to save. nint refers to a SDL_Surface * + /// the SDL_RWops to save the image data to. nint refers to a SDL_RWops * + /// True whether to free the destination after saving + /// The quality of the image. [0;33] Low, [34;66] Medium, [67;100] High + /// + /// + /// If you just want to save to a filename, you can use instead. + /// + /// This function is available since SDL_image 2.0.2. + /// + /// (int) Returns 0 if successful, -1 on error. + public static int SaveJpgRw(nint surface, nint dst, bool freeDst, int quality) { + // Validate the quality parameter to ensure it is within the acceptable range (e.g., 0-100) + if (quality < 0 || quality > 100) { + throw new ArgumentOutOfRangeException(nameof(quality), "Quality must be between 0 and 100."); + } + + // Validate the surface and destination pointers to ensure they are not null + if (surface == nint.Zero) { + throw new ArgumentNullException(nameof(surface), "Surface pointer cannot be null."); + } + + if (dst == nint.Zero) { + throw new ArgumentNullException(nameof(dst), "Destination pointer cannot be null."); + } + + // Call the internal native method and handle any potential errors + int result = INTERNAL_SaveJpgRw(surface, dst, freeDst ? 1 : 0, quality); + if (result != 0) { + throw new InvalidOperationException($"Failed to save JPG. SDL2_image returned error code: {result}"); + } + + return result; + } + + + /// + /// Save an SDL_Surface into a PNG image file. + /// + /// the SDL surface to save. nint refers to a SDL_Surface * + /// path on the filesystem to write new file to. + /// + /// + /// If the file already exists, it will be overwritten. + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (int) Returns 0 if successful, -1 on error. + public static int SavePng(nint surface, string file) { + return INTERNAL_IMG_SavePNG( + surface, + SDL.UTF8_ToNative(file) + ); + } + + /// + /// Save an SDL_Surface into PNG image data, via an SDL_RWops. + /// + /// the SDL surface to save. nint refers to a SDL_Surface * + /// the SDL_RWops to save the image data to. nint refers to a SDL_RWops * + /// True to free the destination after saving + /// + /// + /// If you just want to save to a filename, you can use instead. + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (int) Returns 0 if successful, -1 on error. + public static int SavePngRw(nint surface, nint dst, bool freeDst) { + // Validate the surface pointer to ensure it is not null + if (surface == nint.Zero) { + throw new ArgumentNullException(nameof(surface), "Surface pointer cannot be null."); + } + + // Validate the destination pointer to ensure it is not null + if (dst == nint.Zero) { + throw new ArgumentNullException(nameof(dst), "Destination pointer cannot be null."); + } + + // Call the internal native method and handle any potential errors + int result = INTERNAL_SavePngRw(surface, dst, freeDst ? 1 : 0); + if (result != 0) { + throw new InvalidOperationException($"Failed to save PNG. SDL2_image returned error code: {result}"); + } + + return result; + } + + [LibraryImport(nativeLibName, EntryPoint = "IMG_Linked_Version")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_IMG_Linked_Version(); + [LibraryImport(nativeLibName, EntryPoint = "IMG_Load")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_IMG_Load(byte[] file); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_LoadTexture")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_IMG_LoadTexture( + nint renderer, + byte[] file + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_LoadTextureTyped_RW")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_IMG_LoadTextureTyped_RW( + nint renderer, + nint src, + int freeSrc, + byte[] type + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_LoadTyped_RW")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_IMG_LoadTyped_RW( + nint src, + int freeSrc, + byte[] type + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_SaveJPG")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial int INTERNAL_IMG_SaveJPG( + nint surface, + byte[] file, + int quality + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_SavePNG")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial int INTERNAL_IMG_SavePNG( + nint surface, + byte[] file + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_Init")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial int INTERNAL_Init(InitOptions flags); + [LibraryImport(nativeLibName, EntryPoint = "IMG_Load_RW")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_LoadRw( + nint src, + int freeSrc + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_LoadTexture_RW")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_LoadTextureRw( + nint renderer, + nint src, + int freeSrc + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_Quit")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial void INTERNAL_Quit(); + + + [LibraryImport(nativeLibName, EntryPoint = "IMG_ReadXPMFromArray")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_ReadXPMFromArray( + [In()] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] + string[] xpm + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_ReadXPMFromArrayToRGB888")] + [UnmanagedCallConv (CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_ReadXPMFromArrayToRGB888( + [In()] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] + string[] xpm); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_SaveJPG_RW")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial int INTERNAL_SaveJpgRw( + nint surface, + nint dst, + int freeDst, + int quality + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_SavePNG_RW")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial int INTERNAL_SavePngRw( + nint surface, + nint dst, + int freeDst + ); + #endregion + } +} \ No newline at end of file From 81129e54c951ae488f1ab2468d61df0851224473 Mon Sep 17 00:00:00 2001 From: "Adonis S. Deliannis" Date: Fri, 9 May 2025 12:43:06 -0700 Subject: [PATCH 2/2] Made a few corrections --- src/SDL2_image.cs | 1251 ++++++++++++++++++++++----------------------- 1 file changed, 625 insertions(+), 626 deletions(-) diff --git a/src/SDL2_image.cs b/src/SDL2_image.cs index 1778835..382263b 100644 --- a/src/SDL2_image.cs +++ b/src/SDL2_image.cs @@ -34,8 +34,30 @@ #endregion -namespace SDL2 { +namespace SDL2; +public static partial class Image { + + #region SDL2# Variables + + /* Used by DllImport to load the native library. */ + private const string nativeLibName = "SDL2_image"; + + #endregion + + #region SDL_image.h + + /* Similar to the headers, this is the version we're expecting to be + * running with. You will likely want to check this somewhere in your + * program! + */ + public const int ImageMajorVersion = 2; + public const int ImageMinorVersion = 0; + public const int PatchLevel = 28; + + /// + /// Initialization Flags + /// [Flags] public enum InitOptions { Jpg = 0x00000001, @@ -44,671 +66,648 @@ public enum InitOptions { Webp = 0x00000008 } - public static partial class Image { - - #region SDL2# Variables - - /* Used by DllImport to load the native library. */ - private const string nativeLibName = "SDL2_image"; + /// + /// This macro will evaluate to true if compiled with at least X.Y.Z. + /// + public static bool ImageVersionAtLeast(Version version) => (ImageMajorVersion >= version.Major) + && (ImageMajorVersion > version.Major || ImageMinorVersion >= version.Minor) + && (ImageMajorVersion > version.Major || ImageMinorVersion > version.Minor || PatchLevel >= version.Patch); + + /// + /// This macro can be used to fill a version structure with the compile-time version of the library. + /// + public static void ImageVersion(out Version X) { + X.Major = ImageMajorVersion; + X.Minor = ImageMinorVersion; + X.Patch = PatchLevel; + } - #endregion + /// + /// Initialize SDL_image. + /// + /// Initialization flags, OR'd together. + /// + /// + /// This function loads dynamic libraries that needs and prepares them for use. + /// This must be the first function you call in , and if it fails, you should not continue with the library. + /// + /// + /// Flags should be one or more values from OR'd together. It returns the flags that were successfully + /// initialized, or 0 on failure. More flags may be added in future SDL_image releases. + /// + /// + /// This function may need to load external shared libraries to support various codecs. As a result, it can fail even on + /// otherwise-reasonable systems if those libraries are missing. This is not limited to rare errors like running out of memory. + /// + /// + /// You may call this function more than once to initialize additional flags. The return value reflects both newly-initialized flags + /// and any previously-initialized ones. Because of this behavior, it's safe to call this with zero (no flags set) as a way to + /// query the current initialization state without changing it. + /// + /// + /// Since it returns all previously-initialized flags, do not check for a zero return value to determine an error. Instead, + /// verify that all required flags are set in the return value. + /// + /// + /// If your app depends on a specific image format, missing support may be fatal. But a general image viewer could continue + /// operating even if some formats (e.g., WEBP) are unavailable. + /// + /// + /// Unlike other SDL satellite libraries, calls to do not stack. A single call to + /// deinitializes everything. It is best practice to have one and one call + /// per program, though not strictly required. + /// + /// + /// After initializing , the app may begin loading images into SDL_Surfaces or SDL_Textures. + /// + /// + /// This function is available since SDL_image 2.0.0. + /// + /// + /// All currently initialized flags. + public static int Init(InitOptions flags) { + // Validate the flags to ensure they are within the expected range + if (!Enum.IsDefined(flags)) { + throw new ArgumentException("Invalid initialization flags provided.", nameof(flags)); + } - #region SDL_image.h + // Call the native method and check the result + int result = INTERNAL_Init(flags); + if (result == 0) { + throw new InvalidOperationException("Failed to initialize SDL2_image with the provided flags."); + } - /* Similar to the headers, this is the version we're expecting to be - * running with. You will likely want to check this somewhere in your - * program! - */ - public const int ImageMajorVersion = 2; - public const int ImageMinorVersion = 0; - public const int PatchLevel = 28; + return result; + } - /// - /// Initialization Flags - /// - [Flags] - public enum InitOptions { - Jpg = 0x00000001, - Png = 0x00000002, - Tif = 0x00000004, - Webp = 0x00000008 - } + /// + /// This function gets the version of the dynamically linked SDL_image library. + /// + /// (const SDL_version *) Returns SDL_image version. + public static Version LinkedVersion() { + Version result; + nint result_ptr = INTERNAL_IMG_Linked_Version(); + result = Marshal.PtrToStructure(result_ptr); + return result; + } - /// - /// This macro can be used to fill a version structure with the compile-time version of the library. - /// - public static void ImageVersion(out Version X) { - X.Major = ImageMajorVersion; - X.Minor = ImageMinorVersion; - X.Patch = PatchLevel; + /// + /// Load an image from a filesystem path into a software surface. + /// + /// A path on the filesystem to load an image from. + /// + /// + /// An SDL_Surface is a buffer of pixels in memory accessible by the CPU. + /// Use this if you plan to hand the data to something else or manipulate it further in code. + /// + /// + /// There are no guarantees about what format the new SDL_Surface data will be; in many cases, will attempt to supply a + /// surface that exactly matches the provided image, but in others it might have to convert + /// (either because the image is in a format that SDL doesn't directly support or because it's compressed data + /// that could reasonably uncompress to various formats and had to pick one). + /// + /// You can inspect an SDL_Surface for its specifics, and use to then migrate to any supported format. + /// If the image format supports a transparent pixel, SDL will set the colorkey for the surface. + /// + /// + /// You can enable RLE acceleration on the surface afterwards by calling: + /// There is a separate function to read files from an SDL_RWops, if you need an i/o abstraction to provide data from anywhere + /// instead of a simple filesystem read; that function is . + /// + /// + /// If you are using SDL's 2D rendering API, there is an equivalent call to load images directly into an SDL_Texture for use + /// by the GPU without using a software surface: call instead. + /// + /// + /// When done with the returned surface, the app should dispose of it with a call to . + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (SDL_Surface *) Returns a new SDL surface, or NULL on error. + public static nint Load(string file) { + if (!File.Exists(file)) { + throw new FileNotFoundException("File not found", file); } + return INTERNAL_IMG_Load(SDL.UTF8_ToNative(file)); + } - /// - /// Initialize SDL_image. - /// - /// Initialization flags, OR'd together. - /// - /// - /// This function loads dynamic libraries that needs and prepares them for use. - /// This must be the first function you call in , and if it fails, you should not continue with the library. - /// - /// - /// Flags should be one or more values from OR'd together. It returns the flags that were successfully - /// initialized, or 0 on failure. More flags may be added in future SDL_image releases. - /// - /// - /// This function may need to load external shared libraries to support various codecs. As a result, it can fail even on - /// otherwise-reasonable systems if those libraries are missing. This is not limited to rare errors like running out of memory. - /// - /// - /// You may call this function more than once to initialize additional flags. The return value reflects both newly-initialized flags - /// and any previously-initialized ones. Because of this behavior, it's safe to call this with zero (no flags set) as a way to - /// query the current initialization state without changing it. - /// - /// - /// Since it returns all previously-initialized flags, do not check for a zero return value to determine an error. Instead, - /// verify that all required flags are set in the return value. - /// - /// - /// If your app depends on a specific image format, missing support may be fatal. But a general image viewer could continue - /// operating even if some formats (e.g., WEBP) are unavailable. - /// - /// - /// Unlike other SDL satellite libraries, calls to do not stack. A single call to - /// deinitializes everything. It is best practice to have one and one call - /// per program, though not strictly required. - /// - /// - /// After initializing , the app may begin loading images into SDL_Surfaces or SDL_Textures. - /// - /// - /// This function is available since SDL_image 2.0.0. - /// - /// - /// All currently initialized flags. - public static int Init(InitOptions flags) { - // Validate the flags to ensure they are within the expected range - if (!Enum.IsDefined(flags)) { - throw new ArgumentException("Invalid initialization flags provided.", nameof(flags)); - } - - // Call the native method and check the result - int result = INTERNAL_Init(flags); - if (result == 0) { - throw new InvalidOperationException("Failed to initialize SDL2_image with the provided flags."); - } - - return result; + /// + /// Load an image from an SDL data source into a software surface. + /// + /// an SDL_RWops that data will be read from. nint refers to a SDL_RWops * + /// True whether to free the or not + /// + /// + /// A is a buffer of pixels in memory accessible by the CPU. + /// Use this if you plan to hand the data to something else or manipulate it further in code. + /// + /// + /// There are no guarantees about what format the new data will be; in many cases, will attempt + /// to supply a surface that exactly matches the provided image, but in others it might have to convert + /// (either because the image is in a format that SDL doesn't directly support or because it's compressed data that could + /// reasonably uncompress to various formats and had to pick one). You can inspect a for its specifics, + /// and use to then migrate to any supported format. + /// + /// + /// If the image format supports a transparent pixel, SDL will set the colorkey for the surface. + /// You can enable RLE acceleration on the surface afterwards by calling: . + /// + /// + /// If freesrc is non-zero, the RWops will be closed before returning, whether this function succeeds or not. + /// reads everything it needs from the RWops during this call in any case. + /// + /// + /// There is a separate function to read files from disk without having to deal with SDL_RWops: + /// will call this function and manage those details for you, determining the file type from the filename's extension. + /// + /// + /// There is also , which is equivalent to this function except a file extension (like "BMP", "JPG", etc) + /// can be specified, in case cannot autodetect the file format. + /// + /// + /// If you are using SDL's 2D rendering API, there is an equivalent call to load images directly into a Texture for use by the GPU without using + /// a software surface: call instead. + /// When done with the returned surface, the app should dispose of it with a call to . + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (SDL_Surface *) Returns a new SDL surface, or NULL on error. + public static nint LoadRw(nint src, bool freeSrc) { + // Validate the source pointer to ensure it is not null + if (src == nint.Zero) { + throw new ArgumentNullException(nameof(src), "Source pointer cannot be null."); } - /// - /// This function gets the version of the dynamically linked SDL_image library. - /// - /// (const SDL_version *) Returns SDL_image version. - public static Version LinkedVersion() { - Version result; - nint result_ptr = INTERNAL_IMG_Linked_Version(); - result = Marshal.PtrToStructure(result_ptr); - return result; + // Call the internal native method and handle any potential errors + nint result = INTERNAL_LoadRw(src, freeSrc ? 1 : 0); + if (result == nint.Zero) { + throw new InvalidOperationException("Failed to load RW. SDL2_image returned a null pointer."); } - /// - /// Load an image from a filesystem path into a software surface. - /// - /// A path on the filesystem to load an image from. - /// - /// - /// An SDL_Surface is a buffer of pixels in memory accessible by the CPU. - /// Use this if you plan to hand the data to something else or manipulate it further in code. - /// - /// - /// There are no guarantees about what format the new SDL_Surface data will be; in many cases, will attempt to supply a - /// surface that exactly matches the provided image, but in others it might have to convert - /// (either because the image is in a format that SDL doesn't directly support or because it's compressed data - /// that could reasonably uncompress to various formats and had to pick one). - /// - /// You can inspect an SDL_Surface for its specifics, and use to then migrate to any supported format. - /// If the image format supports a transparent pixel, SDL will set the colorkey for the surface. - /// - /// - /// You can enable RLE acceleration on the surface afterwards by calling: - /// There is a separate function to read files from an SDL_RWops, if you need an i/o abstraction to provide data from anywhere - /// instead of a simple filesystem read; that function is . - /// - /// - /// If you are using SDL's 2D rendering API, there is an equivalent call to load images directly into an SDL_Texture for use - /// by the GPU without using a software surface: call instead. - /// - /// - /// When done with the returned surface, the app should dispose of it with a call to . - /// - /// This function is available since SDL_image 2.0.0. - /// - /// (SDL_Surface *) Returns a new SDL surface, or NULL on error. - public static nint Load(string file) { - if (!File.Exists(file)) { - throw new FileNotFoundException("File not found", file); - } - return INTERNAL_IMG_Load(SDL.UTF8_ToNative(file)); - } + return result; + } - /// - /// Load an image from an SDL data source into a software surface. - /// - /// an SDL_RWops that data will be read from. nint refers to a SDL_RWops * - /// True whether to free the or not - /// - /// - /// A is a buffer of pixels in memory accessible by the CPU. - /// Use this if you plan to hand the data to something else or manipulate it further in code. - /// - /// - /// There are no guarantees about what format the new data will be; in many cases, will attempt - /// to supply a surface that exactly matches the provided image, but in others it might have to convert - /// (either because the image is in a format that SDL doesn't directly support or because it's compressed data that could - /// reasonably uncompress to various formats and had to pick one). You can inspect a for its specifics, - /// and use to then migrate to any supported format. - /// - /// - /// If the image format supports a transparent pixel, SDL will set the colorkey for the surface. - /// You can enable RLE acceleration on the surface afterwards by calling: . - /// - /// - /// If freesrc is non-zero, the RWops will be closed before returning, whether this function succeeds or not. - /// reads everything it needs from the RWops during this call in any case. - /// - /// - /// There is a separate function to read files from disk without having to deal with SDL_RWops: - /// will call this function and manage those details for you, determining the file type from the filename's extension. - /// - /// - /// There is also , which is equivalent to this function except a file extension (like "BMP", "JPG", etc) - /// can be specified, in case cannot autodetect the file format. - /// - /// - /// If you are using SDL's 2D rendering API, there is an equivalent call to load images directly into a Texture for use by the GPU without using - /// a software surface: call instead. - /// When done with the returned surface, the app should dispose of it with a call to . - /// - /// This function is available since SDL_image 2.0.0. - /// - /// (SDL_Surface *) Returns a new SDL surface, or NULL on error. - public static nint LoadRw(nint src, bool freeSrc) { - // Validate the source pointer to ensure it is not null - if (src == nint.Zero) { - throw new ArgumentNullException(nameof(src), "Source pointer cannot be null."); - } - - // Call the internal native method and handle any potential errors - nint result = INTERNAL_LoadRw(src, freeSrc ? 1 : 0); - if (result == nint.Zero) { - throw new InvalidOperationException("Failed to load RW. SDL2_image returned a null pointer."); - } - - return result; - } + /// + /// Load an image from a filesystem path into a GPU texture. + /// + /// the SDL_Renderer to use to create the GPU texture. nint refers to a SDL_Renderer * + /// a path on the filesystem to load an image from. + /// + /// + /// An SDL_Texture represents an image in GPU memory, usable by SDL's 2D Render API. + /// This can be significantly more efficient than using a CPU-bound if you don't need to manipulate the image directly after loading it. + /// + /// + /// If the loaded image has transparency or a colorkey, a texture with an alpha channel will be created. Otherwise, will attempt to create + /// an SDL_Texture in the most format that most reasonably represents the image data (but in many cases, this will just end up being 32-bit RGB or 32-bit RGBA). + /// + /// + /// There is a separate function to read files from an SDL_RWops, if you need an i/o abstraction to provide data from anywhere instead of a simple filesystem read; + /// that function is . + /// If you would rather decode an image to an (a buffer of pixels in CPU memory), call instead. + /// When done with the returned texture, the app should dispose of it with a call to . + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (SDL_Texture *) Returns a new texture, or NULL on error. + public static nint LoadTexture( + nint renderer, + string file + ) { + return INTERNAL_IMG_LoadTexture( + renderer, + SDL.UTF8_ToNative(file) + ); + } - /// - /// Load an image from a filesystem path into a GPU texture. - /// - /// the SDL_Renderer to use to create the GPU texture. nint refers to a SDL_Renderer * - /// a path on the filesystem to load an image from. - /// - /// - /// An SDL_Texture represents an image in GPU memory, usable by SDL's 2D Render API. - /// This can be significantly more efficient than using a CPU-bound if you don't need to manipulate the image directly after loading it. - /// - /// - /// If the loaded image has transparency or a colorkey, a texture with an alpha channel will be created. Otherwise, will attempt to create - /// an SDL_Texture in the most format that most reasonably represents the image data (but in many cases, this will just end up being 32-bit RGB or 32-bit RGBA). - /// - /// - /// There is a separate function to read files from an SDL_RWops, if you need an i/o abstraction to provide data from anywhere instead of a simple filesystem read; - /// that function is . - /// If you would rather decode an image to an (a buffer of pixels in CPU memory), call instead. - /// When done with the returned texture, the app should dispose of it with a call to . - /// - /// This function is available since SDL_image 2.0.0. - /// - /// (SDL_Texture *) Returns a new texture, or NULL on error. - public static nint LoadTexture( - nint renderer, - string file - ) { - return INTERNAL_IMG_LoadTexture( - renderer, - SDL.UTF8_ToNative(file) - ); - } + /// + /// Load an image from an SDL data source into a GPU texture. + /// + /// the SDL_Renderer to use to create the GPU texture. nint refers to a SDL_Renderer * + /// an SDL_RWops that data will be read from. nint refers to a SDL_RWops * + /// + /// + /// An SDL_Texture represents an image in GPU memory, usable by SDL's 2D Render API. + /// This can be significantly more efficient than using a CPU-bound if you don't need to manipulate the image directly after loading it. + /// + /// + /// If the loaded image has transparency or a colorkey, a texture with an alpha channel will be created. Otherwise, will attempt to create + /// an SDL_Texture in the most format that most reasonably represents the image data (but in many cases, this will just end up being 32-bit RGB or 32-bit RGBA). + /// + /// + /// If freesrc is true, the RWops will be closed before returning, whether this function succeeds or not. reads everything it + /// needs from the RWops during this call in any case. There is a separate function to read files from disk without having to deal + /// with SDL_RWops: will call this function and manage those details for you, determining the file type from the filename's extension. + /// + /// + /// There is also , which is equivalent to this function except a file extension (like "BMP", "JPG", etc) + /// can be specified, in case cannot autodetect the file format. + /// If you would rather decode an image to an (a buffer of pixels in CPU memory), call instead. + /// When done with the returned texture, the app should dispose of it with a call to . + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (SDL_Texture *) Returns a new texture, or NULL on error. + public static nint LoadTextureRw(nint renderer, nint src, bool freeSrc) { + return INTERNAL_LoadTextureRw(renderer, src, freeSrc ? 1 : 0); + } - /// - /// Load an image from an SDL data source into a GPU texture. - /// - /// the SDL_Renderer to use to create the GPU texture. nint refers to a SDL_Renderer * - /// an SDL_RWops that data will be read from. nint refers to a SDL_RWops * - /// - /// - /// An SDL_Texture represents an image in GPU memory, usable by SDL's 2D Render API. - /// This can be significantly more efficient than using a CPU-bound if you don't need to manipulate the image directly after loading it. - /// - /// - /// If the loaded image has transparency or a colorkey, a texture with an alpha channel will be created. Otherwise, will attempt to create - /// an SDL_Texture in the most format that most reasonably represents the image data (but in many cases, this will just end up being 32-bit RGB or 32-bit RGBA). - /// - /// - /// If freesrc is true, the RWops will be closed before returning, whether this function succeeds or not. reads everything it - /// needs from the RWops during this call in any case. There is a separate function to read files from disk without having to deal - /// with SDL_RWops: will call this function and manage those details for you, determining the file type from the filename's extension. - /// - /// - /// There is also , which is equivalent to this function except a file extension (like "BMP", "JPG", etc) - /// can be specified, in case cannot autodetect the file format. - /// If you would rather decode an image to an (a buffer of pixels in CPU memory), call instead. - /// When done with the returned texture, the app should dispose of it with a call to . - /// - /// This function is available since SDL_image 2.0.0. - /// - /// (SDL_Texture *) Returns a new texture, or NULL on error. - public static nint LoadTextureRw(nint renderer, nint src, bool freeSrc) { - return INTERNAL_LoadTextureRw(renderer, src, freeSrc ? 1 : 0); - } + /// + /// Load an image from an SDL data source into a GPU texture. + /// + /// the SDL_Renderer to use to create the GPU texture. nint refers to a SDL_Renderer * + /// an SDL_RWops that data will be read from. nint refers to a SDL_RWops * + /// a filename extension that represent this data ("BMP", "GIF", "PNG", etc). + /// + /// + /// An SDL_Texture represents an image in GPU memory, usable by SDL's 2D Render API. This can be significantly more efficient + /// than using a CPU-bound SDL_Surface if you don't need to manipulate the image directly after loading it. + /// + /// + /// If the loaded image has transparency or a colorkey, a texture with an alpha channel will be created. Otherwise, will attempt to + /// create an SDL_Texture in the most format that most reasonably represents the image data (but in many cases, this will just end up being 32-bit RGB or 32-bit RGBA). + /// If freesrc is true, the RWops will be closed before returning, whether this function succeeds or not. reads everything it needs from the RWops during this call in any case. + /// + /// + /// Even though this function accepts a file type, may still try other decoders that are capable of detecting file type from the contents of the image data, + /// but may rely on the caller-provided type string for formats that it cannot autodetect. + /// If type is NULL, will rely solely on its ability to guess the format. + /// + /// + /// There is a separate function to read files from disk without having to deal with SDL_RWops: will call this function and manage those details for you, + /// determining the file type from the filename's extension. + /// There is also , which is equivalent to this function except that it will rely on to + /// determine what type of data it is loading, much like passing a NULL for type. + /// + /// + /// If you would rather decode an image to an (a buffer of pixels in CPU memory), call instead. + /// When done with the returned texture, the app should dispose of it with a call to . + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (SDL_Texture *) Returns a new texture, or NULL on error. + public static nint LoadTextureTypedRw( + nint renderer, + nint src, + int freeSrc, + string? type + ) { + return INTERNAL_IMG_LoadTextureTyped_RW( + renderer, + src, + freeSrc, + SDL.UTF8_ToNative(type!) + ); + } - /// - /// Load an image from an SDL data source into a GPU texture. - /// - /// the SDL_Renderer to use to create the GPU texture. nint refers to a SDL_Renderer * - /// an SDL_RWops that data will be read from. nint refers to a SDL_RWops * - /// a filename extension that represent this data ("BMP", "GIF", "PNG", etc). - /// - /// - /// An SDL_Texture represents an image in GPU memory, usable by SDL's 2D Render API. This can be significantly more efficient - /// than using a CPU-bound SDL_Surface if you don't need to manipulate the image directly after loading it. - /// - /// - /// If the loaded image has transparency or a colorkey, a texture with an alpha channel will be created. Otherwise, will attempt to - /// create an SDL_Texture in the most format that most reasonably represents the image data (but in many cases, this will just end up being 32-bit RGB or 32-bit RGBA). - /// If freesrc is true, the RWops will be closed before returning, whether this function succeeds or not. reads everything it needs from the RWops during this call in any case. - /// - /// - /// Even though this function accepts a file type, may still try other decoders that are capable of detecting file type from the contents of the image data, - /// but may rely on the caller-provided type string for formats that it cannot autodetect. - /// If type is NULL, will rely solely on its ability to guess the format. - /// - /// - /// There is a separate function to read files from disk without having to deal with SDL_RWops: will call this function and manage those details for you, - /// determining the file type from the filename's extension. - /// There is also , which is equivalent to this function except that it will rely on to - /// determine what type of data it is loading, much like passing a NULL for type. - /// - /// - /// If you would rather decode an image to an (a buffer of pixels in CPU memory), call instead. - /// When done with the returned texture, the app should dispose of it with a call to . - /// - /// This function is available since SDL_image 2.0.0. - /// - /// (SDL_Texture *) Returns a new texture, or NULL on error. - public static nint LoadTextureTypedRw( - nint renderer, - nint src, - int freeSrc, - string? type - ) { - return INTERNAL_IMG_LoadTextureTyped_RW( - renderer, - src, - freeSrc, - SDL.UTF8_ToNative(type!) - ); - } + /// + /// Load an image from an SDL data source into a software surface. + /// + /// an SDL_RWops that data will be read from. nint refers to a SDL_RWops * + /// a filename extension that represent this data ("BMP", "GIF", "PNG", etc). + /// True whether to free the or not. + /// + /// + /// A is a buffer of pixels in memory accessible by the CPU. + /// Use this if you plan to hand the data to something else or manipulate it further in code. + /// + /// + /// There are no guarantees about what format the new data will be; in many cases, will attempt to supply + /// a surface that exactly matches the provided image, but in others it might have to convert + /// (either because the image is in a format that SDL doesn't directly support or because it's compressed data that + /// could reasonably uncompress to various formats and had to pick one). + /// + /// + /// You can inspect an for its specifics, and use to then migrate to any supported format. + /// If the image format supports a transparent pixel, SDL will set the colorkey for the surface. + /// + /// + /// You can enable RLE acceleration on the surface afterwards by calling: + /// If freesrc is true, the RWops will be closed before returning, whether this function succeeds or not. + /// + /// + /// reads everything it needs from the RWops during this call in any case. + /// Even though this function accepts a file type, may still try other decoders that are capable of + /// detecting file type from the contents of the image data, but may rely on the caller-provided type string for formats that it cannot autodetect. + /// If type is NULL, will rely solely on its ability to guess the format. + /// + /// + /// There is a separate function to read files from disk without having to deal with SDL_RWops: will call this function + /// and manage those details for you, determining the file type from the filename's extension. + /// There is also which is equivalent to this function except that it will rely on to determine what type of data it is loading, much like passing a NULL for type. + /// + /// + /// If you are using SDL's 2D rendering API, there is an equivalent call to load images directly into an SDL_Texture for use by the GPU without using a software surface: callIMG_LoadTextureTyped_RW() instead. + /// When done with the returned surface, the app should dispose of it with a call to SDL_FreeSurface(). + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (SDL_Surface *) Returns a new SDL surface, or NULL on error. + public static nint LoadTypedRw( + nint src, + bool freeSrc, + string? type + ) { + return INTERNAL_IMG_LoadTyped_RW( + src, + freeSrc ? 1 : 0, + SDL.UTF8_ToNative(type!) + ); + } - /// - /// Load an image from an SDL data source into a software surface. - /// - /// an SDL_RWops that data will be read from. nint refers to a SDL_RWops * - /// a filename extension that represent this data ("BMP", "GIF", "PNG", etc). - /// True whether to free the or not. - /// - /// - /// A is a buffer of pixels in memory accessible by the CPU. - /// Use this if you plan to hand the data to something else or manipulate it further in code. - /// - /// - /// There are no guarantees about what format the new data will be; in many cases, will attempt to supply - /// a surface that exactly matches the provided image, but in others it might have to convert - /// (either because the image is in a format that SDL doesn't directly support or because it's compressed data that - /// could reasonably uncompress to various formats and had to pick one). - /// - /// - /// You can inspect an for its specifics, and use to then migrate to any supported format. - /// If the image format supports a transparent pixel, SDL will set the colorkey for the surface. - /// - /// - /// You can enable RLE acceleration on the surface afterwards by calling: - /// If freesrc is true, the RWops will be closed before returning, whether this function succeeds or not. - /// - /// - /// reads everything it needs from the RWops during this call in any case. - /// Even though this function accepts a file type, may still try other decoders that are capable of - /// detecting file type from the contents of the image data, but may rely on the caller-provided type string for formats that it cannot autodetect. - /// If type is NULL, will rely solely on its ability to guess the format. - /// - /// - /// There is a separate function to read files from disk without having to deal with SDL_RWops: will call this function - /// and manage those details for you, determining the file type from the filename's extension. - /// There is also which is equivalent to this function except that it will rely on to determine what type of data it is loading, much like passing a NULL for type. - /// - /// - /// If you are using SDL's 2D rendering API, there is an equivalent call to load images directly into an SDL_Texture for use by the GPU without using a software surface: callIMG_LoadTextureTyped_RW() instead. - /// When done with the returned surface, the app should dispose of it with a call to SDL_FreeSurface(). - /// - /// This function is available since SDL_image 2.0.0. - /// - /// (SDL_Surface *) Returns a new SDL surface, or NULL on error. - public static nint LoadTypedRw( - nint src, - bool freeSrc, - string? type - ) { - return INTERNAL_IMG_LoadTyped_RW( - src, - freeSrc ? 1 : 0, - SDL.UTF8_ToNative(type!) - ); - } + /// + /// DeInitialize + /// + /// + /// + /// This should be the last function you call in , after freeing all other resources. + /// This will unload any shared libraries it is using for various codecs. + /// + /// + /// After this call, a call to Init(0) will return 0 (no codecs loaded). + /// You can safely call to reload various codec support after this call. + /// + /// + /// Unlike other SDL satellite libraries, calls to do not stack; a single call to + /// will deinitialize everything and does not have to be paired with a matching call. + /// + /// + /// For that reason, it's considered best practices to have a single and call in your program. + /// While this isn't required, be aware of the risks of deviating from that behavior. + /// + /// + public static void Quit() { + INTERNAL_Quit(); + } - /// - /// DeInitialize - /// - /// - /// - /// This should be the last function you call in , after freeing all other resources. - /// This will unload any shared libraries it is using for various codecs. - /// - /// - /// After this call, a call to Init(0) will return 0 (no codecs loaded). - /// You can safely call to reload various codec support after this call. - /// - /// - /// Unlike other SDL satellite libraries, calls to do not stack; a single call to - /// will deinitialize everything and does not have to be paired with a matching call. - /// - /// - /// For that reason, it's considered best practices to have a single and call in your program. - /// While this isn't required, be aware of the risks of deviating from that behavior. - /// - /// - public static void Quit() { - INTERNAL_Quit(); + /// + /// Load an XPM image from a memory array. + /// + /// a null-terminated array of strings that comprise XPM data. + /// + /// + /// The returned will be an 8bpp indexed surface, if possible, otherwise it will be 32bpp. + /// If you always want 32-bit data, use instead. + /// When done with the returned surface, the app should dispose of it with a call to . + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (SDL_Surface *) Returns a new SDL surface, or NULL on error. + public static nint ReadXPMFromArray(string[] xpm) { + // Validate the input array to ensure it is not null or empty + if (xpm == null || xpm.Length == 0) { + throw new ArgumentException("XPM array cannot be null or empty.", nameof(xpm)); } - /// - /// Load an XPM image from a memory array. - /// - /// a null-terminated array of strings that comprise XPM data. - /// - /// - /// The returned will be an 8bpp indexed surface, if possible, otherwise it will be 32bpp. - /// If you always want 32-bit data, use instead. - /// When done with the returned surface, the app should dispose of it with a call to . - /// - /// This function is available since SDL_image 2.0.0. - /// - /// (SDL_Surface *) Returns a new SDL surface, or NULL on error. - public static nint ReadXPMFromArray(string[] xpm) { - // Validate the input array to ensure it is not null or empty - if (xpm == null || xpm.Length == 0) { - throw new ArgumentException("XPM array cannot be null or empty.", nameof(xpm)); - } - - // Call the internal native method - nint result = INTERNAL_ReadXPMFromArray(xpm); - - // Check if the result is a null pointer, indicating an error - if (result == nint.Zero) { - throw new InvalidOperationException("Failed to read XPM from array. SDL2_image returned a null pointer."); - } - - return result; - } + // Call the internal native method + nint result = INTERNAL_ReadXPMFromArray(xpm); - /// - /// Load an XPM image from a memory array. - /// - /// a null-terminated array of strings that comprise XPM data. - /// - /// - /// The returned surface will always be a 32-bit RGB surface. If you want 8-bit indexed colors (and the XPM data allows it), use instead. - /// When done with the returned surface, the app should dispose of it with a call to . - /// - /// This function is available since SDL_image 2.6.0. - /// - /// (SDL_Surface *) Returns a new SDL surface, or NULL on error. - public static nint ReadXPMFromArrayToRGB888(string[] xpm) { - // Validate the input array to ensure it is not null or empty - if (xpm == null || xpm.Length == 0) { - throw new ArgumentException("XPM array cannot be null or empty.", nameof(xpm)); - } - - // Call the internal native method - nint result = INTERNAL_ReadXPMFromArrayToRGB888(xpm); - - // Check if the result is a null pointer, indicating an error - if (result == nint.Zero) { - throw new InvalidOperationException("Failed to read XPM from array to RGB888. SDL2_image returned a null pointer."); - } - - return result; + // Check if the result is a null pointer, indicating an error + if (result == nint.Zero) { + throw new InvalidOperationException("Failed to read XPM from array. SDL2_image returned a null pointer."); } - /// - /// Save an SDL_Surface into a JPEG image file. - /// - /// the SDL surface to save. nint refers to a SDL_Surface * - /// path on the filesystem to write new file to. - /// - /// - /// If the file already exists, it will be overwritten. - /// - /// This function is available since SDL_image 2.0.2. - /// - /// (int) Returns 0 if successful, -1 on error. - public static int SaveJpg(nint surface, string file, int quality) { - return INTERNAL_IMG_SaveJPG( - surface, - SDL.UTF8_ToNative(file), - quality - ); - } + return result; + } - /// - /// Save an SDL_Surface into JPEG image data, via an SDL_RWops. - /// - /// the SDL surface to save. nint refers to a SDL_Surface * - /// the SDL_RWops to save the image data to. nint refers to a SDL_RWops * - /// True whether to free the destination after saving - /// The quality of the image. [0;33] Low, [34;66] Medium, [67;100] High - /// - /// - /// If you just want to save to a filename, you can use instead. - /// - /// This function is available since SDL_image 2.0.2. - /// - /// (int) Returns 0 if successful, -1 on error. - public static int SaveJpgRw(nint surface, nint dst, bool freeDst, int quality) { - // Validate the quality parameter to ensure it is within the acceptable range (e.g., 0-100) - if (quality < 0 || quality > 100) { - throw new ArgumentOutOfRangeException(nameof(quality), "Quality must be between 0 and 100."); - } - - // Validate the surface and destination pointers to ensure they are not null - if (surface == nint.Zero) { - throw new ArgumentNullException(nameof(surface), "Surface pointer cannot be null."); - } - - if (dst == nint.Zero) { - throw new ArgumentNullException(nameof(dst), "Destination pointer cannot be null."); - } - - // Call the internal native method and handle any potential errors - int result = INTERNAL_SaveJpgRw(surface, dst, freeDst ? 1 : 0, quality); - if (result != 0) { - throw new InvalidOperationException($"Failed to save JPG. SDL2_image returned error code: {result}"); - } - - return result; + /// + /// Load an XPM image from a memory array. + /// + /// a null-terminated array of strings that comprise XPM data. + /// + /// + /// The returned surface will always be a 32-bit RGB surface. If you want 8-bit indexed colors (and the XPM data allows it), use instead. + /// When done with the returned surface, the app should dispose of it with a call to . + /// + /// This function is available since SDL_image 2.6.0. + /// + /// (SDL_Surface *) Returns a new SDL surface, or NULL on error. + public static nint ReadXPMFromArrayToRGB888(string[] xpm) { + // Validate the input array to ensure it is not null or empty + if (xpm == null || xpm.Length == 0) { + throw new ArgumentException("XPM array cannot be null or empty.", nameof(xpm)); } + // Call the internal native method + nint result = INTERNAL_ReadXPMFromArrayToRGB888(xpm); - /// - /// Save an SDL_Surface into a PNG image file. - /// - /// the SDL surface to save. nint refers to a SDL_Surface * - /// path on the filesystem to write new file to. - /// - /// - /// If the file already exists, it will be overwritten. - /// - /// This function is available since SDL_image 2.0.0. - /// - /// (int) Returns 0 if successful, -1 on error. - public static int SavePng(nint surface, string file) { - return INTERNAL_IMG_SavePNG( - surface, - SDL.UTF8_ToNative(file) - ); + // Check if the result is a null pointer, indicating an error + if (result == nint.Zero) { + throw new InvalidOperationException("Failed to read XPM from array to RGB888. SDL2_image returned a null pointer."); } - /// - /// Save an SDL_Surface into PNG image data, via an SDL_RWops. - /// - /// the SDL surface to save. nint refers to a SDL_Surface * - /// the SDL_RWops to save the image data to. nint refers to a SDL_RWops * - /// True to free the destination after saving - /// - /// - /// If you just want to save to a filename, you can use instead. - /// - /// This function is available since SDL_image 2.0.0. - /// - /// (int) Returns 0 if successful, -1 on error. - public static int SavePngRw(nint surface, nint dst, bool freeDst) { - // Validate the surface pointer to ensure it is not null - if (surface == nint.Zero) { - throw new ArgumentNullException(nameof(surface), "Surface pointer cannot be null."); - } - - // Validate the destination pointer to ensure it is not null - if (dst == nint.Zero) { - throw new ArgumentNullException(nameof(dst), "Destination pointer cannot be null."); - } - - // Call the internal native method and handle any potential errors - int result = INTERNAL_SavePngRw(surface, dst, freeDst ? 1 : 0); - if (result != 0) { - throw new InvalidOperationException($"Failed to save PNG. SDL2_image returned error code: {result}"); - } - - return result; - } + return result; + } - [LibraryImport(nativeLibName, EntryPoint = "IMG_Linked_Version")] - [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static partial nint INTERNAL_IMG_Linked_Version(); - [LibraryImport(nativeLibName, EntryPoint = "IMG_Load")] - [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static partial nint INTERNAL_IMG_Load(byte[] file); - - [LibraryImport(nativeLibName, EntryPoint = "IMG_LoadTexture")] - [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static partial nint INTERNAL_IMG_LoadTexture( - nint renderer, - byte[] file + /// + /// Save an SDL_Surface into a JPEG image file. + /// + /// the SDL surface to save. nint refers to a SDL_Surface * + /// path on the filesystem to write new file to. + /// + /// + /// If the file already exists, it will be overwritten. + /// + /// This function is available since SDL_image 2.0.2. + /// + /// (int) Returns 0 if successful, -1 on error. + public static int SaveJpg(nint surface, string file, int quality) { + return INTERNAL_IMG_SaveJPG( + surface, + SDL.UTF8_ToNative(file), + quality ); + } - [LibraryImport(nativeLibName, EntryPoint = "IMG_LoadTextureTyped_RW")] - [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static partial nint INTERNAL_IMG_LoadTextureTyped_RW( - nint renderer, - nint src, - int freeSrc, - byte[] type - ); + /// + /// Save an SDL_Surface into JPEG image data, via an SDL_RWops. + /// + /// the SDL surface to save. nint refers to a SDL_Surface * + /// the SDL_RWops to save the image data to. nint refers to a SDL_RWops * + /// True whether to free the destination after saving + /// The quality of the image. [0;33] Low, [34;66] Medium, [67;100] High + /// + /// + /// If you just want to save to a filename, you can use instead. + /// + /// This function is available since SDL_image 2.0.2. + /// + /// (int) Returns 0 if successful, -1 on error. + public static int SaveJpgRw(nint surface, nint dst, bool freeDst, int quality) { + // Validate the quality parameter to ensure it is within the acceptable range (e.g., 0-100) + if (quality < 0 || quality > 100) { + throw new ArgumentOutOfRangeException(nameof(quality), "Quality must be between 0 and 100."); + } - [LibraryImport(nativeLibName, EntryPoint = "IMG_LoadTyped_RW")] - [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static partial nint INTERNAL_IMG_LoadTyped_RW( - nint src, - int freeSrc, - byte[] type - ); + // Validate the surface and destination pointers to ensure they are not null + if (surface == nint.Zero) { + throw new ArgumentNullException(nameof(surface), "Surface pointer cannot be null."); + } - [LibraryImport(nativeLibName, EntryPoint = "IMG_SaveJPG")] - [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static partial int INTERNAL_IMG_SaveJPG( - nint surface, - byte[] file, - int quality - ); + if (dst == nint.Zero) { + throw new ArgumentNullException(nameof(dst), "Destination pointer cannot be null."); + } - [LibraryImport(nativeLibName, EntryPoint = "IMG_SavePNG")] - [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static partial int INTERNAL_IMG_SavePNG( - nint surface, - byte[] file - ); + // Call the internal native method and handle any potential errors + int result = INTERNAL_SaveJpgRw(surface, dst, freeDst ? 1 : 0, quality); + if (result != 0) { + throw new InvalidOperationException($"Failed to save JPG. SDL2_image returned error code: {result}"); + } - [LibraryImport(nativeLibName, EntryPoint = "IMG_Init")] - [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static partial int INTERNAL_Init(InitOptions flags); - [LibraryImport(nativeLibName, EntryPoint = "IMG_Load_RW")] - [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static partial nint INTERNAL_LoadRw( - nint src, - int freeSrc - ); + return result; + } - [LibraryImport(nativeLibName, EntryPoint = "IMG_LoadTexture_RW")] - [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static partial nint INTERNAL_LoadTextureRw( - nint renderer, - nint src, - int freeSrc - ); - [LibraryImport(nativeLibName, EntryPoint = "IMG_Quit")] - [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static partial void INTERNAL_Quit(); + /// + /// Save an SDL_Surface into a PNG image file. + /// + /// the SDL surface to save. nint refers to a SDL_Surface * + /// path on the filesystem to write new file to. + /// + /// + /// If the file already exists, it will be overwritten. + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (int) Returns 0 if successful, -1 on error. + public static int SavePng(nint surface, string file) { + return INTERNAL_IMG_SavePNG( + surface, + SDL.UTF8_ToNative(file) + ); + } + /// + /// Save an SDL_Surface into PNG image data, via an SDL_RWops. + /// + /// the SDL surface to save. nint refers to a SDL_Surface * + /// the SDL_RWops to save the image data to. nint refers to a SDL_RWops * + /// True to free the destination after saving + /// + /// + /// If you just want to save to a filename, you can use instead. + /// + /// This function is available since SDL_image 2.0.0. + /// + /// (int) Returns 0 if successful, -1 on error. + public static int SavePngRw(nint surface, nint dst, bool freeDst) { + // Validate the surface pointer to ensure it is not null + if (surface == nint.Zero) { + throw new ArgumentNullException(nameof(surface), "Surface pointer cannot be null."); + } - [LibraryImport(nativeLibName, EntryPoint = "IMG_ReadXPMFromArray")] - [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static partial nint INTERNAL_ReadXPMFromArray( - [In()] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] - string[] xpm - ); + // Validate the destination pointer to ensure it is not null + if (dst == nint.Zero) { + throw new ArgumentNullException(nameof(dst), "Destination pointer cannot be null."); + } - [LibraryImport(nativeLibName, EntryPoint = "IMG_ReadXPMFromArrayToRGB888")] - [UnmanagedCallConv (CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static partial nint INTERNAL_ReadXPMFromArrayToRGB888( - [In()] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] - string[] xpm); - - [LibraryImport(nativeLibName, EntryPoint = "IMG_SaveJPG_RW")] - [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static partial int INTERNAL_SaveJpgRw( - nint surface, - nint dst, - int freeDst, - int quality - ); + // Call the internal native method and handle any potential errors + int result = INTERNAL_SavePngRw(surface, dst, freeDst ? 1 : 0); + if (result != 0) { + throw new InvalidOperationException($"Failed to save PNG. SDL2_image returned error code: {result}"); + } - [LibraryImport(nativeLibName, EntryPoint = "IMG_SavePNG_RW")] - [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] - private static partial int INTERNAL_SavePngRw( - nint surface, - nint dst, - int freeDst - ); - #endregion + return result; } + + [LibraryImport(nativeLibName, EntryPoint = "IMG_Linked_Version")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_IMG_Linked_Version(); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_Load")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_IMG_Load(byte[] file); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_LoadTexture")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_IMG_LoadTexture( + nint renderer, + byte[] file + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_LoadTextureTyped_RW")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_IMG_LoadTextureTyped_RW( + nint renderer, + nint src, + int freeSrc, + byte[] type + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_LoadTyped_RW")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_IMG_LoadTyped_RW( + nint src, + int freeSrc, + byte[] type + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_SaveJPG")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial int INTERNAL_IMG_SaveJPG( + nint surface, + byte[] file, + int quality + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_SavePNG")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial int INTERNAL_IMG_SavePNG( + nint surface, + byte[] file + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_Init")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial int INTERNAL_Init(InitOptions flags); + [LibraryImport(nativeLibName, EntryPoint = "IMG_Load_RW")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_LoadRw( + nint src, + int freeSrc + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_LoadTexture_RW")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_LoadTextureRw( + nint renderer, + nint src, + int freeSrc + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_Quit")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial void INTERNAL_Quit(); + + + [LibraryImport(nativeLibName, EntryPoint = "IMG_ReadXPMFromArray")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_ReadXPMFromArray( + [In()] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] + string[] xpm + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_ReadXPMFromArrayToRGB888")] + [UnmanagedCallConv (CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint INTERNAL_ReadXPMFromArrayToRGB888( + [In()] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] + string[] xpm); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_SaveJPG_RW")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial int INTERNAL_SaveJpgRw( + nint surface, + nint dst, + int freeDst, + int quality + ); + + [LibraryImport(nativeLibName, EntryPoint = "IMG_SavePNG_RW")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial int INTERNAL_SavePngRw( + nint surface, + nint dst, + int freeDst + ); + #endregion } \ No newline at end of file