private static byte[] PixelBytesFromImage(Bitmap bmp, PsbPixelFormat pixelFormat = PsbPixelFormat.None) { BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); int stride = bmpData.Stride; // 扫描线的宽度 int offset = stride - bmp.Width; // 显示宽度与扫描线宽度的间隙 IntPtr iptr = bmpData.Scan0; // 获取bmpData的内存起始位置 int scanBytes = stride * bmp.Height; // 用stride宽度,表示这是内存区域的大小 var result = new byte[scanBytes]; System.Runtime.InteropServices.Marshal.Copy(iptr, result, 0, scanBytes); bmp.UnlockBits(bmpData); // 解锁内存区域 switch (pixelFormat) { case PsbPixelFormat.WinRGBA4444: result = Rgba428(result, false); break; case PsbPixelFormat.CommonRGBA8: Rgba2Argb(ref result); break; case PsbPixelFormat.DXT5: //Rgba2Argb(ref result); result = DxtUtil.Dxt5Encode(result, bmp.Width, bmp.Height); break; } return(result); }
public static byte[] GetPixelBytesFromImage(Image image, PsbPixelFormat pixelFormat = PsbPixelFormat.None) { if (!(image is Bitmap bmp)) { bmp = new Bitmap(image); } return(PixelBytesFromImage(bmp, pixelFormat)); }
/// <summary> /// Whether the <see cref="PsbPixelFormat"/> use palette /// </summary> /// <param name="format"></param> /// <returns></returns> public static bool UsePalette(this PsbPixelFormat format) { switch (format) { case PsbPixelFormat.CI8_SW: return(true); default: return(false); } }
public static Bitmap ConvertToImage(byte[] data, byte[] palette, int height, int width, PsbPixelFormat colorFormat, PsbPixelFormat paletteColorFormat) { //Copy data & palette to avoid changing original Data (might be reused) if (palette != null && palette.Length > 0) { return(ConvertToImageWithPalette(data.ToArray(), palette.ToArray(), height, width, colorFormat, paletteColorFormat)); } return(ConvertToImage(data.ToArray(), height, width, colorFormat)); }
public static Bitmap UncompressToImage(byte[] data, int height, int width, PsbPixelFormat colorFormat = PsbPixelFormat.None, int align = 4) { byte[] bytes; try { bytes = Uncompress(data, height, width, align); } catch (Exception e) { throw new BadImageFormatException("data incorrect", e); } return(ConvertToImage(bytes, height, width, colorFormat)); }
public static Bitmap ConvertToImageWithPalette(byte[] data, byte[] palette, int height, int width, PsbPixelFormat colorFormat = PsbPixelFormat.None, PsbPixelFormat paletteColorFormat = PsbPixelFormat.None) { Bitmap bmp; BitmapData bmpData; switch (paletteColorFormat) { case PsbPixelFormat.CommonRGBA8: Switch_0_2(ref palette); break; } switch (colorFormat) { case PsbPixelFormat.CI8_SW: bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed); bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bmp.PixelFormat); ColorPalette pal = bmp.Palette; for (int i = 0; i < 256; i++) { pal.Entries[i] = Color.FromArgb(BitConverter.ToInt32(palette, i * 4)); } // Assign the edited palette to the bitmap. bmp.Palette = pal; data = PostProcessing.UnswizzleTexture(data, bmp.Width, bmp.Height, bmp.PixelFormat); //Switch_0_2(ref data); break; default: return(ConvertToImage(data, height, width, colorFormat)); } int stride = bmpData.Stride; // 扫描线的宽度 int offset = stride - width; // 显示宽度与扫描线宽度的间隙 IntPtr iptr = bmpData.Scan0; // 获取bmpData的内存起始位置 int scanBytes = stride * height; // 用stride宽度,表示这是内存区域的大小 if (scanBytes >= data.Length) { System.Runtime.InteropServices.Marshal.Copy(data, 0, iptr, data.Length); bmp.UnlockBits(bmpData); // 解锁内存区域 return(bmp); } throw new BadImageFormatException("data may not corresponding"); }
public static void ConvertToImageFile(byte[] data, string path, int height, int width, PsbImageFormat format, PsbPixelFormat colorFormat = PsbPixelFormat.None, byte[] palette = null, PsbPixelFormat paletteColorFormat = PsbPixelFormat.None) { Bitmap bmp = ConvertToImage(data, palette, height, width, colorFormat, paletteColorFormat); switch (format) { case PsbImageFormat.bmp: bmp.Save(path, ImageFormat.Bmp); break; case PsbImageFormat.png: bmp.Save(path, ImageFormat.Png); break; } }
public static void ConvertToImageFile(byte[] data, string path, int height, int width, PsbImageFormat format, PsbPixelFormat colorFormat = PsbPixelFormat.None) { var bmp = ConvertToImage(data, height, width, colorFormat); switch (format) { case PsbImageFormat.Bmp: bmp.Save(path, ImageFormat.Bmp); break; case PsbImageFormat.Png: bmp.Save(path, ImageFormat.Png); break; } }
public static string ToStringForPsb(this PsbPixelFormat pixelFormat) { switch (pixelFormat) { case PsbPixelFormat.None: case PsbPixelFormat.WinRGBA8: case PsbPixelFormat.CommonRGBA8: return("RGBA8"); case PsbPixelFormat.DXT5: return("DXT5"); case PsbPixelFormat.WinRGBA4444: return("RGBA4444"); default: throw new ArgumentOutOfRangeException(nameof(pixelFormat), pixelFormat, null); } }
public static Bitmap ConvertToImage(byte[] data, int height, int width, PsbPixelFormat colorFormat = PsbPixelFormat.None) { Bitmap bmp; BitmapData bmpData; { bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bmp.PixelFormat); } switch (colorFormat) { case PsbPixelFormat.WinRGBA4444: data = Rgba428(data); break; case PsbPixelFormat.CommonRGBA8: Rgba2Argb(ref data); break; case PsbPixelFormat.DXT5: //MARK: RL seems compatible to DXT5 compress? data = DxtUtil.DecompressDxt5(data, width, height); Rgba2Argb(ref data); //DXT5(for win) need conversion break; } int stride = bmpData.Stride; // 扫描线的宽度 int offset = stride - width; // 显示宽度与扫描线宽度的间隙 IntPtr iptr = bmpData.Scan0; // 获取bmpData的内存起始位置 int scanBytes = stride * height; // 用stride宽度,表示这是内存区域的大小 if (scanBytes >= data.Length) { System.Runtime.InteropServices.Marshal.Copy(data, 0, iptr, data.Length); bmp.UnlockBits(bmpData); // 解锁内存区域 return(bmp); } throw new BadImageFormatException("data may not corresponding"); }
/// <summary> /// Get RGBA bytes from palette /// </summary> /// <param name="palette"></param> /// <param name="palettePixelFormat"></param> /// <returns></returns> public static byte[] GetPaletteBytes(this ColorPalette palette, PsbPixelFormat palettePixelFormat) { byte[] bytes = new byte[palette.Entries.Length * 4]; for (var i = 0; i < palette.Entries.Length; i++) { //LE ARGB var color = palette.Entries[i]; bytes[i * 4] = color.B; bytes[i * 4 + 1] = color.G; bytes[i * 4 + 2] = color.R; bytes[i * 4 + 3] = color.A; var bt = BitConverter.GetBytes(color.ToArgb()); } switch (palettePixelFormat) { case PsbPixelFormat.CommonRGBA8: RL.Switch_0_2(ref bytes); break; } return(bytes); }
/// <summary> /// Split textures into parts and save to files /// </summary> /// <param name="psb">PSB</param> /// <param name="path">Save directory</param> /// <param name="option">Save option</param> /// <param name="imageFormat">Save format</param> /// <param name="pixelFormat">When save to PSB special formats, specific pixel format to use</param> public static void SplitTextureToFiles(this PSB psb, string path, PsbImageOption option = PsbImageOption.Extract, PsbImageFormat imageFormat = PsbImageFormat.Png, PsbPixelFormat pixelFormat = PsbPixelFormat.None) { if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } var source = (PsbDictionary)psb.Objects["source"]; foreach (var texPair in source) { if (!(texPair.Value is PsbDictionary tex)) { continue; } var name = texPair.Key; if (!Directory.Exists(Path.Combine(path, name))) { Directory.CreateDirectory(Path.Combine(path, name)); } var icon = (PsbDictionary)tex["icon"]; var texture = (PsbDictionary)tex["texture"]; //var mipmap = (PsbDictionary)texture["mipMap"]; //TODO: Mipmap? var md = PsbResCollector.GenerateMotionResMetadata(texture, (PsbResource)texture["pixel"]); md.Spec = psb.Platform; //Important Bitmap bmp = md.ToImage(); foreach (var iconPair in icon) { var savePath = Path.Combine(path, name, iconPair.Key); var info = (PsbDictionary)iconPair.Value; var width = (int)(PsbNumber)info["width"]; var height = (int)(PsbNumber)info["height"]; var top = (int)(PsbNumber)info["top"]; var left = (int)(PsbNumber)info["left"]; var attr = (int)(PsbNumber)info["attr"]; Bitmap b = new Bitmap(width, height, PixelFormat.Format32bppArgb); #if USE_FASTBITMAP using (FastBitmap f = b.FastLock()) { f.CopyRegion(bmp, new Rectangle(left, top, width, height), new Rectangle(0, 0, b.Width, b.Height)); } #else Graphics g = Graphics.FromImage(b); //g.InterpolationMode = InterpolationMode.NearestNeighbor; //g.PixelOffsetMode = PixelOffsetMode.Half; g.DrawImage(bmp, new Rectangle(0, 0, b.Width, b.Height), new Rectangle(left, top, width, height), GraphicsUnit.Pixel); g.Dispose(); #endif switch (option) { case PsbImageOption.Decompress: File.WriteAllBytes(savePath + ".raw", RL.GetPixelBytesFromImage(b, pixelFormat)); break; case PsbImageOption.Compress: File.WriteAllBytes(savePath + ".rl", RL.CompressImage(b, pixelFormat)); break; case PsbImageOption.Original: case PsbImageOption.Extract: default: switch (imageFormat) { case PsbImageFormat.Bmp: b.Save(savePath + ".bmp", ImageFormat.Bmp); break; case PsbImageFormat.Png: default: b.Save(savePath + ".png", ImageFormat.Png); //b.Save(savePath + $"_{attr}.png", ImageFormat.Png); break; } break; } } bmp.Dispose(); } }
public static void DecompressToImageFile(byte[] data, string path, int height, int width, PsbImageFormat format = PsbImageFormat.png, PsbPixelFormat colorFormat = PsbPixelFormat.None, int align = 4) { byte[] bytes; try { bytes = Decompress(data, height, width, align); } catch (Exception e) { throw new PsbBadFormatException(PsbBadFormatReason.Resources, "data incorrect", e); } ConvertToImageFile(bytes, path, height, width, format, colorFormat); }
public static byte[] GetPixelBytesFromImageFile(string path, PsbPixelFormat pixelFormat = PsbPixelFormat.None) { Bitmap bmp = new Bitmap(path, false); return(PixelBytesFromImage(bmp, pixelFormat)); }
public static byte[] CompressImageFile(string path, PsbPixelFormat pixelFormat = PsbPixelFormat.None) { return(CompressImage(new Bitmap(path, false), pixelFormat)); }
public static byte[] CompressImage(Bitmap image, PsbPixelFormat pixelFormat = PsbPixelFormat.None) { return(Compress(PixelBytesFromImage(image, pixelFormat))); }
public static Bitmap ConvertToImage(byte[] data, int height, int width, PsbPixelFormat colorFormat = PsbPixelFormat.None) { var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); var bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bmp.PixelFormat); switch (colorFormat) { case PsbPixelFormat.BeRGBA4444: data = Argb428(data); Argb2Rgba(ref data); break; case PsbPixelFormat.LeRGBA4444: data = Argb428(data); break; case PsbPixelFormat.BeRGBA8: Switch_0_2(ref data); break; case PsbPixelFormat.A8L8: data = ReadA8L8(data, width, height); break; case PsbPixelFormat.A8L8_SW: data = ReadA8L8(data, width, height); data = PostProcessing.UnswizzleTexture(data, width, height, PixelFormat.Format32bppArgb); break; case PsbPixelFormat.DXT5: data = DxtUtil.DecompressDxt5(data, width, height); Switch_0_2(ref data); //DXT5(for win) need conversion break; case PsbPixelFormat.RGBA8_SW: data = PostProcessing.UnswizzleTexture(data, bmp.Width, bmp.Height, bmp.PixelFormat); Switch_0_2(ref data); break; case PsbPixelFormat.LeRGBA4444_SW: data = Argb428(data); //Rgba2Argb(ref data); data = PostProcessing.UnswizzleTexture(data, bmp.Width, bmp.Height, bmp.PixelFormat); break; case PsbPixelFormat.TileRGBA8_SW: data = PostProcessing.UntileTexture(data, bmp.Width, bmp.Height, bmp.PixelFormat); break; case PsbPixelFormat.A8: data = ReadA8(data, height, width); break; case PsbPixelFormat.A8_SW: data = ReadA8(data, height, width); data = PostProcessing.UnswizzleTexture(data, width, height, PixelFormat.Format32bppArgb); break; case PsbPixelFormat.TileA8_SW: data = ReadA8(data, height, width); data = PostProcessing.UntileTexture(data, width, height, PixelFormat.Format32bppArgb); break; case PsbPixelFormat.L8: data = ReadL8(data, height, width); break; case PsbPixelFormat.L8_SW: data = ReadL8(data, height, width); data = PostProcessing.UnswizzleTexture(data, width, height, PixelFormat.Format32bppArgb); break; case PsbPixelFormat.RGBA5650: data = ReadRgba5650(data); break; case PsbPixelFormat.RGBA5650_SW: data = ReadRgba5650(data); data = PostProcessing.UnswizzleTexture(data, width, height, PixelFormat.Format32bppArgb); break; } int stride = bmpData.Stride; // 扫描线的宽度 int offset = stride - width; // 显示宽度与扫描线宽度的间隙 IntPtr iptr = bmpData.Scan0; // 获取bmpData的内存起始位置 int scanBytes = stride * height; // 用stride宽度,表示这是内存区域的大小 if (scanBytes >= data.Length) { Marshal.Copy(data, 0, iptr, data.Length); bmp.UnlockBits(bmpData); // 解锁内存区域 return(bmp); } throw new BadImageFormatException("data may not corresponding"); }
/// <summary> /// Try to switch Spec /// </summary> /// <param name="psb"></param> /// <param name="targetSpec"></param> /// <param name="pixelFormat"></param> public static void SwitchSpec(this PSB psb, PsbSpec targetSpec, PsbPixelFormat pixelFormat = PsbPixelFormat.None) { if (targetSpec == PsbSpec.other) { return; } //Alternative //TODO: Alternative table? bool isAlternative = false; var realTargetSpec = PsbSpec.common; var original = psb.Platform; if (original == PsbSpec.ems) { original = PsbSpec.common; } if (targetSpec == PsbSpec.ems) { isAlternative = true; realTargetSpec = targetSpec; targetSpec = PsbSpec.common; } if (targetSpec == PsbSpec.krkr) //krkr can not select pixel format { switch (original) { case PsbSpec.win: { Common2KrkrConverter winKrkr = new Common2KrkrConverter(); winKrkr.Convert(psb); break; } case PsbSpec.common: { Common2KrkrConverter commonKrkr = new Common2KrkrConverter(); commonKrkr.Convert(psb); break; } default: psb.Platform = targetSpec; break; } } else if (targetSpec == PsbSpec.win) { switch (original) { case PsbSpec.krkr: Krkr2CommonConverter krkr2Win = new Krkr2CommonConverter(true); krkr2Win.Convert(psb); break; case PsbSpec.common: CommonWinConverter winCommon = new CommonWinConverter(); winCommon.Convert(psb); break; default: psb.Platform = targetSpec; break; } } else if (targetSpec == PsbSpec.common || targetSpec == PsbSpec.ems) { switch (original) { case PsbSpec.krkr: Krkr2CommonConverter krkr2Common = new Krkr2CommonConverter(); krkr2Common.Convert(psb); break; case PsbSpec.win: CommonWinConverter commonWin = new CommonWinConverter(); commonWin.Convert(psb); break; case PsbSpec.common: case PsbSpec.ems: psb.Platform = targetSpec; break; default: psb.Platform = targetSpec; break; } } else { psb.Platform = targetSpec; } if (isAlternative) { psb.Platform = realTargetSpec; } }
private static byte[] PixelBytesFromImage(Bitmap bmp, PsbPixelFormat pixelFormat = PsbPixelFormat.None) { BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat); int stride = bmpData.Stride; // 扫描线的宽度 int offset = stride - bmp.Width; // 显示宽度与扫描线宽度的间隙 IntPtr iPtr = bmpData.Scan0; // 获取bmpData的内存起始位置 int scanBytes = stride * bmp.Height; // 用stride宽度,表示这是内存区域的大小 var result = new byte[scanBytes]; Marshal.Copy(iPtr, result, 0, scanBytes); bmp.UnlockBits(bmpData); // 解锁内存区域 switch (pixelFormat) { case PsbPixelFormat.LeRGBA4444: result = Argb428(result, false); break; case PsbPixelFormat.BeRGBA4444: Argb2Rgba(ref result, true); result = Argb428(result, false); break; case PsbPixelFormat.BeRGBA8: Switch_0_2(ref result); break; case PsbPixelFormat.A8L8: result = Argb2A8L8(result); break; case PsbPixelFormat.A8L8_SW: result = PostProcessing.SwizzleTexture(result, bmp.Width, bmp.Height, bmp.PixelFormat); result = Argb2A8L8(result); break; case PsbPixelFormat.DXT5: //Switch_0_2(ref result); result = DxtUtil.Dxt5Encode(result, bmp.Width, bmp.Height); break; case PsbPixelFormat.RGBA8_SW: result = PostProcessing.SwizzleTexture(result, bmp.Width, bmp.Height, bmp.PixelFormat); Switch_0_2(ref result); break; case PsbPixelFormat.TileRGBA8_SW: result = PostProcessing.TileTexture(result, bmp.Width, bmp.Height, bmp.PixelFormat); break; case PsbPixelFormat.L8: result = Argb2L8(result); break; case PsbPixelFormat.A8_SW: result = PostProcessing.SwizzleTexture(result, bmp.Width, bmp.Height, bmp.PixelFormat); result = Argb2A8(result); break; case PsbPixelFormat.TileA8_SW: result = PostProcessing.TileTexture(result, bmp.Width, bmp.Height, bmp.PixelFormat); result = Argb2A8(result); break; case PsbPixelFormat.A8: result = Argb2A8(result); break; case PsbPixelFormat.CI8_SW: result = PostProcessing.SwizzleTexture(result, bmp.Width, bmp.Height, bmp.PixelFormat); break; case PsbPixelFormat.CI4_SW: result = PostProcessing.SwizzleTexture(result, bmp.Width, bmp.Height, bmp.PixelFormat); break; case PsbPixelFormat.L8_SW: result = PostProcessing.SwizzleTexture(result, bmp.Width, bmp.Height, bmp.PixelFormat); result = Argb2L8(result); break; case PsbPixelFormat.LeRGBA4444_SW: result = PostProcessing.SwizzleTexture(result, bmp.Width, bmp.Height, bmp.PixelFormat); result = Argb428(result, false); break; case PsbPixelFormat.RGBA5650: result = Argb2Rgba5650(result); break; case PsbPixelFormat.RGBA5650_SW: result = PostProcessing.SwizzleTexture(result, bmp.Width, bmp.Height, bmp.PixelFormat); result = Argb2Rgba5650(result); break; } return(result); }