コード例 #1
0
        /// <summary>
        /// Creates a Blp2 object from the specified data stream.
        /// </summary>
        /// <param name="stream">A stream that contains the data of a Blp2 or System.Drawing.Image picture.</param>
        /// <returns>Blp2 object containing the image of the stream.</returns>
        /// <exception cref=""></exception>
        public static Blp2 FromStream(Stream stream)
        {
            using (BinaryReader br = new BinaryReader(stream)) {
                Blp2Header header = Blp2Header.FromBinaryReader(br);

                Blp2 ret = new Blp2();

                if (new string(header.fourCC) == "BLP2")
                {
                    ret.bmp = new Bitmap((int)header.width, (int)header.height, PixelFormat.Format32bppArgb);

                    BitmapData bmpData = ret.bmp.LockBits(new Rectangle(0, 0, ret.bmp.Width, ret.bmp.Height), ImageLockMode.ReadWrite, ret.bmp.PixelFormat);

                    byte[] imgData = new byte[header.lengths[0]];
                    br.BaseStream.Seek(header.offsets[0], SeekOrigin.Begin);
                    imgData = br.ReadBytes(imgData.Length);

                    // BLP2 conversion
                    if (header.type == DataType.Uncompressed_DirectX && header.encoding == Encoding.RAW1 &&
                        (header.alphaDepth == AlphaDepth.NoAlpha || header.alphaDepth == AlphaDepth.Alpha1Bit || header.alphaDepth == AlphaDepth.Alpha8Bit))
                    {
                        // Uncompressed paletted image
                        ret.format = FileFormat.Raw;

                        // Load palette (4-byte BGRA color values)
                        br.BaseStream.Seek(Marshal.SizeOf(typeof(Blp2Header)), SeekOrigin.Begin);
                        byte[]  colorData = br.ReadBytes(256 * 4);
                        Color[] c         = new Color[256];
                        for (int i = 0; i < 1024; i += 4)
                        {
                            c[i / 4] = Color.FromArgb(255, colorData[i], colorData[i + 1], colorData[i + 2]);
                        }

                        // Read indexed bitmap
                        byte[] decompImgData = new byte[header.width * header.height * 4];
                        for (int i = 0; i < (header.width * header.height); i++)
                        {
                            decompImgData[i * 4]     = c[imgData[i]].R;
                            decompImgData[i * 4 + 1] = c[imgData[i]].G;
                            decompImgData[i * 4 + 2] = c[imgData[i]].B;
                            decompImgData[i * 4 + 3] = 255;
                        }

                        // Apply alpha channels
                        if (header.alphaDepth == AlphaDepth.Alpha8Bit)
                        {
                            // 8-bits alpha
                            br.BaseStream.Seek(header.offsets[0] + header.width * header.height, SeekOrigin.Begin);
                            byte[] alphaData = br.ReadBytes((int)(header.width * header.height));
                            for (int i = 0; i < (header.width * header.height); i++)
                            {
                                decompImgData[i * 4 + 3] = alphaData[i];
                            }
                        }
                        else if (header.alphaDepth == AlphaDepth.Alpha1Bit)
                        {
                            // 1-bits alpha
                            br.BaseStream.Seek(header.offsets[0] + (header.width * header.height), SeekOrigin.Begin);
                            byte[] alphaData = br.ReadBytes((int)(header.width * header.height / 8));
                            for (int i = 0; i < (header.width * header.height / 8); i++)
                            {
                                for (int j = 0; j < 8; j++)
                                {
                                    decompImgData[i * 32 + ((j + 1) * 4) - 1] = (byte)((alphaData[i] & 1 << j) == 1 << j ? 255 : 0);
                                }
                            }
                        }

                        Marshal.Copy(decompImgData, 0, bmpData.Scan0, decompImgData.Length);
                    }
                    else if (header.type == DataType.Uncompressed_DirectX && header.encoding == Encoding.RAW3 &&

                             (header.alphaDepth == AlphaDepth.NoAlpha || header.alphaDepth == AlphaDepth.Alpha1Bit || header.alphaDepth == AlphaDepth.Alpha8Bit))
                    {
                        // Uncompressed BGRA image
                        ret.format = FileFormat.Raw;
                        Marshal.Copy(imgData, 0, bmpData.Scan0, imgData.Length);
                    }
                    else if (header.type == DataType.Uncompressed_DirectX && header.encoding == Encoding.DXT &&
                             (header.alphaEncoding == AlphaEncoding.DXT1 || header.alphaEncoding == AlphaEncoding.DXT3 || header.alphaEncoding == AlphaEncoding.DXT5))
                    {
                        // DXT1/3/5
                        ret.format = FileFormat.Dxt;

                        byte[] decompImgData = new byte[header.width * header.height * 4];

                        LibSquish.DxtFormat flags = 0;
                        switch (header.alphaEncoding)
                        {
                        case AlphaEncoding.DXT1:
                            flags = LibSquish.DxtFormat.Dxt1;
                            break;

                        case AlphaEncoding.DXT3:
                            flags = LibSquish.DxtFormat.Dxt3;
                            break;

                        case AlphaEncoding.DXT5:
                            flags = LibSquish.DxtFormat.Dxt5;
                            break;
                        }

                        LibSquish.DecompressImage(decompImgData, header.width, header.height, imgData, (int)flags);
                        RemapRGBA(ref decompImgData);
                        Marshal.Copy(decompImgData, 0, bmpData.Scan0, decompImgData.Length);
                    }
                    else if (header.type == DataType.JPEG)
                    {
                        ret.format = FileFormat.Jpeg;
                        ret.bmp.UnlockBits(bmpData);
                        throw new NotImplementedException();
                    }
                    else
                    {
                        ret.bmp.UnlockBits(bmpData);
                        throw new BlpFormatException("The given BLP2 format is not supported.");
                    }

                    ret.bmp.UnlockBits(bmpData);
                }
                else
                {
                    try {
                        // Let System.Drawing.Image handle loading
                        ret.bmp    = (Bitmap)Image.FromStream(stream);
                        ret.format = FileFormat.Image;
                    } catch (ArgumentException e) {
                        throw new BlpFormatException("The stream did not contain valid image data.", e.InnerException);
                    }
                }

                ret.header = header;
                return(ret);
            }
        }
コード例 #2
0
        /// <summary>
        /// Saves the currently loaded image to a Dxt encoded Blp file.
        /// </summary>
        /// <param name="filename">The path to the output file.</param>
        /// <param name="format">Dxt format. See <see cref="LibSquish.DxtFormat"/></param>
        /// <param name="resizeMethod">Method for possibly required resizing. See <see cref="FixSize"/></param>
        /// <param name="hasMipmaps">Specifies whether mipmaps are generated or not.</param>
        /// <param name="compression">Compression method used by LibSquish. Affects quality / speed. See <see cref="LibSquish.ColorCompression"/></param>
        public void Save(string filename, LibSquish.DxtFormat format, ResizeMethod resizeMethod, bool hasMipmaps, LibSquish.ColorCompression compression = LibSquish.ColorCompression.ClusterFit)
        {
            if (bmp != null)
            {
                FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Write);

                using (BinaryWriter bw = new BinaryWriter(fs)) {
                    Blp2Header header = new Blp2Header(DataType.Uncompressed_DirectX, Encoding.DXT, 0, 0, (byte)(hasMipmaps ? 1 : 0), 0, 0);

                    List <Bitmap> bmps = new List <Bitmap>();
                    // Add resized image to the output
                    bmps.Add(FixSize(resizeMethod));

                    header.width  = (uint)bmps[0].Width;
                    header.height = (uint)bmps[0].Height;

                    // Add mipmaps
                    if (hasMipmaps)
                    {
                        bmps.AddRange(GenerateMipmaps(bmps[0]));
                    }

                    byte[] compImgData  = { };
                    byte[] colorPalette = new byte[256 * 4];

                    switch (format)
                    {
                    case LibSquish.DxtFormat.Dxt1:
                        header.alphaEncoding = AlphaEncoding.DXT1;
                        header.alphaDepth    = AlphaDepth.Alpha1Bit;
                        break;

                    case LibSquish.DxtFormat.Dxt3:
                        header.alphaEncoding = AlphaEncoding.DXT3;
                        header.alphaDepth    = AlphaDepth.Alpha8Bit;
                        break;

                    case LibSquish.DxtFormat.Dxt5:
                        header.alphaEncoding = AlphaEncoding.DXT5;
                        header.alphaDepth    = AlphaDepth.Alpha8Bit;
                        break;
                    }

                    for (int i = 0; i < bmps.Count; i++)
                    {
                        // Copy raw image data to byte array
                        BitmapData bmpData = bmps[i].LockBits(new Rectangle(0, 0, bmps[i].Width, bmps[i].Height), ImageLockMode.ReadOnly, bmps[i].PixelFormat);
                        byte[]     imgData = new byte[bmpData.Stride * bmps[i].Height];
                        Marshal.Copy(bmpData.Scan0, imgData, 0, bmpData.Stride * bmps[i].Height);
                        bmps[i].UnlockBits(bmpData);

                        // Set up conversion flags
                        int flags = (int)format | (int)compression | (int)LibSquish.ColorErrorMetric.Perceptual;

                        // Compress to DXT format
                        RemapRGBA(ref imgData);
                        byte[] buff = new byte[LibSquish.GetStorageRequirements((uint)bmps[i].Width, (uint)bmps[i].Height, flags)];
                        LibSquish.CompressImage(imgData, (uint)bmps[i].Width, (uint)bmps[i].Height, buff, flags);

                        Array.Resize(ref compImgData, compImgData.Length + buff.Length);
                        buff.CopyTo(compImgData, compImgData.Length - buff.Length);

                        // Image data locations
                        header.offsets[i] = (i > 0) ? header.offsets[i - 1] + header.lengths[i - 1] : (uint)(Marshal.SizeOf(typeof(Blp2Header)) + colorPalette.Length);
                        header.lengths[i] = (uint)buff.Length;
                    }

                    bw.Write(header.GetBytes());
                    bw.Write(colorPalette);
                    bw.Write(compImgData);
                }
            }
            else
            {
                throw new BlpConversionException("No image data to convert.");
            }
        }