/* HaRepacker - WZ extractor and repacker * Copyright (C) 2009, 2010 haha01haha01 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. If not, see .*/ namespace SharpApng { using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using uGIF; using UnityEngine; public class Frame : IDisposable { #region Fields private Image m_bmp; private int m_den; private int m_num; #endregion Fields #region Constructors public Frame(Image bmp, int num, int den) { this.m_num = num; this.m_den = den; this.m_bmp = bmp; } #endregion Constructors #region Properties public Image Bitmap { get { return m_bmp; } set { m_bmp = value; } } public int DelayDen { get { return m_den; } set { m_den = value; } } public int DelayNum { get { return m_num; } set { m_num = value; } } #endregion Properties #region Methods public void Dispose() { } #endregion Methods } internal class Apng : IDisposable { #region Fields private List m_frames = new List(); #endregion Fields #region Constructors public Apng() { } #endregion Constructors #region Indexers public Frame this[int index] { get { if (index < m_frames.Count) return m_frames[index]; else return null; } set { if (index < m_frames.Count) m_frames[index] = value; } } #endregion Indexers #region Methods public void AddFrame(Frame frame) { m_frames.Add(frame); } public void AddFrame(Image bmp, int num, int den) { m_frames.Add(new Frame(bmp, num, den)); } public void Dispose() { foreach (Frame frame in m_frames) frame.Dispose(); m_frames.Clear(); } public void WriteApng(string path, bool firstFrameHidden, bool disposeAfter) { Size maxSize = new Size(m_frames.Max(f => f.Bitmap.width), m_frames.Max(f => f.Bitmap.height)); for (int i = 0; i < m_frames.Count; i++) { Frame frame = m_frames[i]; //if (frame.Bitmap.Width != maxSize.Width || frame.Bitmap.Height != maxSize.Height) //frame.Bitmap = ExtendImage(frame.Bitmap, maxSize); ApngBasicWrapper.CreateFrameManaged(frame.Bitmap, frame.DelayNum, frame.DelayDen, i); } ApngBasicWrapper.SaveApngManaged(path, m_frames.Count, maxSize.Width, maxSize.Height, firstFrameHidden); if (disposeAfter) Dispose(); } private static Image ExtendImage(Image source, Size newSize) { Image result = new Image(newSize.Width, newSize.Height); //using (Graphics g = Graphics.FromImage(result)) //{ // g.DrawImageUnscaled(source, 0, 0); //} return result; } #endregion Methods } internal static class ApngBasicWrapper { #region Fields private const string apngdll = "apng64.dll"; private const int PIXEL_DEPTH = 4; #endregion Fields #region Methods internal static void CreateFrameManaged(Image source, int num, int den, int i) { IntPtr ptr = MarshalByteArray(TranslateImage(source)); CreateFrame(ptr, num, den, i, source.width * source.height * PIXEL_DEPTH); ReleaseData(ptr); } internal static void SaveApngManaged(string path, int frameCount, int width, int height, bool firstFrameHidden) { IntPtr pathPtr = MarshalString(path); byte firstFrame = firstFrameHidden ? (byte)1 : (byte)0; SaveAPNG(pathPtr, frameCount, width, height, PIXEL_DEPTH, firstFrame); var bufferSize = GetBufferSize(); //Call and return the pointer IntPtr returnedPtr = GetBufferContent(); //Create new Variable to Store the result byte[] returnedResult = new byte[bufferSize]; //Copy from result pointer to the C# variable Marshal.Copy(returnedPtr, returnedResult, 0, bufferSize); File.WriteAllBytes(path, returnedResult); Debug.Log("saved"); ReleaseData(pathPtr); } [DllImport(apngdll, CallingConvention = CallingConvention.StdCall)] private static extern void CreateFrame(IntPtr pdata, int num, int den, int i, int len); [DllImport(apngdll)] private static extern void SaveAPNG(IntPtr path, int frameCount, int width, int height, int bytesPerPixel, byte firstFrameHidden); [DllImport(apngdll)] private static extern int GetBufferSize(); [DllImport(apngdll)] private static extern IntPtr GetBufferContent(); private static IntPtr MarshalByteArray(byte[] source) { int size = Marshal.SizeOf(source[0]) * source.Length; IntPtr pnt = Marshal.AllocHGlobal(size); Marshal.Copy(source, 0, pnt, source.Length); return pnt; } private static IntPtr MarshalString(string source) { byte[] toMarshal = Encoding.ASCII.GetBytes(source); int size = Marshal.SizeOf(source[0]) * source.Length; IntPtr pnt = Marshal.AllocHGlobal(size + Marshal.SizeOf(source[0])); Marshal.Copy(toMarshal, 0, pnt, source.Length); //Marshal.Copy(new byte[] { 0 }, 0, new IntPtr(pnt.ToInt32() + size), 1); return pnt; } private static void ReleaseData(IntPtr ptr) { Marshal.FreeHGlobal(ptr); } static byte[] TranslateImage(Image texture) { int width = texture.width, height = texture.height; Color32[] original = new Color32[texture.pixels.Length]; texture.pixels.CopyTo(original, 0); byte[] result = new byte[texture.width * texture.height * PIXEL_DEPTH]; int p = 0; Debug.Log("1"); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int index = (y * width + x); int index2 = ((height-y-1) * width + x); result[index * PIXEL_DEPTH] = original[index2].b; result[index * PIXEL_DEPTH + 1] = original[index2].g; result[index * PIXEL_DEPTH + 2] = original[index2].r; result[index * PIXEL_DEPTH + 3] = original[index2].a; } p += 1; } Debug.Log("2"); return result; } #endregion Methods } }