internal static ImageSource DecompressTextureToImageSource(byte[] imageData, int width, int height, bool ignoreAlpha, IPixelEffect effect, uint fourCC, ImageTextureUtil.DXGI_FORMAT dxgiFormat) { using (var imageStream = new MemoryStream(imageData)) { byte[] pixelColors; if (fourCC == (uint)ImageTextureUtil.DDS_FOURCC.DXT1) { pixelColors = DxtUtil.DecompressDxt1(imageStream, width, height); } else if (fourCC == (uint)ImageTextureUtil.DDS_FOURCC.DXT3) { pixelColors = DxtUtil.DecompressDxt3(imageStream, width, height); } else { pixelColors = DxtUtil.DecompressDxt5(imageStream, width, height, dxgiFormat); } // Copy the pixel colors into a byte array const int bytesPerPixel = 4; var stride = width * bytesPerPixel; var pixelRgba = new byte[pixelColors.Length]; for (var i = 0; i < pixelColors.Length; i += bytesPerPixel) { pixelRgba[i + 0] = pixelColors[i + 2]; pixelRgba[i + 1] = pixelColors[i + 1]; pixelRgba[i + 2] = pixelColors[i + 0]; pixelRgba[i + 3] = ignoreAlpha ? (byte)0xff : pixelColors[i + 3]; } if (effect == null) { return(System.Windows.Media.Imaging.BitmapSource.Create(width, height, 96, 96, PixelFormats.Bgra32, null, pixelRgba, stride)); } var bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); var bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, bmp.PixelFormat); //Copy the data from the byte array into BitmapData.Scan0 Marshal.Copy(pixelRgba, 0, bmpData.Scan0, pixelRgba.Length); // Unlock the pixels bmp.UnlockBits(bmpData); bmp = effect.Quantize(bmp); return(ImageHelper.ConvertBitmapToBitmapImage(bmp)); } }
internal static Bitmap DecompressTextureToBitmap(byte[] imageData, int width, int height, bool ignoreAlpha, uint fourCC, ImageTextureUtil.DXGI_FORMAT dxgiFormat) { using (var imageStream = new MemoryStream(imageData)) { byte[] pixelColors; if (fourCC == (uint)ImageTextureUtil.DDS_FOURCC.DXT1) { pixelColors = DxtUtil.DecompressDxt1(imageStream, width, height); } else if (fourCC == (uint)ImageTextureUtil.DDS_FOURCC.DXT3) { pixelColors = DxtUtil.DecompressDxt3(imageStream, width, height); } else { pixelColors = DxtUtil.DecompressDxt5(imageStream, width, height, dxgiFormat); } // Copy the pixel colors into a byte array const int bytesPerPixel = 4; var pixelRgba = new byte[pixelColors.Length]; for (var i = 0; i < pixelColors.Length; i += bytesPerPixel) { pixelRgba[i + 0] = pixelColors[i + 2]; pixelRgba[i + 1] = pixelColors[i + 1]; pixelRgba[i + 2] = pixelColors[i + 0]; pixelRgba[i + 3] = ignoreAlpha ? (byte)0xff : pixelColors[i + 3]; } // Here create the Bitmap to the know height, width and format var bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); // Create a BitmapData and Lock all pixels to be written var bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, bmp.PixelFormat); //Copy the data from the byte array into BitmapData.Scan0 Marshal.Copy(pixelRgba, 0, bmpData.Scan0, pixelRgba.Length); // Unlock the pixels bmp.UnlockBits(bmpData); return(bmp); } }
private static void DecompressDxt5Block(BinaryReader imageReader, int x, int y, int blockCountX, int width, int height, byte[] imageData, ImageTextureUtil.DXGI_FORMAT dxgiFormat) { byte alpha0 = imageReader.ReadByte(); byte alpha1 = imageReader.ReadByte(); ulong alphaMask = (ulong)imageReader.ReadByte(); alphaMask += (ulong)imageReader.ReadByte() << 8; alphaMask += (ulong)imageReader.ReadByte() << 16; alphaMask += (ulong)imageReader.ReadByte() << 24; alphaMask += (ulong)imageReader.ReadByte() << 32; alphaMask += (ulong)imageReader.ReadByte() << 40; ushort c0 = imageReader.ReadUInt16(); ushort c1 = imageReader.ReadUInt16(); byte r0, g0, b0; byte r1, g1, b1; switch (dxgiFormat) { case ImageTextureUtil.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM_SRGB: break; case ImageTextureUtil.DXGI_FORMAT.DXGI_FORMAT_UNKNOWN: break; default: break; } ConvertRgb565ToRgb888(c0, out r0, out g0, out b0); ConvertRgb565ToRgb888(c1, out r1, out g1, out b1); uint lookupTable = imageReader.ReadUInt32(); for (int blockY = 0; blockY < 4; blockY++) { for (int blockX = 0; blockX < 4; blockX++) { byte r = 0, g = 0, b = 0, a = 255; uint index = (lookupTable >> 2 * (4 * blockY + blockX)) & 0x03; uint alphaIndex = (uint)((alphaMask >> 3 * (4 * blockY + blockX)) & 0x07); if (alphaIndex == 0) { a = alpha0; } else if (alphaIndex == 1) { a = alpha1; } else if (alpha0 > alpha1) { a = (byte)(((8 - alphaIndex) * alpha0 + (alphaIndex - 1) * alpha1) / 7); } else if (alphaIndex == 6) { a = 0; } else if (alphaIndex == 7) { a = 0xff; } else { a = (byte)(((6 - alphaIndex) * alpha0 + (alphaIndex - 1) * alpha1) / 5); } switch (index) { case 0: r = r0; g = g0; b = b0; break; case 1: r = r1; g = g1; b = b1; break; case 2: r = (byte)((2 * r0 + r1) / 3); g = (byte)((2 * g0 + g1) / 3); b = (byte)((2 * b0 + b1) / 3); break; case 3: r = (byte)((r0 + 2 * r1) / 3); g = (byte)((g0 + 2 * g1) / 3); b = (byte)((b0 + 2 * b1) / 3); break; } int px = (x << 2) + blockX; int py = (y << 2) + blockY; if ((px < width) && (py < height)) { int offset = ((py * width) + px) << 2; imageData[offset] = r; imageData[offset + 1] = g; imageData[offset + 2] = b; imageData[offset + 3] = a; } } } }
internal static byte[] DecompressDxt5(Stream imageStream, int width, int height, ImageTextureUtil.DXGI_FORMAT dxgiFormat) { byte[] imageData = new byte[width * height * 4]; using (BinaryReader imageReader = new BinaryReader(imageStream)) { if (dxgiFormat == ImageTextureUtil.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM_SRGB) { int blockSize = 8; // For block-compressed formats, compute the pitch as: int dwPitchOrLinearSize = Math.Max(1, ((width + 3) / 4)) * blockSize; } int blockCountX = (width + 3) / 4; int blockCountY = (height + 3) / 4; for (int y = 0; y < blockCountY; y++) { for (int x = 0; x < blockCountX; x++) { DecompressDxt5Block(imageReader, x, y, blockCountX, width, height, imageData, dxgiFormat); } } } return(imageData); }
internal static byte[] DecompressDxt5(byte[] imageData, int width, int height, ImageTextureUtil.DXGI_FORMAT dxgiFormat) { using (MemoryStream imageStream = new MemoryStream(imageData)) { return(DecompressDxt5(imageStream, width, height, dxgiFormat)); } }
private static void DecompressDxt5Block(BinaryReader imageReader, int x, int y, int blockCountX, int width, int height, byte[] imageData, ImageTextureUtil.DXGI_FORMAT dxgiFormat) { byte alpha0 = imageReader.ReadByte(); byte alpha1 = imageReader.ReadByte(); ulong alphaMask = (ulong)imageReader.ReadByte(); alphaMask += (ulong)imageReader.ReadByte() << 8; alphaMask += (ulong)imageReader.ReadByte() << 16; alphaMask += (ulong)imageReader.ReadByte() << 24; alphaMask += (ulong)imageReader.ReadByte() << 32; alphaMask += (ulong)imageReader.ReadByte() << 40; ushort c0 = imageReader.ReadUInt16(); ushort c1 = imageReader.ReadUInt16(); byte r0, g0, b0; byte r1, g1, b1; switch (dxgiFormat) { case ImageTextureUtil.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM_SRGB: // there is suport to be some sort of SRGB conversion somwhere here, but I'm not sure where precicly and on what values. //ConvertSrgbToRgb888(c0, out r0, out g0, out b0); //ConvertSrgbToRgb888(c1, out r1, out g1, out b1); var aa = (byte)(255 * D3DX_SRGB_to_FLOAT_inexact(((float)(c0 & 0x000000ff)) / 255)); r0 = (byte)(255 * D3DX_SRGB_to_FLOAT_inexact(((float)(((c0 >> 8) & 0x000000ff))) / 255)); g0 = (byte)(255 * D3DX_SRGB_to_FLOAT_inexact(((float)(c1 & 0x000000ff)) / 255)); b0 = (byte)(255 * D3DX_SRGB_to_FLOAT_inexact(((float)(((c1 >> 8) & 0x000000ff))) / 255)); r1 = r0; g1 = g0; b1 = b0; break; case ImageTextureUtil.DXGI_FORMAT.DXGI_FORMAT_UNKNOWN: default: ConvertRgb565ToRgb888(c0, out r0, out g0, out b0); ConvertRgb565ToRgb888(c1, out r1, out g1, out b1); break; } uint lookupTable = imageReader.ReadUInt32(); for (int blockY = 0; blockY < 4; blockY++) { for (int blockX = 0; blockX < 4; blockX++) { byte r = 0, g = 0, b = 0, a = 255; uint index = (lookupTable >> 2 * (4 * blockY + blockX)) & 0x03; uint alphaIndex = (uint)((alphaMask >> 3 * (4 * blockY + blockX)) & 0x07); if (alphaIndex == 0) { a = alpha0; } else if (alphaIndex == 1) { a = alpha1; } else if (alpha0 > alpha1) { a = (byte)(((8 - alphaIndex) * alpha0 + (alphaIndex - 1) * alpha1) / 7); } else if (alphaIndex == 6) { a = 0; } else if (alphaIndex == 7) { a = 0xff; } else { a = (byte)(((6 - alphaIndex) * alpha0 + (alphaIndex - 1) * alpha1) / 5); } switch (index) { case 0: r = r0; g = g0; b = b0; break; case 1: r = r1; g = g1; b = b1; break; case 2: r = (byte)((2 * r0 + r1) / 3); g = (byte)((2 * g0 + g1) / 3); b = (byte)((2 * b0 + b1) / 3); break; case 3: r = (byte)((r0 + 2 * r1) / 3); g = (byte)((g0 + 2 * g1) / 3); b = (byte)((b0 + 2 * b1) / 3); break; } int px = (x << 2) + blockX; int py = (y << 2) + blockY; if ((px < width) && (py < height)) { int offset = ((py * width) + px) << 2; imageData[offset] = r; imageData[offset + 1] = g; imageData[offset + 2] = b; imageData[offset + 3] = a; } } } }