欢迎光临散文网 会员登陆 & 注册

pvz一代特殊图像格式分析——texTV系列

2021-11-17 00:37 作者:萌新迎风听雨  | 我要投稿

声明:本教程内容包含:ptx2X系列编码解码、ptxPS3系列图像查看、texTV系列编码解码、texiOS系列编码解码、txz图像编码解码,若你根据本教程写出了对应工具,请务必注明是参考了本教程。

一代在TV版和iOS版均出现过tex格式,不过两种tex文件结构并不相同,这里介绍TV版的tex格式,后续更新iOS版格式介绍。

使用十六进制编辑器打开TV版中的crazydave-atlas1.tex,可以看到0x0开始的8个字节显然是文件魔数(在文件起始位置用于标识文件类型的内容),0x8开始4个字节应该都是00,猜测0xC开始4字节和0x10开始4字节的内容是图像宽度或高度,0x14开始的12个字节暂时不知道是什么意思,0x20开始的4字节内容正好是文件大小-0x30,也就是从0x30开始到文件末的大小,后面跟着12字节的00。

0x30出现了78 9C,正好是zlib压缩的文件魔数,于是删除掉前面0x30的数据,对整个后续内容进行zlib解压,得到了一个大小为1708032字节的文件,1708032=512*1668*2,也就是说2字节=1像素rgba颜色,而根据图像名字来看应该是戴夫图像,这张图像在dz解包中出现过半透明的像素,使用rgb565或rgba5551来存储不合适,所以猜测图像为rgba4444压缩。用此格式将其转为png后,得到图像如图,发现图像轮廓没问题,但是颜色有问题。

于是使用十六进制编辑器打开解压后的文件,发现开头都是FF 0F,而此图像左上角一开始就是透明的,所以alpha通道肯定对应那个0,猜测其为argb4444存储,对应方式解码后,得到正确图像。

texTV共有两种格式,02为argb8888,03为argb4444,格式02的只有一张图片。

C#代码实现:

        //编码

        public static void Save(Bitmap Pic, string outFile, int format)

        {

            if (format > 3 || format < 2)

            {

                throw new Exception("错误的格式类型:texTV" + format);

            }

            HexWriter HW = HexWriter.Create("temp");

            HW.SetPosition(0x0);

            switch (format)

            {

                case 2:

                    Save_A8R8G8B8(HW, Pic);

                    break;

                case 3:

                    Save_A4R4G4B4(HW, Pic);

                    break;

            }

            HW.Close();

            Zlib.Compress("temp", "temp2");

            HexWriter HW2 = HexWriter.Create(outFile);

            HW2.SetPosition(0x0);

            HW2.WriteUInt16(0x4553);

            HW2.WriteUInt16(0x5958);

            HW2.WriteUInt16(0x4554);

            HW2.WriteUInt16(0x58);

            HW2.WriteUInt32(0x0);

            HW2.WriteUInt32((ushort)Pic.Width);

            HW2.WriteUInt32((ushort)Pic.Height);

            HW2.WriteUInt32((ushort)format);

            HW2.WriteUInt32(0x1);

            HW2.WriteUInt32(0x1);

            HexReader HR = HexReader.Create("temp2");

            HW2.WriteInt64(HR.GetSize());

            HW2.WriteInt64(0x0);

            HR.SetPosition(0x0);

            HW2.WriteBytes(HR.ReadAll());

            HR.Close();

            HW2.Close();

            File.Delete("temp");

            File.Delete("temp2");

        }

        static void Save_A4R4G4B4(HexWriter HW, Bitmap img)

        {

            int height = img.Height;

            int width = img.Width;

            Color temp2;

            for (int i = 0; i < height; i++)

            {

                for (int j = 0; j < width; j++)

                {

                    temp2 = img.GetPixel(j, i);

                    HW.WriteUInt16((ushort)(((temp2.A & 0xF0) << 8) + ((temp2.B & 0xF0) >> 4) + (temp2.G & 0xF0) + ((temp2.R & 0xF0) << 4)));

                }

            }

        }

        static void Save_A8R8G8B8(HexWriter HW, Bitmap img)

        {

            int height = img.Height;

            int width = img.Width;

            Color temp2;

            for (int i = 0; i < height; i++)

            {

                for (int j = 0; j < width; j++)

                {

                    temp2 = img.GetPixel(j, i);

                    HW.WriteByte(temp2.B);

                    HW.WriteByte(temp2.G);

                    HW.WriteByte(temp2.R);

                    HW.WriteByte(temp2.A);

                }

            }

        }

        //编码

        public static Bitmap Get(string fileName)

        {

                HexReader HR = HexReader.Create(fileName);

                //这是TV版tex

                HR.SetPosition(0xC);

                int width = HR.ReadInt32();

                int height = HR.ReadInt32();

                int format = HR.ReadInt32();

                HR.AddPosition(0x18);

                FileStream a = new FileStream("temp", FileMode.Create);

                HR.CopyTo(a);

                a.Close();

                Zlib.Decompress("temp", "temp2");

                Bitmap ans;

                HexReader c = HexReader.Create("temp2");

                switch (format)

                {

                    case 2:

                        ans = Get_A8R8G8B8(c, height, width);

                        break;

                    case 3:

                        ans = Get_A4R4G4B4(c, height, width);

                        break;

                    default:

                        ans = null;

                        break;

                }

                c.Close();

                File.Delete("temp");

                File.Delete("temp2");

                return ans;

        }

        static Bitmap Get_A8R8G8B8(HexReader HR, int height, int width)

        {

            Bitmap img = new Bitmap(width, height);

            byte a;

            byte r;

            byte g;

            byte b;

            LockBitmap img2 = new LockBitmap(img);

            img2.LockBits();

            for (int i = 0; i < height; i++)

            {

                for (int j = 0; j < width; j++)

                {

                    b = HR.ReadByte();

                    g = HR.ReadByte();

                    r = HR.ReadByte();

                    a = HR.ReadByte();

                    img2.SetPixel(j, i, Color.FromArgb(a, r, g, b));

                }

            }

            img2.UnlockBits();

            return img;

        }

        static Bitmap Get_A4R4G4B4(HexReader HR, int height, int width)

        {

            Bitmap img = new Bitmap(width, height);

            int a;

            int r;

            int g;

            int b;

            byte temp;

            LockBitmap img2 = new LockBitmap(img);

            img2.LockBits();

            for (int i = 0; i < height; i++)

            {

                for (int j = 0; j < width; j++)

                {

                    temp = HR.ReadByte();

                    g = ((temp & 0xF0) >> 4) * 17;

                    b = (temp & 0xF) * 17;

                    temp = HR.ReadByte();

                    a = ((temp & 0xF0) >> 4) * 17;

                    r = (temp & 0xF) * 17;

                    img2.SetPixel(j, i, Color.FromArgb(a, r, g, b));

                }

            }

            img2.UnlockBits();

            return img;

        }

pvz一代特殊图像格式分析——texTV系列的评论 (共 条)

分享到微博请遵守国家法律