1. Head to the 33rd Modeling Contest Poll and drink to your heart's desire.
    Dismiss Notice
  2. Choose your means of doom in the 17th Mini Mapping Contest Poll.
    Dismiss Notice
  3. A slave to two rhythms, the 22nd Terraining Contest is here.
    Dismiss Notice
  4. The heavens smile on the old faithful. The 16th Techtree Contest has begun.
    Dismiss Notice
  5. The die is cast - the 6th Melee Mapping Contest results have been announced. Onward to the Hive Cup!
    Dismiss Notice
  6. The glory of the 20th Icon Contest is yours for the taking!
    Dismiss Notice
  7. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Help reading blp file on c#

Discussion in 'Warcraft Editing Tools' started by Trigger.edge, Jul 29, 2017.

  1. Trigger.edge

    Trigger.edge

    Joined:
    Jun 21, 2012
    Messages:
    419
    Resources:
    0
    Resources:
    0
    Hello guys.

    I'm looking for a library (dll) or command-line tool to convert blp images into tga/png/jpg and vice versa.

    What do you recommend me?
     
    Last edited: Jul 30, 2017
  2. GhostWolf

    GhostWolf

    Joined:
    Jul 29, 2007
    Messages:
    4,952
    Resources:
    2
    Tools:
    1
    Tutorials:
    1
    Resources:
    2
    I don't believe any command-line tools exist, but you can ask DSG to make one - Imperial BLP.

    Note that if what you are really looking for is batch conversion, BLP Lab supports it.

    If you want to actually use BLP textures, parsing them is fairly simple!
     
  3. Dr Super Good

    Dr Super Good

    Spell Reviewer

    Joined:
    Jan 18, 2005
    Messages:
    26,100
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    Currently there are no C++ (can be integrated into C#) libraries which correctly parse blp0/1. I do plan on making one eventually but unfortunately I have too many projects at the moment to consider.

    I could create a simple Java (jar) program that could be run from the command line to convert BLP0/1 files into tga or png files. I would not advise conversion directly to jpg due to the losy nature of jpg, at least in its most common form.
     
  4. Trigger.edge

    Trigger.edge

    Joined:
    Jun 21, 2012
    Messages:
    419
    Resources:
    0
    Resources:
    0
    Thanks guys, I'm using PitzerMike's blpaletter, although it makes me a bit complicated since I have to adapt some of its functions.
     
  5. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,789
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    I can probably make something for you when I have time.

    You can try porting my PHP-BLP library to C# yourself if you like.
     
  6. Trigger.edge

    Trigger.edge

    Joined:
    Jun 21, 2012
    Messages:
    419
    Resources:
    0
    Resources:
    0
    Well, since blpaletter does not support read images with alpha channels, I will try to use your library.

    Although it would be helpful if you convert it to c#
     
  7. Dr Super Good

    Dr Super Good

    Spell Reviewer

    Joined:
    Jan 18, 2005
    Messages:
    26,100
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    That library seems wrong. For example it is not correctly parsing the alphaBits and hasMipmaps fields.

    Here is an implementation for Java ImageIO framework which can also be used as a reference.
     
  8. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,429
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    @Shadow Daemon gave me a command-line version of BLPLab a few years ago. Here it is, help is in blplabcl.txt:
     

    Attached Files:

  9. Dr Super Good

    Dr Super Good

    Spell Reviewer

    Joined:
    Jan 18, 2005
    Messages:
    26,100
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    Worth noting that BLP Lab's BLP library is incorrect. It will work for most common textures, but it is not complaint with Warcraft III.
     
  10. Trigger.edge

    Trigger.edge

    Joined:
    Jun 21, 2012
    Messages:
    419
    Resources:
    0
    Resources:
    0
    My antivirus will not let me use blplabcl.exe :D

    [​IMG]
    With this code I am able to read the Blp header, however I do not know how to read the image data :/
    PHP:
    public BlpFile(Stream stream)
            {
                str = stream;
                byte[] buffer = new byte[4];

                str.Read(buffer, 0, 4);


                //Prints BLP type
                DebugMsg(Encoding.ASCII.GetString(buffer, 0, 4));


                // Reading compression
                str.Read(buffer, 0, 4);
                uint compression = BitConverter.ToUInt32(buffer, 0);

                DebugMsg(compression.ToString());
               
                // Reading encoding, alphaBitDepth, alphaEncoding and hasMipmaps
                str.Read(buffer, 0, 4);

                encoding = buffer[0];
                alphaDepth = buffer[1];
                alphaEncoding = buffer[2];
                hasMipmaps = buffer[3];

                // Reading width
                str.Read(buffer, 0, 4);
                width = BitConverter.ToInt32(buffer, 0);

                DebugMsg(width.ToString());

                // Reading height
                str.Read(buffer, 0, 4);
                height = BitConverter.ToInt32(buffer, 0);

                DebugMsg(height.ToString());
               
                // Reading MipmapOffset Array
                for (int i = 0; i < 16; i++)
                {
                    str.Read(buffer, 0, 4);
                    mipmapOffsets[i] = BitConverter.ToUInt32(buffer, 0);
                }

                // Reading MipmapSize Array
                for (int i = 0; i < 16; i++)
                {
                    str.Read(buffer, 0, 4);
                    mippmapSize[i] = BitConverter.ToUInt32(buffer, 0);
                }

                // When encoding is 1, there is no image compression and we have to read a color palette
                if (encoding == 1)
                {
                    // Reading palette
                    for (int i = 0; i < 256; i++)
                    {
                        byte[] color = new byte[4];
                        str.Read(color, 0, 4);
                        paletteBGRA[i].blue = color[0];
                        paletteBGRA[i].green = color[1];
                        paletteBGRA[i].red = color[2];
                        paletteBGRA[i].alpha = color[3];
                    }
                }
            }
     
     

    Attached Files:

    • 113.png
      113.png
      File size:
      10.1 KB
      Views:
      365
  11. Dr Super Good

    Dr Super Good

    Spell Reviewer

    Joined:
    Jan 18, 2005
    Messages:
    26,100
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    That seems to be the header for BLP2 (World of Warcraft) and not BLP1 (Warcraft III).

    There are a ton of C++ implementations for reading BLP2. However my Java, and possibly GhostWolf's JavaScrpt are the only BLP1 libraries to correctly read the format. TriggerHappy's PHP mostly reads BLP1, but appears to be lacking decoding logic for index content with 1 and 4 bit alpha packing.
     
  12. Trigger.edge

    Trigger.edge

    Joined:
    Jun 21, 2012
    Messages:
    419
    Resources:
    0
    Resources:
    0
    Well I have "fixed" the code based on magos blp format specification, does anyone have an idea that I am doing wrong here?

    Code (CSS):

            public static void DebugMsg(string msg)
            {
                MessageBox.Show(msg, "", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }

            public string ReadString(byte[] buffer, int count)
            {
                str.Read(buffer, 0, count);
                return Encoding.ASCII.GetString(buffer, 0, 4);
            }

            public bool ReadBool(byte[] buffer, int count)
            {
                str.Read(buffer, 0, count);
                return BitConverter.ToBoolean(buffer, 0);
            }

            public uint ReadUInt32(byte[] buffer, int count)
            {
                str.Read(buffer, 0, count);
                return BitConverter.ToUInt32(buffer, 0);
            }

            public int ReadInt32(byte[] buffer, int count)
            {
                str.Read(buffer, 0, count);
                return BitConverter.ToInt32(buffer, 0);
            }

            public BlpFile(Stream stream)
            {
                str = stream;
                byte[] buffer = new byte[4];

                type = ReadString(buffer, 4);
                compression = ReadUInt32(buffer, 4);
                alphaFlags = ReadUInt32(buffer, 4);
                width = ReadUInt32(buffer, 4);
                height = ReadUInt32(buffer, 4);
                alphaEncoding = ReadUInt32(buffer, 4);
             
                //read unused flags
                hasMipmaps = ReadBool(buffer, 4);

                for (int i = 0; i < 16; i++)
                    mipmapOffset[i] = ReadUInt32(buffer, 4);
                for (int i = 0; i < 16; i++)
                    mipmapSize[i] = ReadUInt32(buffer, 4);

                while (mipmapOffset[mipmapCount] != 0 && mipmapSize[mipmapCount] != 0)
                    mipmapCount++;

                if (0 == compression)
                {
                    jpegHeaderSize = ReadUInt32(buffer, 4);

                    jpegHeader = new byte[jpegHeaderSize];
                    str.Read(jpegHeader, 0, Convert.ToInt32(jpegHeaderSize));

                    if (type == "BLP1")
                    {
                        imageData = new byte[mipmapSize[0]];
                        str.Position = mipmapOffset[0];
                        str.Read(imageData, 0, imageData.Length);


                        //My problem begins here for blp compressed:
                        int w = Convert.ToInt32(width);
                        int h = Convert.ToInt32(height);

                        bitmap = new Bitmap(w, h);
                        BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
                        Marshal.Copy(imageData, 0, bmpdata.Scan0, imageData.Length);
                        bitmap.UnlockBits(bmpdata);
                    }
                }
                else if (1 == compression)
                {
                    // Reading palette

                    for (int i = 0; i < 256; i++)
                    {
                        Palette[i].blue = ReadInt32(buffer, 4);
                        Palette[i].green = ReadInt32(buffer, 4);
                        Palette[i].red = ReadInt32(buffer, 4);
                        Palette[i].alpha = ReadInt32(buffer, 4);
                    }

                    int[] indexList = new int[width * height];
                    int[] alphaList = new int[width * height];

                    for (int i = 0; i < width * height; i++)
                        indexList[i] = ReadInt32(buffer, 4);

                    if (alphaFlags == 8)
                    {
                        for (int i = 0; i < width * height; i++)
                            alphaList[i] = ReadInt32(buffer, 4);
                    }

                    // Whats Next?

                }
     
  13. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,789
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    JPEG-BLP's are basically a JPEG image (technically multiple, with mipmaps) with a BLP header. For those you can just read the first mipmap and merge it with the JPEG header. The only issue is that the colorspace may be BGR (you want RGB), so you will have to figure out how to convert it from there. PHP-BLP uses a tool called imagemagick, and I think there is a windows binary you can use, but there may be a better way with a native C# library.

    For palleted BLP's you need a way to dynamically create an image and fill it up with the correct colors.

    You may want to use DSG's BLP spec:

    BLP Specifications (WC3)
     
  14. Dr Super Good

    Dr Super Good

    Spell Reviewer

    Joined:
    Jan 18, 2005
    Messages:
    26,100
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    Mipmap count is based on the hasMipmaps. If not 0 then a full set of mipmaps (ending at 1*1) is present, otherwise only the full scale image is present.

    JPEG content BLPs are literally JPEG image files. This means they have their own height and width. One must use the mipmap height and width to resize the decoded JPEG image appropriately.

    Indexed colour BLP files have a header consisting of 256 BGR colour entries, each entry being 4 bytes with 1 of these being unused (no alpha).
     
    Last edited: Aug 5, 2017