281 lines
7.9 KiB
C#
281 lines
7.9 KiB
C#
|
/* 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 <http://www.gnu.org/licenses/>.*/
|
||
|
|
||
|
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<Frame> m_frames = new List<Frame>();
|
||
|
|
||
|
#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
|
||
|
}
|
||
|
}
|