Advertisement
Bunny83

BMPLoader

Feb 5th, 2017 (edited)
5,078
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 23.30 KB | None | 0 0
  1. #region License and Information
  2. /*****
  3. *
  4. * BMPLoader.cs
  5. *
  6. * This is a simple implementation of a BMP file loader for Unity3D.
  7. * Formats it should support are:
  8. *  - 1 bit monochrome indexed
  9. *  - 2-8 bit indexed
  10. *  - 16 / 24 / 32 bit color (including "BI_BITFIELDS")
  11. *  - RLE-4 and RLE-8 support has been added.
  12. *
  13. * Unless the type is "BI_ALPHABITFIELDS" the loader does not interpret alpha
  14. * values by default, however you can set the "ReadPaletteAlpha" setting to
  15. * true to interpret the 4th (usually "00") value as alpha for indexed images.
  16. * You can also set "ForceAlphaReadWhenPossible" to true so it will interpret
  17. * the "left over" bits as alpha if there are any. It will also force to read
  18. * alpha from a palette if it's an indexed image, just like "ReadPaletteAlpha".
  19. *
  20. * It's not tested well to the bone, so there might be some errors somewhere.
  21. * However I tested it with 4 different images created with MS Paint
  22. * (1bit, 4bit, 8bit, 24bit) as those are the only formats supported.
  23. *
  24. * 2017.02.05 - first version
  25. * 2017.03.06 - Added RLE4 / RLE8 support
  26. * 2021.01.21 - Fixed RLE4 bug; Fixed wrongly reading bit masks for indexed images.
  27. * 2021.01.22 - Addes support for negative heights (top-down images) The actual
  28. *              flipping happens once at the Texture2D conversion.
  29. *
  30. * Copyright (c) 2017 Markus Göbel (Bunny83)
  31. *
  32. * Permission is hereby granted, free of charge, to any person obtaining a copy
  33. * of this software and associated documentation files (the "Software"), to
  34. * deal in the Software without restriction, including without limitation the
  35. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  36. * sell copies of the Software, and to permit persons to whom the Software is
  37. * furnished to do so, subject to the following conditions:
  38. *
  39. * The above copyright notice and this permission notice shall be included in
  40. * all copies or substantial portions of the Software.
  41. *
  42. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  43. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  44. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  45. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  46. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  47. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  48. * IN THE SOFTWARE.
  49. *
  50. *****/
  51. #endregion License and Information
  52. using UnityEngine;
  53. using System.Collections;
  54. using System.Collections.Generic;
  55. using System.IO;
  56. using System;
  57.  
  58. namespace B83.Image.BMP
  59. {
  60.     public enum BMPComressionMode : int
  61.     {
  62.         BI_RGB = 0x00,
  63.         BI_RLE8 = 0x01,
  64.         BI_RLE4 = 0x02,
  65.         BI_BITFIELDS = 0x03,
  66.         BI_JPEG = 0x04,
  67.         BI_PNG = 0x05,
  68.         BI_ALPHABITFIELDS = 0x06,
  69.  
  70.         BI_CMYK = 0x0B,
  71.         BI_CMYKRLE8 = 0x0C,
  72.         BI_CMYKRLE4 = 0x0D,
  73.  
  74.     }
  75.     public struct BMPFileHeader
  76.     {
  77.         public ushort magic; // "BM"
  78.         public uint filesize;
  79.         public uint reserved;
  80.         public uint offset;
  81.     }
  82.     public struct BitmapInfoHeader
  83.     {
  84.         public uint size;
  85.         public int width;
  86.         public int height;
  87.         public ushort nColorPlanes; // always 1
  88.         public ushort nBitsPerPixel; // [1,4,8,16,24,32]
  89.         public BMPComressionMode compressionMethod;
  90.         public uint rawImageSize; // can be "0"
  91.         public int xPPM;
  92.         public int yPPM;
  93.         public uint nPaletteColors;
  94.         public uint nImportantColors;
  95.  
  96.         public int absWidth { get { return Mathf.Abs(width); } }
  97.         public int absHeight { get { return Mathf.Abs(height); } }
  98.  
  99.     }
  100.  
  101.     public class BMPImage
  102.     {
  103.         public BMPFileHeader header;
  104.         public BitmapInfoHeader info;
  105.         public uint rMask = 0x00FF0000;
  106.         public uint gMask = 0x0000FF00;
  107.         public uint bMask = 0x000000FF;
  108.         public uint aMask = 0x00000000;
  109.         public List<Color32> palette;
  110.         public Color32[] imageData;
  111.         public Texture2D ToTexture2D()
  112.         {
  113.             var tex = new Texture2D(info.absWidth, info.absHeight);
  114.            
  115.             if (info.height < 0)
  116.                 FlipImage();
  117.            
  118.             tex.SetPixels32(imageData);
  119.             tex.Apply();
  120.             return tex;
  121.         }
  122.         // flip image if height is negative
  123.         internal void FlipImage()
  124.         {
  125.             if (info.height > 0)
  126.                 return;
  127.             int w = info.absWidth;
  128.             int h = info.absHeight;
  129.             int h2 = h / 2;
  130.             for (int y = 0; y < h2; y++)
  131.             {
  132.                 for(int x = 0, o1=y*w, o2=(h-y-1)*w; x < w; x++,o1++,o2++)
  133.                 {
  134.                     var tmp = imageData[o1];
  135.                     imageData[o1] = imageData[o2];
  136.                     imageData[o2] = tmp;
  137.                 }
  138.             }
  139.             info.height = h;
  140.         }
  141.  
  142.         public void ReplaceColor(Color32 aColorToSearch, Color32 aReplacementColor)
  143.         {
  144.             var s = aColorToSearch;
  145.             for (int i = 0; i < imageData.Length; i++)
  146.             {
  147.                 var c = imageData[i];
  148.                 if (c.r == s.r && c.g == s.g && c.b == s.b && c.a == s.a)
  149.                     imageData[i] = aReplacementColor;
  150.             }
  151.         }
  152.         public void ReplaceFirstPixelColor(Color32 aReplacementColor)
  153.         {
  154.             ReplaceColor(imageData[0], aReplacementColor);
  155.         }
  156.         public void ReplaceFirstPixelColorWithTransparency()
  157.         {
  158.             ReplaceFirstPixelColor(new Color32(0, 0, 0, 0));
  159.         }
  160.     }
  161.  
  162.  
  163.     public class BMPLoader
  164.     {
  165.         const ushort MAGIC = 0x4D42; // "BM" little endian
  166.         public bool ReadPaletteAlpha = false;
  167.         public bool ForceAlphaReadWhenPossible = false;
  168.  
  169.         public BMPImage LoadBMP(string aFileName)
  170.         {
  171.             using (var file = File.OpenRead(aFileName))
  172.                 return LoadBMP(file);
  173.         }
  174.         public BMPImage LoadBMP(byte[] aData)
  175.         {
  176.             using (var stream = new MemoryStream(aData))
  177.                 return LoadBMP(stream);
  178.         }
  179.  
  180.         public BMPImage LoadBMP(Stream aData)
  181.         {
  182.             using (var reader = new BinaryReader(aData))
  183.                 return LoadBMP(reader);
  184.  
  185.         }
  186.         public BMPImage LoadBMP(BinaryReader aReader)
  187.         {
  188.             BMPImage bmp = new BMPImage();
  189.             if (!ReadFileHeader(aReader, ref bmp.header))
  190.             {
  191.                 Debug.LogError("Not a BMP file");
  192.                 return null;
  193.             }
  194.             if (!ReadInfoHeader(aReader, ref bmp.info))
  195.             {
  196.                 Debug.LogError("Unsupported header format");
  197.                 return null;
  198.             }
  199.             if (bmp.info.compressionMethod != BMPComressionMode.BI_RGB
  200.                 && bmp.info.compressionMethod != BMPComressionMode.BI_BITFIELDS
  201.                 && bmp.info.compressionMethod != BMPComressionMode.BI_ALPHABITFIELDS
  202.                 && bmp.info.compressionMethod != BMPComressionMode.BI_RLE4
  203.                 && bmp.info.compressionMethod != BMPComressionMode.BI_RLE8
  204.                 )
  205.             {
  206.                 Debug.LogError("Unsupported image format: " + bmp.info.compressionMethod);
  207.                 return null;
  208.             }
  209.             long offset = 14 + bmp.info.size;
  210.             aReader.BaseStream.Seek(offset, SeekOrigin.Begin);
  211.             if (bmp.info.nBitsPerPixel < 24)
  212.             {
  213.                 bmp.rMask = 0x00007C00;
  214.                 bmp.gMask = 0x000003E0;
  215.                 bmp.bMask = 0x0000001F;
  216.             }
  217.  
  218.             if (bmp.info.nBitsPerPixel > 8 && (bmp.info.compressionMethod == BMPComressionMode.BI_BITFIELDS || bmp.info.compressionMethod == BMPComressionMode.BI_ALPHABITFIELDS))
  219.             {
  220.                 bmp.rMask = aReader.ReadUInt32();
  221.                 bmp.gMask = aReader.ReadUInt32();
  222.                 bmp.bMask = aReader.ReadUInt32();
  223.             }
  224.             if (ForceAlphaReadWhenPossible)
  225.                 bmp.aMask = GetMask(bmp.info.nBitsPerPixel) ^ (bmp.rMask | bmp.gMask | bmp.bMask);
  226.  
  227.             if (bmp.info.compressionMethod == BMPComressionMode.BI_ALPHABITFIELDS)
  228.                 bmp.aMask = aReader.ReadUInt32();
  229.  
  230.             if (bmp.info.nPaletteColors > 0 || bmp.info.nBitsPerPixel <= 8)
  231.                 bmp.palette = ReadPalette(aReader, bmp, ReadPaletteAlpha || ForceAlphaReadWhenPossible);
  232.  
  233.  
  234.             aReader.BaseStream.Seek(bmp.header.offset, SeekOrigin.Begin);
  235.             bool uncompressed = bmp.info.compressionMethod == BMPComressionMode.BI_RGB ||
  236.                 bmp.info.compressionMethod == BMPComressionMode.BI_BITFIELDS ||
  237.                 bmp.info.compressionMethod == BMPComressionMode.BI_ALPHABITFIELDS;
  238.             if (bmp.info.nBitsPerPixel == 32 && uncompressed)
  239.                 Read32BitImage(aReader, bmp);
  240.             else if (bmp.info.nBitsPerPixel == 24 && uncompressed)
  241.                 Read24BitImage(aReader, bmp);
  242.             else if (bmp.info.nBitsPerPixel == 16 && uncompressed)
  243.                 Read16BitImage(aReader, bmp);
  244.             else if (bmp.info.compressionMethod == BMPComressionMode.BI_RLE4 && bmp.info.nBitsPerPixel == 4 && bmp.palette != null)
  245.                 ReadIndexedImageRLE4(aReader, bmp);
  246.             else if (bmp.info.compressionMethod == BMPComressionMode.BI_RLE8 && bmp.info.nBitsPerPixel == 8 && bmp.palette != null)
  247.                 ReadIndexedImageRLE8(aReader, bmp);
  248.             else if (uncompressed && bmp.info.nBitsPerPixel <= 8 && bmp.palette != null)
  249.                 ReadIndexedImage(aReader, bmp);
  250.             else
  251.             {
  252.                 Debug.LogError("Unsupported file format: " + bmp.info.compressionMethod + " BPP: " + bmp.info.nBitsPerPixel);
  253.                 return null;
  254.             }
  255.             return bmp;
  256.         }
  257.  
  258.  
  259.         private static void Read32BitImage(BinaryReader aReader, BMPImage bmp)
  260.         {
  261.             int w = Mathf.Abs(bmp.info.width);
  262.             int h = Mathf.Abs(bmp.info.height);
  263.             Color32[] data = bmp.imageData = new Color32[w * h];
  264.             if (aReader.BaseStream.Position + w * h * 4 > aReader.BaseStream.Length)
  265.             {
  266.                 Debug.LogError("Unexpected end of file.");
  267.                 return;
  268.             }
  269.             int shiftR = GetShiftCount(bmp.rMask);
  270.             int shiftG = GetShiftCount(bmp.gMask);
  271.             int shiftB = GetShiftCount(bmp.bMask);
  272.             int shiftA = GetShiftCount(bmp.aMask);
  273.             byte a = 255;
  274.             for (int i = 0; i < data.Length; i++)
  275.             {
  276.                 uint v = aReader.ReadUInt32();
  277.                 byte r = (byte)((v & bmp.rMask) >> shiftR);
  278.                 byte g = (byte)((v & bmp.gMask) >> shiftG);
  279.                 byte b = (byte)((v & bmp.bMask) >> shiftB);
  280.                 if (bmp.bMask != 0)
  281.                     a = (byte)((v & bmp.aMask) >> shiftA);
  282.                 data[i] = new Color32(r, g, b, a);
  283.             }
  284.         }
  285.  
  286.  
  287.         private static void Read24BitImage(BinaryReader aReader, BMPImage bmp)
  288.         {
  289.             int w = Mathf.Abs(bmp.info.width);
  290.             int h = Mathf.Abs(bmp.info.height);
  291.             int rowLength = ((24 * w + 31) / 32) * 4;
  292.             int count = rowLength * h;
  293.             int pad = rowLength - w * 3;
  294.             Color32[] data = bmp.imageData = new Color32[w * h];
  295.             if (aReader.BaseStream.Position + count > aReader.BaseStream.Length)
  296.             {
  297.                 Debug.LogError("Unexpected end of file. (Have " + (aReader.BaseStream.Position + count) + " bytes, expected " + aReader.BaseStream.Length + " bytes)");
  298.                 return;
  299.             }
  300.             int shiftR = GetShiftCount(bmp.rMask);
  301.             int shiftG = GetShiftCount(bmp.gMask);
  302.             int shiftB = GetShiftCount(bmp.bMask);
  303.             for (int y = 0; y < h; y++)
  304.             {
  305.                 for (int x = 0; x < w; x++)
  306.                 {
  307.                     uint v = aReader.ReadByte() | ((uint)aReader.ReadByte() << 8) | ((uint)aReader.ReadByte() << 16);
  308.                     byte r = (byte)((v & bmp.rMask) >> shiftR);
  309.                     byte g = (byte)((v & bmp.gMask) >> shiftG);
  310.                     byte b = (byte)((v & bmp.bMask) >> shiftB);
  311.                     data[x + y * w] = new Color32(r, g, b, 255);
  312.                 }
  313.                 for (int i = 0; i < pad; i++)
  314.                     aReader.ReadByte();
  315.             }
  316.         }
  317.  
  318.         private static void Read16BitImage(BinaryReader aReader, BMPImage bmp)
  319.         {
  320.             int w = Mathf.Abs(bmp.info.width);
  321.             int h = Mathf.Abs(bmp.info.height);
  322.             int rowLength = ((16 * w + 31) / 32) * 4;
  323.             int count = rowLength * h;
  324.             int pad = rowLength - w * 2;
  325.             Color32[] data = bmp.imageData = new Color32[w * h];
  326.             if (aReader.BaseStream.Position + count > aReader.BaseStream.Length)
  327.             {
  328.                 Debug.LogError("Unexpected end of file. (Have " + (aReader.BaseStream.Position + count) + " bytes, expected " + aReader.BaseStream.Length + " bytes)");
  329.                 return;
  330.             }
  331.             int shiftR = GetShiftCount(bmp.rMask);
  332.             int shiftG = GetShiftCount(bmp.gMask);
  333.             int shiftB = GetShiftCount(bmp.bMask);
  334.             int shiftA = GetShiftCount(bmp.aMask);
  335.             byte a = 255;
  336.             for (int y = 0; y < h; y++)
  337.             {
  338.                 for (int x = 0; x < w; x++)
  339.                 {
  340.                     uint v = aReader.ReadByte() | ((uint)aReader.ReadByte() << 8);
  341.                     byte r = (byte)((v & bmp.rMask) >> shiftR);
  342.                     byte g = (byte)((v & bmp.gMask) >> shiftG);
  343.                     byte b = (byte)((v & bmp.bMask) >> shiftB);
  344.                     if (bmp.aMask != 0)
  345.                         a = (byte)((v & bmp.aMask) >> shiftA);
  346.                     data[x + y * w] = new Color32(r, g, b, a);
  347.                 }
  348.                 for (int i = 0; i < pad; i++)
  349.                     aReader.ReadByte();
  350.             }
  351.         }
  352.  
  353.         private static void ReadIndexedImage(BinaryReader aReader, BMPImage bmp)
  354.         {
  355.             int w = Mathf.Abs(bmp.info.width);
  356.             int h = Mathf.Abs(bmp.info.height);
  357.             int bitCount = bmp.info.nBitsPerPixel;
  358.             int rowLength = ((bitCount * w + 31) / 32) * 4;
  359.             int count = rowLength * h;
  360.             int pad = rowLength - (w * bitCount + 7) / 8;
  361.             Color32[] data = bmp.imageData = new Color32[w * h];
  362.             if (aReader.BaseStream.Position + count > aReader.BaseStream.Length)
  363.             {
  364.                 Debug.LogError("Unexpected end of file. (Have " + (aReader.BaseStream.Position + count) + " bytes, expected " + aReader.BaseStream.Length + " bytes)");
  365.                 return;
  366.             }
  367.             BitStreamReader bitReader = new BitStreamReader(aReader);
  368.             for (int y = 0; y < h; y++)
  369.             {
  370.                 for (int x = 0; x < w; x++)
  371.                 {
  372.                     int v = (int)bitReader.ReadBits(bitCount);
  373.                     if (v >= bmp.palette.Count)
  374.                     {
  375.                         Debug.LogError("Indexed bitmap has indices greater than it's color palette");
  376.                         return;
  377.                     }
  378.                     data[x + y * w] = bmp.palette[v];
  379.                 }
  380.                 bitReader.Flush();
  381.                 for (int i = 0; i < pad; i++)
  382.                     aReader.ReadByte();
  383.             }
  384.         }
  385.         private static void ReadIndexedImageRLE4(BinaryReader aReader, BMPImage bmp)
  386.         {
  387.             int w = Mathf.Abs(bmp.info.width);
  388.             int h = Mathf.Abs(bmp.info.height);
  389.             Color32[] data = bmp.imageData = new Color32[w * h];
  390.             int x = 0;
  391.             int y = 0;
  392.             int yOffset = 0;
  393.             while (aReader.BaseStream.Position < aReader.BaseStream.Length - 1)
  394.             {
  395.                 int count = (int)aReader.ReadByte();
  396.                 byte d = aReader.ReadByte();
  397.                 if (count > 0)
  398.                 {
  399.                     for (int i = (count / 2); i > 0; i--)
  400.                     {
  401.                         data[x++ + yOffset] = bmp.palette[(d >> 4) & 0x0F];
  402.                         data[x++ + yOffset] = bmp.palette[d & 0x0F];
  403.                     }
  404.                     if ((count & 0x01) > 0)
  405.                     {
  406.                         data[x++ + yOffset] = bmp.palette[(d >> 4) & 0x0F];
  407.                     }
  408.                 }
  409.                 else
  410.                 {
  411.                     if (d == 0)
  412.                     {
  413.                         x = 0;
  414.                         y += 1;
  415.                         yOffset = y * w;
  416.                     }
  417.                     else if (d == 1)
  418.                     {
  419.                         break;
  420.                     }
  421.                     else if (d == 2)
  422.                     {
  423.                         x += aReader.ReadByte();
  424.                         y += aReader.ReadByte();
  425.                         yOffset = y * w;
  426.                     }
  427.                     else
  428.                     {
  429.                         for (int i = (d / 2); i > 0; i--)
  430.                         {
  431.                             byte d2 = aReader.ReadByte();
  432.                             data[x++ + yOffset] = bmp.palette[(d2 >> 4) & 0x0F];
  433.                             if (x + 1 < w)
  434.                                 data[x++ + yOffset] = bmp.palette[d2 & 0x0F];
  435.                         }
  436.                         if ((d & 0x01) > 0)
  437.                         {
  438.                             data[x++ + yOffset] = bmp.palette[(aReader.ReadByte() >> 4) & 0x0F];
  439.                         }
  440.                         if ((((d - 1) / 2) & 1) == 0)
  441.                         {
  442.                             aReader.ReadByte(); // padding (word alignment)
  443.                         }
  444.                     }
  445.                 }
  446.             }
  447.         }
  448.         private static void ReadIndexedImageRLE8(BinaryReader aReader, BMPImage bmp)
  449.         {
  450.             int w = Mathf.Abs(bmp.info.width);
  451.             int h = Mathf.Abs(bmp.info.height);
  452.             Color32[] data = bmp.imageData = new Color32[w * h];
  453.             int x = 0;
  454.             int y = 0;
  455.             int yOffset = 0;
  456.             while (aReader.BaseStream.Position < aReader.BaseStream.Length - 1)
  457.             {
  458.                 int count = (int)aReader.ReadByte();
  459.                 byte d = aReader.ReadByte();
  460.                 if (count > 0)
  461.                 {
  462.                     for (int i = count; i > 0; i--)
  463.                     {
  464.                         data[x++ + yOffset] = bmp.palette[d];
  465.                     }
  466.                 }
  467.                 else
  468.                 {
  469.                     if (d == 0)
  470.                     {
  471.                         x = 0;
  472.                         y += 1;
  473.                         yOffset = y * w;
  474.                     }
  475.                     else if (d == 1)
  476.                     {
  477.                         break;
  478.                     }
  479.                     else if (d == 2)
  480.                     {
  481.                         x += aReader.ReadByte();
  482.                         y += aReader.ReadByte();
  483.                         yOffset = y * w;
  484.                     }
  485.                     else
  486.                     {
  487.                         for (int i = d; i > 0; i--)
  488.                         {
  489.                             data[x++ + yOffset] = bmp.palette[aReader.ReadByte()];
  490.                         }
  491.                         if ((d & 0x01) > 0)
  492.                         {
  493.                             aReader.ReadByte(); // padding (word alignment)
  494.                         }
  495.                     }
  496.                 }
  497.             }
  498.         }
  499.         private static int GetShiftCount(uint mask)
  500.         {
  501.             for (int i = 0; i < 32; i++)
  502.             {
  503.                 if ((mask & 0x01) > 0)
  504.                     return i;
  505.                 mask >>= 1;
  506.             }
  507.             return -1;
  508.         }
  509.         private static uint GetMask(int bitCount)
  510.         {
  511.             uint mask = 0;
  512.             for (int i = 0; i < bitCount; i++)
  513.             {
  514.                 mask <<= 1;
  515.                 mask |= 0x01;
  516.             }
  517.             return mask;
  518.         }
  519.         private static bool ReadFileHeader(BinaryReader aReader, ref BMPFileHeader aFileHeader)
  520.         {
  521.             aFileHeader.magic = aReader.ReadUInt16();
  522.             if (aFileHeader.magic != MAGIC)
  523.                 return false;
  524.             aFileHeader.filesize = aReader.ReadUInt32();
  525.             aFileHeader.reserved = aReader.ReadUInt32();
  526.             aFileHeader.offset = aReader.ReadUInt32();
  527.             return true;
  528.         }
  529.         private static bool ReadInfoHeader(BinaryReader aReader, ref BitmapInfoHeader aHeader)
  530.         {
  531.             aHeader.size = aReader.ReadUInt32();
  532.             if (aHeader.size < 40)
  533.                 return false;
  534.             aHeader.width = aReader.ReadInt32();
  535.             aHeader.height = aReader.ReadInt32();
  536.             aHeader.nColorPlanes = aReader.ReadUInt16();
  537.             aHeader.nBitsPerPixel = aReader.ReadUInt16();
  538.             aHeader.compressionMethod = (BMPComressionMode)aReader.ReadInt32();
  539.             aHeader.rawImageSize = aReader.ReadUInt32();
  540.             aHeader.xPPM = aReader.ReadInt32();
  541.             aHeader.yPPM = aReader.ReadInt32();
  542.             aHeader.nPaletteColors = aReader.ReadUInt32();
  543.             aHeader.nImportantColors = aReader.ReadUInt32();
  544.             int pad = (int)aHeader.size - 40;
  545.             if (pad > 0)
  546.                 aReader.ReadBytes(pad);
  547.             return true;
  548.         }
  549.         public static List<Color32> ReadPalette(BinaryReader aReader, BMPImage aBmp, bool aReadAlpha)
  550.         {
  551.             uint count = aBmp.info.nPaletteColors;
  552.             if (count == 0u)
  553.                 count = 1u << aBmp.info.nBitsPerPixel;
  554.             var palette = new List<Color32>((int)count);
  555.             for (int i = 0; i < count; i++)
  556.             {
  557.                 byte b = aReader.ReadByte();
  558.                 byte g = aReader.ReadByte();
  559.                 byte r = aReader.ReadByte();
  560.                 byte a = aReader.ReadByte();
  561.                 if (!aReadAlpha)
  562.                     a = 255;
  563.                 palette.Add(new Color32(r, g, b, a));
  564.             }
  565.             return palette;
  566.         }
  567.  
  568.     }
  569.     public class BitStreamReader
  570.     {
  571.         BinaryReader m_Reader;
  572.         byte m_Data = 0;
  573.         int m_Bits = 0;
  574.  
  575.         public BitStreamReader(BinaryReader aReader)
  576.         {
  577.             m_Reader = aReader;
  578.         }
  579.         public BitStreamReader(Stream aStream) : this(new BinaryReader(aStream)) { }
  580.  
  581.         public byte ReadBit()
  582.         {
  583.             if (m_Bits <= 0)
  584.             {
  585.                 m_Data = m_Reader.ReadByte();
  586.                 m_Bits = 8;
  587.             }
  588.             return (byte)((m_Data >> --m_Bits) & 1);
  589.         }
  590.  
  591.         public ulong ReadBits(int aCount)
  592.         {
  593.             ulong val = 0UL;
  594.             if (aCount <= 0 || aCount > 32)
  595.                 throw new System.ArgumentOutOfRangeException("aCount", "aCount must be between 1 and 32 inclusive");
  596.             for (int i = aCount - 1; i >= 0; i--)
  597.                 val |= ((ulong)ReadBit() << i);
  598.             return val;
  599.         }
  600.         public void Flush()
  601.         {
  602.             m_Data = 0;
  603.             m_Bits = 0;
  604.         }
  605.     }
  606. }
  607.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement