Ejemplo n.º 1
0
        public IMGC(Stream input)
        {
            using (var br = new BinaryReaderX(input, true))
            {
                //Header
                header = br.ReadType <IMGCHeader>();
                if (header.imageFormat == 28 && header.bitDepth == 8)
                {
                    editMode           = true;
                    header.imageFormat = 29;
                }

                //get tile table
                br.BaseStream.Position = header.tableDataOffset;
                var tableC = br.ReadBytes(header.tableSize1);
                tableComp = (CompressionMethod)(tableC[0] & 0x7);
                byte[] table = Compressor.Decompress(new MemoryStream(tableC));

                //get image data
                br.BaseStream.Position = header.tableDataOffset + header.tableSize2;
                var texC = br.ReadBytes(header.imgDataSize);
                picComp = (CompressionMethod)(texC[0] & 0x7);
                byte[] tex = Compressor.Decompress(new MemoryStream(texC));

                //order pic blocks by table
                byte[] pic = Order(new MemoryStream(table), new MemoryStream(tex));

                //return finished image
                settings = new ImageSettings(Support.Format[header.imageFormat], header.width, header.height)
                {
                    Swizzle = new ImgcSwizzle(header.width, header.height)
                };
                Image = Kolors.Load(pic, settings);
            }
        }
Ejemplo n.º 2
0
        /// <inheritdoc cref="IIndexEncoding.Quantize(IEnumerable{Color},QuantizationSettings)"/>
        public (IEnumerable <IndexData> indices, IList <Color> palette) Quantize(IEnumerable <Color> colors, QuantizationSettings settings)
        {
            if (settings.ColorModel == ColorModel.RGBA)
            {
                settings.ColorModel = ColorModel.RGB;
            }

            var colorList = colors.ToList();

            var(indices, palette) = Kolors.Quantize(colorList, settings);

            var alphaIndexData = indices.
                                 Zip(colorList, (x, y) => new { index = x, alpha = y.A }).
                                 Select(x => new AlphaIndexData(Convert.ChangeBitDepth(x.alpha, 8, _alphaDepth), x.index));

            return(alphaIndexData, palette);
        }
Ejemplo n.º 3
0
        public void Save(Stream file)
        {
            int width    = (Image.Width + 0x7) & ~0x7;
            int height   = (Image.Height + 0x7) & ~0x7;
            var settings = new ImageSettings(Support.Format[header.imageFormat], width, height)
            {
                Swizzle = new ImgcSwizzle(width, height)
            };

            byte[] pic = Kolors.Save(Image, settings);

            using (var bw = new BinaryWriterX(file, true))
            {
                //Header
                header.width  = (short)Image.Width;
                header.height = (short)Image.Height;

                //tile table
                var    table     = new MemoryStream();
                byte[] importPic = Deflate(pic, Support.Format[header.imageFormat].BitDepth, out table);

                //Table
                bw.BaseStream.Position = 0x48;
                var comp = Compressor.Compress(table, tableComp);
                bw.Write(comp);
                header.tableSize1 = comp.Length;
                header.tableSize2 = (header.tableSize1 + 3) & ~3;

                //Image
                bw.BaseStream.Position = 0x48 + header.tableSize2;
                header.imageFormat     = (editMode) ? (byte)28 : header.imageFormat;
                comp = Compressor.Compress(new MemoryStream(importPic), picComp);
                bw.Write(comp);
                bw.WriteAlignment(4);
                header.imgDataSize = comp.Length;

                //Header
                bw.BaseStream.Position = 0;
                bw.WriteType(header);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="input"></param>
        public BTX(Stream input)
        {
            using (var br = new BinaryReaderX(input, true))
            {
                // Header
                Header = br.ReadType <FileHeader>();
                br.SeekAlignment();
                FileName = br.ReadCStringASCII();

                // Setup
                var dataLength        = Header.Width * Header.Height;
                var paletteDataLength = Header.ColorCount * 4;

                // Image
                br.BaseStream.Position = Header.ImageOffset;
                var texture = br.ReadBytes(dataLength);

                // Palette
                if (Header.Format == ImageFormat.Palette_8)
                {
                    br.BaseStream.Position = Header.PaletteOffset;
                    var palette = br.ReadBytes(paletteDataLength);

                    var settings = new IndexedImageSettings(IndexEncodings[(int)Header.Format], PaletteEncodings[(int)Header.Format], Header.Width, Header.Height);
                    var data     = Kolors.Load(texture, palette, settings);
                    Texture           = data.image;
                    Palette           = data.palette;
                    FormatName        = IndexEncodings[(int)Header.Format].FormatName;
                    PaletteFormatName = PaletteEncodings[(int)Header.Format].FormatName;
                    HasPalette        = true;
                }
                else
                {
                    var settings = new ImageSettings(Encodings[(int)Header.Format], Header.Width, Header.Height);
                    Texture    = Kolors.Load(texture, settings);
                    FormatName = Encodings[(int)Header.Format].FormatName;
                }
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="output"></param>
        public void Save(Stream output)
        {
            using (var bw = new BinaryWriterX(output, true))
            {
                // Updates
                Header.Width  = (short)Texture.Width;
                Header.Height = (short)Texture.Height;

                // Header
                bw.WriteType(Header);
                bw.WriteAlignment();
                bw.WriteString(FileName, Encoding.ASCII, false);
                bw.WriteAlignment();

                // Setup
                if (Header.Format == ImageFormat.Palette_8)
                {
                    var settings = new IndexedImageSettings(IndexEncodings[(int)Header.Format], PaletteEncodings[(int)Header.Format], Header.Width, Header.Height)
                    {
                        QuantizationSettings = new QuantizationSettings(new WuColorQuantizer(6, 3), Header.Width, Header.Height)
                        {
                            ColorCount    = 256,
                            ParallelCount = 8
                        }
                    };
                    var data = Kolors.Save(Texture, settings);

                    bw.Write(data.indexData);
                    bw.Write(data.paletteData);
                }
                else
                {
                    var settings = new ImageSettings(Encodings[(int)Header.Format], Header.Width, Header.Height);
                    var data     = Kolors.Save(Texture, settings);

                    bw.Write(data);
                }
            }
        }
Ejemplo n.º 6
0
        public TEX(Stream input)
        {
            using (var br = new BinaryReaderX(input))
            {
                // Set endianess
                if (br.PeekString() == "\0XET")
                {
                    br.ByteOrder = ByteOrder = ByteOrder.BigEndian;
                }

                // Header
                Header     = br.ReadType <FileHeader>();
                HeaderInfo = new FileHeaderInfo
                {
                    // Block 1
                    Version           = (Version)(Header.Block1 & 0xFFF),
                    Unknown1          = (int)((Header.Block1 >> 12) & 0xFFF),
                    Unused1           = (int)((Header.Block1 >> 24) & 0xF),
                    AlphaChannelFlags = (AlphaChannelFlags)((Header.Block1 >> 28) & 0xF),
                    // Block 2
                    MipMapCount = (int)(Header.Block2 & 0x3F),
                    Width       = (int)((Header.Block2 >> 6) & 0x1FFF),
                    Height      = Math.Max((int)((Header.Block2 >> 19) & 0x1FFF), MinHeight),
                    // Block 3
                    Unknown2 = (int)(Header.Block3 & 0xFF),
                    Format   = (byte)((Header.Block3 >> 8) & 0xFF),
                    Unknown3 = (int)((Header.Block3 >> 16) & 0xFFFF)
                };

                if (HeaderInfo.Version == Version._Switchv1 && !SwitchFormats.ContainsKey(HeaderInfo.Format))
                {
                    throw new InvalidOperationException($"Switch texture format 0x{HeaderInfo.Format.ToString("X2")} is not implemented.");
                }
                else if (!Formats.ContainsKey(HeaderInfo.Format))
                {
                    throw new InvalidOperationException($"Texture format 0x{HeaderInfo.Format.ToString("X2")} is not implemented.");
                }

                // TODO: Consider whether the following settings make more sense if conditioned by the ByteOrder (or Platform)
                //var format = HeaderInfo.Format.ToString().StartsWith("DXT1") ? Format.DXT1 : HeaderInfo.Format.ToString().StartsWith("DXT5") ? Format.DXT5 : HeaderInfo.Format;
                var encoding = (HeaderInfo.Version == Version._Switchv1) ? SwitchFormats[HeaderInfo.Format] : Formats[HeaderInfo.Format];

                List <int> mipMaps = null;
                if (HeaderInfo.Version == Version._Switchv1)
                {
                    var texOverallSize = br.ReadInt32();
                    if (texOverallSize > br.BaseStream.Length)
                    {
                        br.BaseStream.Position -= 4;
                        SwitchUnknownData       = br.ReadBytes(0x6C);
                        texOverallSize          = br.ReadInt32();
                        HeaderInfo.MipMapCount++;
                    }
                    mipMaps = br.ReadMultiple <int>(HeaderInfo.MipMapCount);
                }
                else if (HeaderInfo.Version != Version._3DSv1)
                {
                    mipMaps = br.ReadMultiple <int>(HeaderInfo.MipMapCount);
                }

                for (var i = 0; i < mipMaps.Count; i++)
                {
                    var texDataSize = 0;
                    if (SwitchUnknownData != null)
                    {
                        if (i + 1 == HeaderInfo.MipMapCount)
                        {
                            continue;
                        }
                        texDataSize = mipMaps[i + 1] - mipMaps[i];
                    }
                    else if (HeaderInfo.Version != Version._3DSv1)
                    {
                        texDataSize = (i + 1 < HeaderInfo.MipMapCount ? mipMaps[i + 1] : (int)br.BaseStream.Length) - mipMaps[i];
                    }
                    else
                    {
                        texDataSize = Formats[HeaderInfo.Format].BitDepth * (HeaderInfo.Width >> i) * (HeaderInfo.Height >> i) / 8;
                    }

                    Settings = new ImageSettings(encoding, Math.Max(HeaderInfo.Width >> i, 2), Math.Max(HeaderInfo.Height >> i, 2));

                    //Set possible Swizzles
                    if (HeaderInfo.Version == Version._3DSv1 || HeaderInfo.Version == Version._3DSv2 || HeaderInfo.Version == Version._3DSv3)
                    {
                        Settings.Swizzle = new CTRSwizzle(Settings.Width, Settings.Height, CtrTransformation.None, true);
                    }
                    else if (HeaderInfo.Version == Version._Switchv1)
                    {
                        Settings.Swizzle = new SwitchSwizzle(Settings.Width, Settings.Height, Settings.Encoding.BitDepth, GetSwitchSwizzleFormat(Settings.Encoding.FormatName), true);
                    }
                    else if (Settings.Encoding.FormatName.Contains("DXT"))
                    {
                        Settings.Swizzle = new BCSwizzle(Settings.Width, Settings.Height);
                    }

                    //Set possible pixel shaders
                    if ((Format)HeaderInfo.Format == Format.DXT5_B)
                    {
                        Settings.PixelShader = ToNoAlpha;
                    }
                    else if ((Format)HeaderInfo.Format == Format.DXT5_YCbCr)
                    {
                        Settings.PixelShader = ToProperColors;
                    }

                    EncodingInfo info = null;
                    if (HeaderInfo.Version == Version._3DSv1 || HeaderInfo.Version == Version._3DSv2 ||
                        HeaderInfo.Version == Version._3DSv3)
                    {
                        info = EncodingInfos.First(x => x.EncodingIndex == HeaderInfo.Format);
                    }
                    else if (HeaderInfo.Version == Version._Switchv1)
                    {
                        info = SwitchEncodingInfos.First(x => x.EncodingIndex == HeaderInfo.Format);
                    }

                    if (i == 0)
                    {
                        Bitmaps.Add(new BitmapInfo(Kolors.Load(br.ReadBytes(texDataSize), Settings), info));
                    }
                    else
                    {
                        Bitmaps[0].MipMaps.Add(Kolors.Load(br.ReadBytes(texDataSize), Settings));
                    }
                }

                if (SwitchUnknownData != null)
                {
                    SwitchOverflowingData = br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position));
                }
            }
        }
Ejemplo n.º 7
0
        public void Save(Stream output)
        {
            using (var bw = new BinaryWriterX(output, ByteOrder))
            {
                if (SwitchUnknownData != null)
                {
                    HeaderInfo.MipMapCount--;
                }
                Header.Block1 = (uint)((int)HeaderInfo.Version | (HeaderInfo.Unknown1 << 12) | (HeaderInfo.Unused1 << 24) | ((int)HeaderInfo.AlphaChannelFlags << 28));
                Header.Block2 = (uint)(HeaderInfo.MipMapCount | (HeaderInfo.Width << 6) | (HeaderInfo.Height << 19));
                Header.Block3 = (uint)(HeaderInfo.Unknown2 | ((int)HeaderInfo.Format << 8) | (HeaderInfo.Unknown3 << 16));
                bw.WriteType(Header);
                if (HeaderInfo.Version == Version._Switchv1 && SwitchUnknownData != null)
                {
                    bw.Write(SwitchUnknownData);
                }

                //var format = HeaderInfo.Format.ToString().StartsWith("DXT1") ? Format.DXT1 : HeaderInfo.Format.ToString().StartsWith("DXT5") ? Format.DXT5 : HeaderInfo.Format;
                var encoding = (HeaderInfo.Version == Version._Switchv1) ? SwitchFormats[HeaderInfo.Format] : Formats[HeaderInfo.Format];

                // Mipmap Downsampling
                if (Bitmaps.Count > 1 && HeaderInfo.MipMapCount > 1)
                {
                    var firstBitmap = Bitmaps[0].Image;
                    var width       = firstBitmap.Width;
                    var height      = firstBitmap.Height;
                    for (var i = 0; i < HeaderInfo.MipMapCount - 1; i++)
                    {
                        var bmp = new Bitmap(width / 2, height / 2);
                        var gfx = Graphics.FromImage(bmp);
                        gfx.InterpolationMode  = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                        gfx.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                        gfx.PixelOffsetMode    = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                        gfx.DrawImage(firstBitmap, new Rectangle(0, 0, bmp.Width, bmp.Height));
                        Bitmaps[0].MipMaps[i] = bmp;
                        width  = bmp.Width;
                        height = bmp.Height;
                    }
                }

                var bitmaps = new List <byte[]>();

                Settings = new ImageSettings(encoding, Bitmaps[0].Image.Width, Bitmaps[0].Image.Height);

                //Set possible Swizzles
                if (HeaderInfo.Version == Version._3DSv1 || HeaderInfo.Version == Version._3DSv2 || HeaderInfo.Version == Version._3DSv3)
                {
                    Settings.Swizzle = new CTRSwizzle(Bitmaps[0].Image.Width, Bitmaps[0].Image.Height, CtrTransformation.None, true);
                }
                else if (HeaderInfo.Version == Version._Switchv1)
                {
                    Settings.Swizzle = new SwitchSwizzle(Bitmaps[0].Image.Width, Bitmaps[0].Image.Height, Settings.Encoding.BitDepth, GetSwitchSwizzleFormat(Settings.Encoding.FormatName), true);    //Switch Swizzle
                }
                else if (Settings.Encoding.FormatName.Contains("DXT"))
                {
                    Settings.Swizzle = new BCSwizzle(Bitmaps[0].Image.Width, Bitmaps[0].Image.Height);
                }

                if ((Format)HeaderInfo.Format == Format.DXT5_B)
                {
                    Settings.PixelShader = ToNoAlpha;
                }
                else if ((Format)HeaderInfo.Format == Format.DXT5_YCbCr)
                {
                    Settings.PixelShader = ToOptimisedColors;
                }

                bitmaps.Add(Kolors.Save(Bitmaps[0].Image, Settings));

                foreach (var mipmap in Bitmaps[0].MipMaps)
                {
                    Settings = new ImageSettings(encoding, Bitmaps[0].Image.Width, Bitmaps[0].Image.Height);

                    //Set possible Swizzles
                    if (HeaderInfo.Version == Version._3DSv1 || HeaderInfo.Version == Version._3DSv2 || HeaderInfo.Version == Version._3DSv3)
                    {
                        Settings.Swizzle = new CTRSwizzle(mipmap.Width, mipmap.Height, CtrTransformation.None, true);
                    }
                    else if (HeaderInfo.Version == Version._Switchv1)
                    {
                        Settings.Swizzle = new SwitchSwizzle(mipmap.Width, mipmap.Height, Settings.Encoding.BitDepth, GetSwitchSwizzleFormat(Settings.Encoding.FormatName), true);    //Switch Swizzle
                    }
                    else if (Settings.Encoding.FormatName.Contains("DXT"))
                    {
                        Settings.Swizzle = new BCSwizzle(mipmap.Width, mipmap.Height);
                    }

                    if ((Format)HeaderInfo.Format == Format.DXT5_B)
                    {
                        Settings.PixelShader = ToNoAlpha;
                    }
                    else if ((Format)HeaderInfo.Format == Format.DXT5_YCbCr)
                    {
                        Settings.PixelShader = ToOptimisedColors;
                    }

                    bitmaps.Add(Kolors.Save(mipmap, Settings));
                }

                if (HeaderInfo.Version == Version._Switchv1)
                {
                    if (SwitchUnknownData != null)
                    {
                        var listOffset = bw.BaseStream.Position;
                        bw.BaseStream.Position += 8 + HeaderInfo.MipMapCount * sizeof(int);

                        var offsets   = new List <int>();
                        var relOffset = bw.BaseStream.Position;
                        foreach (var bitmap in bitmaps)
                        {
                            var data = new byte[(bitmap.Length + 0x1FF) & ~0x1FF];
                            Array.Copy(bitmap, data, bitmap.Length);
                            bw.Write(data);
                            offsets.Add((int)(bw.BaseStream.Position - relOffset));
                        }
                        offsets[offsets.Count - 1] = (offsets.Last() + 0x7FF) & ~0x7FF;
                        bw.BaseStream.Position     = relOffset + offsets.Last();

                        bw.Write(SwitchOverflowingData);

                        var totalSize = bw.BaseStream.Position - 0x84 - HeaderInfo.MipMapCount * sizeof(int);

                        bw.BaseStream.Position = listOffset;
                        bw.Write((int)totalSize);
                        bw.BaseStream.Position += 4;
                        foreach (var offset in offsets)
                        {
                            bw.Write(offset);
                        }
                    }
                    else
                    {
                        bw.BaseStream.Position += 0x4 + HeaderInfo.MipMapCount * sizeof(int);

                        var offsets   = new List <int>();
                        var relOffset = bw.BaseStream.Position;
                        foreach (var bitmap in bitmaps)
                        {
                            offsets.Add((int)(bw.BaseStream.Position - relOffset));
                            var data = new byte[(bitmap.Length + 0x1FF) & ~0x1FF];
                            Array.Copy(bitmap, data, bitmap.Length);
                            bw.Write(data);
                        }
                        var totalSize = bw.BaseStream.Position - (0x10 + 0x4 + HeaderInfo.MipMapCount * sizeof(int));

                        bw.BaseStream.Position = 0x10;
                        bw.Write((int)totalSize);
                        foreach (var offset in offsets)
                        {
                            bw.Write(offset);
                        }
                    }
                }
                else
                // Mipmaps, but not for Version 3DS v1
                if (HeaderInfo.Version != Version._3DSv1)
                {
                    var offset = HeaderInfo.Version == Version._PS3v1 ? HeaderInfo.MipMapCount * sizeof(int) + HeaderLength : 0;
                    foreach (var bitmap in bitmaps)
                    {
                        bw.Write(offset);
                        offset += bitmap.Length;
                    }
                }

                // Bitmaps
                if (SwitchUnknownData == null)
                {
                    foreach (var bitmap in bitmaps)
                    {
                        bw.Write(bitmap);
                    }
                }
            }
        }
Ejemplo n.º 8
0
        /// <inheritdoc cref="IIndexEncoding.Quantize(IEnumerable{Color},QuantizationSettings)"/>
        public (IEnumerable <IndexData> indices, IList <Color> palette) Quantize(IEnumerable <Color> colors, QuantizationSettings settings)
        {
            var(indices, palette) = Kolors.Quantize(colors, settings);

            return(indices.Select(x => new IndexData(x)), palette);
        }