public void WriteTo(Stream stream) { using (SubStream tmpstream = new SubStream(new MemoryStream())) { WriteTo(tmpstream); tmpstream.Seek(0, SeekOrigin.Begin); tmpstream.CopyTo(stream); } }
protected List<int> ProcessInt32List(SubStream data) { List<int> vals = new List<int>(); int nents = data.ReadInt32(); for (int i = 0; i < nents; i++) { vals.Add(data.ReadInt32()); } return vals; }
protected Dictionary<string, dynamic> ProcessKeyValuePairs(SubStream data, List<string> path) { Dictionary<string, object> ret = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase); while (true) { string key = data.ReadString(); if (key == "") { return ret; } List<string> _path = path.ToList(); _path.Add(key); dynamic val = ProcessValue(data, _path); ret[key] = val; } }
protected void WriteInt32List(SubStream outstream, List<int> data) { outstream.WriteInt32(data.Count); foreach (int val in data) { outstream.WriteInt32(val); } }
protected dynamic ProcessValue(SubStream data, List<string> path) { int type = data.ReadByte(); switch ((char)type) { case 'T': return ProcessKeyValuePairs(data, path); case 'I': return ProcessInt32List(data); case 'i': return data.ReadInt32(); case 'F': return ProcessSingleList(data); case 'f': return data.ReadSingle(); case 'S': return ProcessStringList(data); case 's': return data.ReadString(); case 'M': return ProcessList(data, path); case '.': return null; case 'R': return ProcessRawBinary(data); default: throw new NotImplementedException(String.Format("Unknown type {0} ({0:X8}) at position {1}", (char)type, data.Position)); } }
public RS5Environment(SubStream data) { data.Position = 0; Data = ProcessValue(data, new List<string>()); }
public void WriteTo(SubStream stream) { WriteValue(stream, this.Data); }
protected static Bitmap GetBitmapFromDDS_DXT1(SubStream data, int offset, int width, int height, out bool hasalpha) { Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); byte[] bmpraw = new byte[width * height * 4]; hasalpha = false; for (int y = 0; y < height; y += 4) { for (int x = 0; x < width; x += 4) { Color[,] colourdata = GetDXT1ColourBlock(data, offset, false); for (int v = 0; v < 4; v++) { for (int u = 0; u < 4; u++) { if (x + u < width && y + v < height) { int i = ((y + v) * width + (x + u)) * 4; bmpraw[i] = colourdata[u, v].B; bmpraw[i + 1] = colourdata[u, v].G; bmpraw[i + 2] = colourdata[u, v].R; bmpraw[i + 3] = colourdata[u, v].A; hasalpha |= colourdata[u, v].A != 255; } } } offset += 8; } } BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); for (int y = 0; y < height; y++) { Marshal.Copy(bmpraw, y * width * 4, bmpdata.Scan0 + y * bmpdata.Stride, width * 4); } bmp.UnlockBits(bmpdata); return bmp; }
protected void WriteRawBinary(SubStream outstream, byte[] data) { outstream.WriteInt32(data.Length); outstream.WriteBytes(data.Length, data); }
protected void WriteStringList(SubStream outstream, List<string> data) { outstream.WriteInt32(data.Count); foreach (string val in data) { outstream.WriteString(val); } }
protected RS5Chunk(SubStream data, long offset) : this(GetChunkData(data, offset)) { }
private static SubStream GetChunkData(SubStream data, long offset) { int totalsize = (((12 + (int)data.GetByte(offset + 6) + 7) & -8) + data.GetInt32(offset + 8) + 7) & -8; return(new SubStream(data, offset, totalsize)); }
public DDSImage(SubStream data) { if (data.GetByte(0) == 'D' && data.GetByte(1) == 'D' && data.GetByte(2) == 'S' && data.GetByte(3) == ' ') { Height = data.GetInt32(12); Width = data.GetInt32(16); Depth = data.GetInt32(24); Flags = data.GetUInt32(8); Pitch = data.GetInt32(20); FourCC = Encoding.ASCII.GetString(data.GetBytes(84, 4)); RGBBitCount = data.GetInt32(88); RedMask = data.GetUInt32(92); GreenMask = data.GetUInt32(96); BlueMask = data.GetUInt32(100); AlphaMask = data.GetUInt32(104); Data = data; ImageOffset = 128; if (Depth == 0) { Depth = 1; } if ((Flags & 8) == 0) { Pitch = Width * RGBBitCount / 8; } IsARGB32 = (FourCC == "DXT1" || FourCC == "DXT2" || FourCC == "DXT3" || FourCC == "DXT4" || FourCC == "DXT5" || FourCC == "\0\0\0\0"); IntensityFactor = 1.0; try { FailureReason = null; switch (FourCC) { case "DXT1": Bitmap = GetBitmapFromDDS_DXT1(Data, ImageOffset, Width, Height, out HasAlpha); break; case "DXT2": Bitmap = GetBitmapFromDDS_DXT3(Data, ImageOffset, Width, Height, true, out HasAlpha); break; case "DXT3": Bitmap = GetBitmapFromDDS_DXT3(Data, ImageOffset, Width, Height, false, out HasAlpha); break; case "DXT4": Bitmap = GetBitmapFromDDS_DXT5(Data, ImageOffset, Width, Height, true, out HasAlpha); break; case "DXT5": Bitmap = GetBitmapFromDDS_DXT5(Data, ImageOffset, Width, Height, false, out HasAlpha); break; case "\0\0\0\0": Bitmap = GetBitmapFromDDS_RAW(Data, ImageOffset, Width, Height, Pitch, RGBBitCount, RedMask, GreenMask, BlueMask, AlphaMask, out HasAlpha, out IsARGB32); break; case "q\0\0\0": Bitmap = GetBitmapFromDDS_ARGB16F(Data, ImageOffset, Width, Height, out HasAlpha, out IntensityFactor); break; default: Bitmap = null; FailureReason = String.Format("Unknown DDS FourCC {0:X2}:{1:X2}:{2:X2}:{3:X2}", Data.GetByte(84), Data.GetByte(85), Data.GetByte(86), Data.GetByte(87)); break; } } catch (Exception ex) { Bitmap = null; FailureReason = ex.Message; } } else { throw new NotImplementedException(String.Format("Unknown file format {0:X2}:{1:X2}:{2:X2}:{3:X2}", data.GetByte(0), data.GetByte(1), data.GetByte(2), data.GetByte(3))); } }
protected static Color[,] GetDXT1ColourBlock(SubStream data, int offset, bool IsDXT3) { ushort c0v = data.GetUInt16(offset); ushort c1v = data.GetUInt16(offset + 2); Color[] c = new Color[4]; c[0] = Color.FromArgb(0xFF, (c0v >> 8) & 0xF8, (c0v >> 3) & 0xFC, (c0v << 3) & 0xF8); c[1] = Color.FromArgb(0xFF, (c1v >> 8) & 0xF8, (c1v >> 3) & 0xFC, (c1v << 3) & 0xF8); if (c0v > c1v || IsDXT3) { c[2] = Color.FromArgb(0xFF, ((int)c[0].R * 2 + c[1].R + 1) / 3, ((int)c[0].G * 2 + c[1].G + 1) / 3, ((int)c[0].B * 2 + c[1].B + 1) / 3); c[3] = Color.FromArgb(0xFF, ((int)c[1].R * 2 + c[0].R + 1) / 3, ((int)c[1].G * 2 + c[0].G + 1) / 3, ((int)c[1].B * 2 + c[0].B + 1) / 3); } else { c[2] = Color.FromArgb(0xFF, ((int)c[0].R + c[1].R) / 2, ((int)c[0].G + c[1].G) / 2, ((int)c[0].B + c[1].B) / 2); c[3] = Color.FromArgb(0, 0, 0, 0); } ulong lookup = data.GetUInt32(offset + 4); Color[,] output = new Color[4, 4]; for (int i = 0; i < 16; i++) { output[i % 4, i / 4] = c[(lookup >> (i * 2)) & 3]; } return output; }
protected static Bitmap GetBitmapFromDDS_RAW(SubStream Data, int Offset, int Width, int Height, int Pitch, int RGBBitCount, uint RedMask, uint GreenMask, uint BlueMask, uint AlphaMask, out bool hasalpha, out bool isargb32) { uint RGBBitMask = (uint)((1L << RGBBitCount) - 1); int RedShift = MostSignificantBitPosition(RedMask) - 7; int GreenShift = MostSignificantBitPosition(GreenMask) - 7; int BlueShift = MostSignificantBitPosition(BlueMask) - 7; int AlphaShift = MostSignificantBitPosition(AlphaMask) - 7; int RedBits = RedMask == 0 ? 0 : MostSignificantBitPosition(RedMask) - LeastSignificantBitPosition(RedMask) + 1; int GreenBits = GreenMask == 0 ? 0 : MostSignificantBitPosition(GreenMask) - LeastSignificantBitPosition(GreenMask) + 1; int BlueBits = BlueMask == 0 ? 0 : MostSignificantBitPosition(BlueMask) - LeastSignificantBitPosition(BlueMask) + 1; int AlphaBits = AlphaMask == 0 ? 0 : MostSignificantBitPosition(AlphaMask) - LeastSignificantBitPosition(AlphaMask) + 1; hasalpha = false; isargb32 = RedBits <= 8 && GreenBits <= 8 && BlueBits <= 8 && AlphaBits <= 8; Bitmap bmp = new Bitmap(Width, Height, PixelFormat.Format32bppArgb); byte[] bmpraw = new byte[Width * Height * 4]; for (int y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { int w = (4 - ((RGBBitCount + 7) / 8)); int bitpos = y * Pitch * 8 + x * RGBBitCount; int i = ((bitpos + RGBBitCount - 1) / 8 - 7); int b = (bitpos - i * 8); int o = (y * Width + x) * 4; uint v = (uint)((Data.GetUInt64(i + 128) >> b) & RGBBitMask); bmpraw[o + 0] = GetMaskShiftVal(v, BlueMask, BlueShift, 0x00); bmpraw[o + 1] = GetMaskShiftVal(v, GreenMask, GreenShift, 0x00); bmpraw[o + 2] = GetMaskShiftVal(v, RedMask, RedShift, 0x00); bmpraw[o + 3] = GetMaskShiftVal(v, AlphaMask, AlphaShift, 0xFF); hasalpha = bmpraw[o + 3] != 255; } } BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); for (int y = 0; y < Height; y++) { Marshal.Copy(bmpraw, y * Width * 4, bmpdata.Scan0 + y * bmpdata.Stride, Width * 4); } bmp.UnlockBits(bmpdata); return bmp; }
protected static Bitmap GetBitmapFromDDS_DXT5(SubStream data, int offset, int width, int height, bool IsDXT4, out bool hasalpha) { Bitmap bmp = new Bitmap(width, height, IsDXT4 ? PixelFormat.Format32bppPArgb : PixelFormat.Format32bppArgb); byte[] bmpraw = new byte[width * height * 4]; hasalpha = false; for (int y = 0; y < height; y += 4) { for (int x = 0; x < width; x += 4) { byte[] a = new byte[8]; a[0] = data.GetByte(offset); a[1] = data.GetByte(offset + 1); if (a[0] > a[1]) { a[2] = (byte)(((int)a[0] * 6 + a[1] * 1 + 3) / 7); a[3] = (byte)(((int)a[0] * 5 + a[1] * 2 + 3) / 7); a[4] = (byte)(((int)a[0] * 4 + a[1] * 3 + 3) / 7); a[5] = (byte)(((int)a[0] * 3 + a[1] * 4 + 3) / 7); a[6] = (byte)(((int)a[0] * 2 + a[1] * 5 + 3) / 7); a[7] = (byte)(((int)a[0] * 1 + a[1] * 6 + 3) / 7); } else { a[2] = (byte)(((int)a[0] * 4 + a[1] * 1 + 2) / 5); a[3] = (byte)(((int)a[0] * 3 + a[1] * 2 + 2) / 5); a[4] = (byte)(((int)a[0] * 2 + a[1] * 3 + 2) / 5); a[5] = (byte)(((int)a[0] * 1 + a[1] * 4 + 2) / 5); a[6] = 0x00; a[7] = 0xFF; } ulong alphasel = data.GetUInt64(offset) >> 16; byte[,] alphadata = new byte[4, 4]; for (int i = 0; i < 16; i++) { alphadata[i % 4, i / 4] = a[(alphasel >> (i * 3)) & 7]; } Color[,] colourdata = GetDXT1ColourBlock(data, offset + 8, true); for (int v = 0; v < 4; v++) { for (int u = 0; u < 4; u++) { if (x + u < width && y + v < height) { int i = ((y + v) * width + (x + u)) * 4; bmpraw[i] = colourdata[u, v].B; bmpraw[i + 1] = colourdata[u, v].G; bmpraw[i + 2] = colourdata[u, v].R; bmpraw[i + 3] = alphadata[u, v]; hasalpha |= alphadata[u, v] != 255; } } } offset += 16; } } BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, IsDXT4 ? PixelFormat.Format32bppPArgb : PixelFormat.Format32bppArgb); for (int y = 0; y < height; y++) { Marshal.Copy(bmpraw, y * width * 4, bmpdata.Scan0 + y * bmpdata.Stride, width * 4); } bmp.UnlockBits(bmpdata); return bmp; }
protected static Bitmap GetBitmapFromDDS_DXT3(SubStream data, int offset, int width, int height, bool IsDXT2, out bool hasalpha) { Bitmap bmp = new Bitmap(width, height, IsDXT2 ? PixelFormat.Format32bppPArgb : PixelFormat.Format32bppArgb); byte[] bmpraw = new byte[width * height * 4]; hasalpha = false; for (int y = 0; y < height; y += 4) { for (int x = 0; x < width; x += 4) { ulong alpharaw = data.GetUInt64(offset); byte[,] alphadata = new byte[4, 4]; for (int i = 0; i < 16; i++) { alphadata[i % 4, i / 4] = (byte)(((alpharaw >> (i * 4)) & 0x0F) * 0x11); } Color[,] colourdata = GetDXT1ColourBlock(data, offset + 8, true); for (int v = 0; v < 4; v++) { for (int u = 0; u < 4; u++) { if (x + u < width && y + v < height) { int i = ((y + v) * width + (x + u)) * 4; bmpraw[i] = colourdata[u, v].B; bmpraw[i + 1] = colourdata[u, v].G; bmpraw[i + 2] = colourdata[u, v].R; bmpraw[i + 3] = alphadata[u, v]; hasalpha |= alphadata[u, v] != 255; } } } offset += 16; } } BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, IsDXT2 ? PixelFormat.Format32bppPArgb : PixelFormat.Format32bppArgb); for (int y = 0; y < height; y++) { Marshal.Copy(bmpraw, y * width * 4, bmpdata.Scan0 + y * bmpdata.Stride, width * 4); } bmp.UnlockBits(bmpdata); return bmp; }
protected void WriteKeyValuePairs(SubStream outstream, IDictionary data) { foreach (DictionaryEntry de in data) { outstream.WriteString(de.Key.ToString()); WriteValue(outstream, de.Value); } outstream.WriteByte(0); }
protected RS5Chunk(SubStream chunkdata) { this.ChunkData = chunkdata; this._Data = new Lazy <SubStream>(() => GetData()); this._Chunks = new Lazy <Dictionary <string, RS5Chunk> >(() => GetChunks()); }
protected void WriteList(SubStream outstream, IList data) { outstream.WriteInt32(data.Count); foreach (object val in data) { WriteValue(outstream, val); } }
protected static Bitmap GetBitmapFromDDS_ARGB16F(SubStream data, int offset, int width, int height, out bool hasalpha, out double intensity) { float[] fdata = new float[width * height * 4]; double maxval = Double.NegativeInfinity; double minval = Double.PositiveInfinity; double maxalpha = Double.NegativeInfinity; double minalpha = Double.PositiveInfinity; double alphaoffset = 0.0; hasalpha = false; for (int i = 0; i < width * height * 4; i += 4) { for (int j = 0; j < 4; j++) { fdata[i + j] = HalfToFloat(data.GetUInt16(offset + (i + j) * 2)); } for (int j = 0; j < 3; j++) { if (fdata[i + j] > maxval) { maxval = fdata[i + j]; } if (fdata[i + j] < minval) { minval = fdata[i + j]; } } if (fdata[i + 3] > maxalpha) { maxalpha = fdata[i + 3]; } if (fdata[i + 3] < minalpha) { minalpha = fdata[i + 3]; } } if (minval < 0 || minalpha < 0) { throw new NotImplementedException("ARGB16F with negative values not supported"); } if (maxval == 0) { maxval = 1.0; } if (maxalpha == 0) { maxalpha = 1.0; //alphaoffset = 1.0; } intensity = maxval; Bitmap bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); byte[] bmpraw = new byte[width * height * 4]; for (int i = 0; i < width * height * 4; i += 4) { bmpraw[i + 0] = (byte)(fdata[i + 2] * 255 / maxval); bmpraw[i + 1] = (byte)(fdata[i + 1] * 255 / maxval); bmpraw[i + 2] = (byte)(fdata[i + 0] * 255 / maxval); bmpraw[i + 3] = (byte)((fdata[i + 3] + alphaoffset) * 255 / maxalpha); hasalpha |= bmpraw[i + 3] != 255; } BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); for (int y = 0; y < height; y++) { Marshal.Copy(bmpraw, y * width * 4, bmpdata.Scan0 + y * bmpdata.Stride, width * 4); } bmp.UnlockBits(bmpdata); return(bmp); }
protected void WriteSingleList(SubStream outstream, List<float> data) { outstream.WriteInt32(data.Count); foreach (float val in data) { outstream.WriteSingle(val); } }
protected List<dynamic> ProcessList(SubStream data, List<string> path) { List<object> vals = new List<object>(); int nents = data.ReadInt32(); for (int i = 0; i < nents; i++) { List<string> _path = path.ToList(); _path.Add(""); vals.Add(ProcessValue(data, _path)); } return vals; }
protected void WriteValue(SubStream outstream, object data) { if (data == null) { outstream.WriteByte((byte)'.'); } else if (data is string) { outstream.WriteByte((byte)'s'); outstream.WriteString((string)data); } else if (data is float) { outstream.WriteByte((byte)'f'); outstream.WriteSingle((float)data); } else if (data is int) { outstream.WriteByte((byte)'i'); outstream.WriteInt32((int)data); } else if (data is byte[]) { outstream.WriteByte((byte)'R'); WriteRawBinary(outstream, (byte[])data); } else if (data is List<string>) { outstream.WriteByte((byte)'S'); WriteStringList(outstream, (List<string>)data); } else if (data is List<float>) { outstream.WriteByte((byte)'F'); WriteSingleList(outstream, (List<float>)data); } else if (data is List<int>) { outstream.WriteByte((byte)'I'); WriteInt32List(outstream, (List<int>)data); } else if (data is IList) { outstream.WriteByte((byte)'M'); WriteList(outstream, (IList)data); } else if (data is IDictionary) { outstream.WriteByte((byte)'T'); WriteKeyValuePairs(outstream, (IDictionary)data); } else { throw new InvalidOperationException(String.Format("Unable to write value of type {0}", data.GetType().ToString())); } }
private static SubStream GetChunkData(SubStream data, long offset) { int totalsize = (((12 + (int)data.GetByte(offset + 6) + 7) & -8) + data.GetInt32(offset + 8) + 7) & -8; return new SubStream(data, offset, totalsize); }
protected static Bitmap GetBitmapFromDDS_ARGB16F(SubStream data, int offset, int width, int height, out bool hasalpha, out double intensity) { float[] fdata = new float[width * height * 4]; double maxval = Double.NegativeInfinity; double minval = Double.PositiveInfinity; double maxalpha = Double.NegativeInfinity; double minalpha = Double.PositiveInfinity; double alphaoffset = 0.0; hasalpha = false; for (int i = 0; i < width * height * 4; i+=4) { for (int j = 0; j < 4; j++) { fdata[i + j] = HalfToFloat(data.GetUInt16(offset + (i + j) * 2)); } for (int j = 0; j < 3; j++) { if (fdata[i + j] > maxval) { maxval = fdata[i + j]; } if (fdata[i + j] < minval) { minval = fdata[i + j]; } } if (fdata[i + 3] > maxalpha) { maxalpha = fdata[i + 3]; } if (fdata[i + 3] < minalpha) { minalpha = fdata[i + 3]; } } if (minval < 0 || minalpha < 0) { throw new NotImplementedException("ARGB16F with negative values not supported"); } if (maxval == 0) { maxval = 1.0; } if (maxalpha == 0) { maxalpha = 1.0; //alphaoffset = 1.0; } intensity = maxval; Bitmap bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); byte[] bmpraw = new byte[width * height * 4]; for (int i = 0; i < width * height * 4; i += 4) { bmpraw[i + 0] = (byte)(fdata[i + 2] * 255 / maxval); bmpraw[i + 1] = (byte)(fdata[i + 1] * 255 / maxval); bmpraw[i + 2] = (byte)(fdata[i + 0] * 255 / maxval); bmpraw[i + 3] = (byte)((fdata[i + 3] + alphaoffset) * 255 / maxalpha); hasalpha |= bmpraw[i + 3] != 255; } BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); for (int y = 0; y < height; y++) { Marshal.Copy(bmpraw, y * width * 4, bmpdata.Scan0 + y * bmpdata.Stride, width * 4); } bmp.UnlockBits(bmpdata); return bmp; }
protected RS5Chunk(SubStream chunkdata) { this.ChunkData = chunkdata; this._Data = new Lazy<SubStream>(() => GetData()); this._Chunks = new Lazy<Dictionary<string, RS5Chunk>>(() => GetChunks()); }
protected byte[] ProcessRawBinary(SubStream data) { List<object> vals = new List<object>(); int nents = data.ReadInt32(); byte[] rawdata = data.ReadBytes(nents); return rawdata; }
protected static Bitmap GetBitmapFromDDS_DXT5(SubStream data, int offset, int width, int height, bool IsDXT4, out bool hasalpha) { Bitmap bmp = new Bitmap(width, height, IsDXT4 ? PixelFormat.Format32bppPArgb : PixelFormat.Format32bppArgb); byte[] bmpraw = new byte[width * height * 4]; hasalpha = false; for (int y = 0; y < height; y += 4) { for (int x = 0; x < width; x += 4) { byte[] a = new byte[8]; a[0] = data.GetByte(offset); a[1] = data.GetByte(offset + 1); if (a[0] > a[1]) { a[2] = (byte)(((int)a[0] * 6 + a[1] * 1 + 3) / 7); a[3] = (byte)(((int)a[0] * 5 + a[1] * 2 + 3) / 7); a[4] = (byte)(((int)a[0] * 4 + a[1] * 3 + 3) / 7); a[5] = (byte)(((int)a[0] * 3 + a[1] * 4 + 3) / 7); a[6] = (byte)(((int)a[0] * 2 + a[1] * 5 + 3) / 7); a[7] = (byte)(((int)a[0] * 1 + a[1] * 6 + 3) / 7); } else { a[2] = (byte)(((int)a[0] * 4 + a[1] * 1 + 2) / 5); a[3] = (byte)(((int)a[0] * 3 + a[1] * 2 + 2) / 5); a[4] = (byte)(((int)a[0] * 2 + a[1] * 3 + 2) / 5); a[5] = (byte)(((int)a[0] * 1 + a[1] * 4 + 2) / 5); a[6] = 0x00; a[7] = 0xFF; } ulong alphasel = data.GetUInt64(offset) >> 16; byte[,] alphadata = new byte[4, 4]; for (int i = 0; i < 16; i++) { alphadata[i % 4, i / 4] = a[(alphasel >> (i * 3)) & 7]; } Color[,] colourdata = GetDXT1ColourBlock(data, offset + 8, true); for (int v = 0; v < 4; v++) { for (int u = 0; u < 4; u++) { if (x + u < width && y + v < height) { int i = ((y + v) * width + (x + u)) * 4; bmpraw[i] = colourdata[u, v].B; bmpraw[i + 1] = colourdata[u, v].G; bmpraw[i + 2] = colourdata[u, v].R; bmpraw[i + 3] = alphadata[u, v]; hasalpha |= alphadata[u, v] != 255; } } } offset += 16; } } BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, IsDXT4 ? PixelFormat.Format32bppPArgb : PixelFormat.Format32bppArgb); for (int y = 0; y < height; y++) { Marshal.Copy(bmpraw, y * width * 4, bmpdata.Scan0 + y * bmpdata.Stride, width * 4); } bmp.UnlockBits(bmpdata); return(bmp); }