From 6cff1b96d4e7f18688d218a0e2eba3977a7722bd Mon Sep 17 00:00:00 2001 From: Crsky Date: Sun, 12 Apr 2026 18:49:53 +0800 Subject: [PATCH] Extract WebP Codec --- ArcFormats/ArcFormats.csproj | 1 + ArcFormats/Artemis/ImageNekoPNG.cs | 39 ++---------------- ArcFormats/WebPCodec.cs | 64 ++++++++++++++++++++++++++++++ ArcFormats/YuRis/ImageYDG.cs | 37 ++--------------- 4 files changed, 72 insertions(+), 69 deletions(-) create mode 100644 ArcFormats/WebPCodec.cs diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index 64fbc3d5..f74ca076 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -278,6 +278,7 @@ + diff --git a/ArcFormats/Artemis/ImageNekoPNG.cs b/ArcFormats/Artemis/ImageNekoPNG.cs index e70af69d..cf95a60a 100644 --- a/ArcFormats/Artemis/ImageNekoPNG.cs +++ b/ArcFormats/Artemis/ImageNekoPNG.cs @@ -65,10 +65,10 @@ namespace GameRes.Formats.Artemis data[j] -= (byte)(0x77 * j); var slice_width = 0; var slice_height = 0; - if (1 != WebPGetInfo (data, (UIntPtr)data.Length, ref slice_width, ref slice_height)) + if (1 != WebPCodec.WebPGetInfo(data, (UIntPtr)data.Length, ref slice_width, ref slice_height)) throw new InvalidFormatException("WebP image decoder failed."); var slice_size = stride * slice_height; - if (IntPtr.Zero == WebPDecodeBGRAInto (data, (UIntPtr)data.Length, output, (UIntPtr)slice_size, stride)) + if (IntPtr.Zero == WebPCodec.WebPDecodeBGRAInto (data, (UIntPtr)data.Length, output, (UIntPtr)slice_size, stride)) throw new InvalidFormatException("WebP image decoder failed."); output += slice_size; } @@ -94,7 +94,7 @@ namespace GameRes.Formats.Artemis offset[i] = file.ReadInt32(); for (var i = 0; i < 8; i++) length[i] = file.ReadInt32(); - LibWebPLoader.Load(); + WebPCodec.Load(); var image_width = 0; var image_height = 0; for (var i = 0; i < 8; i++) @@ -111,7 +111,7 @@ namespace GameRes.Formats.Artemis webp_header[j] -= (byte)(0x77 * j); var slice_width = 0; var slice_height = 0; - if (1 != WebPGetInfo (webp_header, (UIntPtr)webp_header.Length, ref slice_width, ref slice_height)) + if (1 != WebPCodec.WebPGetInfo (webp_header, (UIntPtr)webp_header.Length, ref slice_width, ref slice_height)) throw new InvalidFormatException ("WebP image decoder failed."); image_width = Math.Max (image_width, slice_width); image_height += slice_height; @@ -130,36 +130,5 @@ namespace GameRes.Formats.Artemis { throw new NotImplementedException("ImageNekoPNG.Write not implemented"); } - - [DllImport("libwebp.dll", EntryPoint = "WebPGetInfo", CallingConvention = CallingConvention.Cdecl)] - public static extern int WebPGetInfo ([MarshalAs(UnmanagedType.LPArray)] byte[] data, UIntPtr data_size, ref int width, ref int height); - - [DllImport("libwebp.dll", EntryPoint = "WebPDecodeBGRAInto", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr WebPDecodeBGRAInto ([MarshalAs(UnmanagedType.LPArray)] byte[] data, UIntPtr data_size, IntPtr output_buffer, UIntPtr output_buffer_size, int output_stride); - } - - internal static class LibWebPLoader - { - [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)] - static extern IntPtr LoadLibraryEx (string lpFileName, IntPtr hReservedNull, uint dwFlags); - - static bool loaded = false; - - const uint LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100; - const uint LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800; - - public static void Load () - { - if (loaded) - return; - var folder = Path.GetDirectoryName (Assembly.GetExecutingAssembly().Location); - folder = Path.Combine (folder, (IntPtr.Size == 4) ? "x86" : "x64"); - var fullPath = Path.Combine (folder, "libwebp.dll"); - fullPath = Path.GetFullPath (fullPath); - var handle = LoadLibraryEx (fullPath, IntPtr.Zero, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32); - if (IntPtr.Zero == handle) - throw new Win32Exception (Marshal.GetLastWin32Error()); - loaded = true; - } } } diff --git a/ArcFormats/WebPCodec.cs b/ArcFormats/WebPCodec.cs new file mode 100644 index 00000000..a13bd0d7 --- /dev/null +++ b/ArcFormats/WebPCodec.cs @@ -0,0 +1,64 @@ +//! \file WebPCodec.cs +//! \date Sun Apr 12 2026 +//! \brief Google WebP image format. +// +// Copyright (C) 2016 by morkt +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// + +using System; +using System.ComponentModel; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace GameRes.Formats +{ + public class WebPCodec + { + [DllImport("libwebp.dll", EntryPoint = "WebPGetInfo", CallingConvention = CallingConvention.Cdecl)] + public static extern int WebPGetInfo ([MarshalAs(UnmanagedType.LPArray)] byte[] data, UIntPtr data_size, ref int width, ref int height); + + [DllImport("libwebp.dll", EntryPoint = "WebPDecodeBGRAInto", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr WebPDecodeBGRAInto ([MarshalAs(UnmanagedType.LPArray)] byte[] data, UIntPtr data_size, IntPtr output_buffer, UIntPtr output_buffer_size, int output_stride); + + [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)] + static extern IntPtr LoadLibraryEx (string lpFileName, IntPtr hReservedNull, uint dwFlags); + + static bool loaded = false; + + const uint LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100; + const uint LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800; + + public static void Load () + { + if (loaded) + return; + var dir = Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location); + dir = Path.Combine (dir, (IntPtr.Size == 4) ? "x86" : "x64"); + var path = Path.Combine (dir, "libwebp.dll"); + path = Path.GetFullPath (path); + var lib = LoadLibraryEx (path, IntPtr.Zero, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32); + if (IntPtr.Zero == lib) + throw new Win32Exception (Marshal.GetLastWin32Error ()); + loaded = true; + } + } +} diff --git a/ArcFormats/YuRis/ImageYDG.cs b/ArcFormats/YuRis/ImageYDG.cs index 31eb66e9..8aeae9b8 100644 --- a/ArcFormats/YuRis/ImageYDG.cs +++ b/ArcFormats/YuRis/ImageYDG.cs @@ -174,11 +174,11 @@ namespace GameRes.Formats.YuRis byte[] DecodeWebP (byte[] data, out int width, out int height) { - LibWebPLoader.Load (); + WebPCodec.Load (); width = 0; height = 0; - if (1 != WebPGetInfo (data, (UIntPtr)data.Length, ref width, ref height)) + if (1 != WebPCodec.WebPGetInfo(data, (UIntPtr)data.Length, ref width, ref height)) throw new InvalidFormatException ("WebP image decoder failed."); int stride = width * 4; @@ -186,7 +186,7 @@ namespace GameRes.Formats.YuRis var handle = GCHandle.Alloc (output, GCHandleType.Pinned); try { - if (IntPtr.Zero == WebPDecodeBGRAInto (data, (UIntPtr)data.Length, + if (IntPtr.Zero == WebPCodec.WebPDecodeBGRAInto (data, (UIntPtr)data.Length, handle.AddrOfPinnedObject (), (UIntPtr)output.Length, stride)) { throw new InvalidFormatException ("WebP image decoder failed."); @@ -324,36 +324,5 @@ namespace GameRes.Formats.YuRis return run; } } - - [DllImport("libwebp.dll", EntryPoint = "WebPGetInfo", CallingConvention = CallingConvention.Cdecl)] - public static extern int WebPGetInfo([MarshalAs(UnmanagedType.LPArray)] byte[] data, UIntPtr data_size, ref int width, ref int height); - - [DllImport("libwebp.dll", EntryPoint = "WebPDecodeBGRAInto", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr WebPDecodeBGRAInto([MarshalAs(UnmanagedType.LPArray)] byte[] data, UIntPtr data_size, IntPtr output_buffer, UIntPtr output_buffer_size, int output_stride); - } - - internal static class LibWebPLoader - { - [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)] - static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, uint dwFlags); - - static bool loaded = false; - - const uint LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100; - const uint LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800; - - public static void Load() - { - if (loaded) - return; - var folder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - folder = Path.Combine(folder, (IntPtr.Size == 4) ? "x86" : "x64"); - var fullPath = Path.Combine(folder, "libwebp.dll"); - fullPath = Path.GetFullPath(fullPath); - var handle = LoadLibraryEx(fullPath, IntPtr.Zero, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32); - if (IntPtr.Zero == handle) - throw new Win32Exception(Marshal.GetLastWin32Error()); - loaded = true; - } } }