/// <summary> /// Gets the PLTE chunk of the parent image and throws an exception if it is not present. /// </summary> /// <returns>The PLTE chunk of the parent image.</returns> /// <exception cref="ChunkNotFoundException" /> protected PLTEChunk GetAssertPLTEChunk() { PLTEChunk chunk = _image.Chunks["PLTE"] as PLTEChunk; if (chunk == null) { throw new ChunkNotFoundException("PLTE chunk not found."); } return(chunk); }
public Color GetEffectiveBackgroundColor() { IHDRChunk hdr = this.GetAssertIHDRChunk(); switch (hdr.ColorType) { case ColorType.Grayscale: case ColorType.GrayscaleWithAlpha: if (hdr.BitDepth == 1) { return(Utils.MakeGray((_backgroundColor.Gray & 0x1) * 255)); } else if (hdr.BitDepth == 2) { return(Utils.MakeGray((_backgroundColor.Gray & 0x3) * 255 / 3)); } else if (hdr.BitDepth == 4) { return(Utils.MakeGray((_backgroundColor.Gray & 0xf) * 255 / 15)); } else if (hdr.BitDepth == 8) { return(Utils.MakeGray(_backgroundColor.Gray & 0xff)); } else if (hdr.BitDepth == 16) { return(Utils.MakeGray(_backgroundColor.Gray * 255 / 65535)); } else { throw new InvalidChunkDataException("Invalid bit depth."); } case ColorType.Truecolor: case ColorType.TruecolorWithAlpha: if (hdr.BitDepth == 8) { return(Color.FromArgb( _backgroundColor.Red & 0xff, _backgroundColor.Green & 0xff, _backgroundColor.Blue & 0xff)); } else if (hdr.BitDepth == 16) { return(Color.FromArgb( _backgroundColor.Red * 255 / 65535, _backgroundColor.Green * 255 / 65535, _backgroundColor.Blue * 255 / 65535)); } else { throw new InvalidChunkDataException("Invalid bit depth."); } case ColorType.IndexedColor: PLTEChunk plte = this.GetAssertPLTEChunk(); return(plte.Entries[_backgroundColor.Index]); default: throw new InvalidChunkDataException("Invalid color type."); } }
/// <summary> /// Reads the image pixels and stores them in Bitmap. /// </summary> /// <param name="data">The image bytes.</param> private void Read(byte[] data) { // optimized for speed (it's very slow already) IHDRChunk hdr = _image.Chunks["IHDR"] as IHDRChunk; int width = (int)hdr.Width; int height = (int)hdr.Height; byte bitDepth = hdr.BitDepth; _bitmap = CreateBitmap(hdr.ColorType, hdr.BitDepth, width, height); _scanlineLength = Utils.IntCeilDiv(Utils.GetBitsPerPixel(hdr.ColorType, hdr.BitDepth) * width, 8) + 1; _bpp = Utils.GetBytesPerPixel(hdr.ColorType, hdr.BitDepth); // bytes per pixel byte[] decoded = null; // palette PLTEChunk palette = _image.Chunks["PLTE"] as PLTEChunk; #region tRNS Chunk tRNSChunk trns = _image.Chunks["tRNS"] as tRNSChunk; int tGray1 = -1; int tGray2 = -1; int tGray4 = -1; int tGray8 = -1; int tGray16 = -1; Color tRgb8 = Color.FromArgb(0, 0, 0, 0); Color tRgb16 = Color.FromArgb(0, 0, 0, 0); int[] tPalette = null; if (trns != null) { tGray1 = trns.Gray & 0x1; tGray2 = trns.Gray & 0x3; tGray4 = trns.Gray & 0xf; tGray8 = trns.Gray & 0xff; tGray16 = trns.Gray; tRgb8 = Color.FromArgb(trns.Red & 0xff, trns.Green & 0xff, trns.Blue & 0xff); tRgb16 = Color.FromArgb(trns.Red * 255 / 65535, trns.Green * 255 / 65535, trns.Blue * 255 / 65535); if (palette != null) { tPalette = new int[palette.Entries.Length]; for (int i = 0; i < tPalette.Length; i++) { if (i < trns.PaletteAlpha.Length) { tPalette[i] = trns.PaletteAlpha[i]; } else { tPalette[i] = 255; } } } } else { if (palette != null) { tPalette = new int[palette.Entries.Length]; for (int i = 0; i < tPalette.Length; i++) { tPalette[i] = 255; } } } #endregion if (hdr.InterlaceMethod == InterlaceMethod.Adam7) { #region Adam7 for (int pass = 0; pass < _adam7.Length; pass++) { } #endregion } else { #region Normal for (int line = 0; line < data.Length / _scanlineLength; line++) { decoded = this.Defilter(data, line, decoded); switch (hdr.ColorType) { case ColorType.Grayscale: if (bitDepth == 1) { for (int i = 0; i < Utils.IntCeilDiv(width, 8); i++) { int[] pixels = new int[8]; for (int j = 0; j < 8; j++) { pixels[j] = (decoded[i] >> (7 - j)) & 0x1; } for (int j = 0; j < 8; j++) { if (i * 8 + j < hdr.Width) { _bitmap.SetPixel(i * 8 + j, line, Utils.MakeGray(pixels[j] == tGray1 ? 0 : 255, pixels[j] * 255)); } } } } else if (bitDepth == 2) { for (int i = 0; i < Utils.IntCeilDiv(width, 4); i++) { int[] pixels = new int[4]; for (int j = 0; j < 4; j++) { pixels[j] = (decoded[i] >> ((3 - j) * 2)) & 0x3; } for (int j = 0; j < 4; j++) { if (i * 4 + j < hdr.Width) { _bitmap.SetPixel(i * 4 + j, line, Utils.MakeGray(pixels[j] == tGray2 ? 0 : 255, pixels[j] * 255 / 3)); } } } } else if (bitDepth == 4) { for (int i = 0; i < Utils.IntCeilDiv(width, 2); i++) { int pixel1 = decoded[i] >> 4; // upper four bits int pixel2 = decoded[i] & 0xf; // lower two bits _bitmap.SetPixel(i * 2, line, Utils.MakeGray( pixel1 == tGray4 ? 0 : 255, pixel1 * 255 / 15)); if (i * 2 + 1 < hdr.Width) { _bitmap.SetPixel(i * 2 + 1, line, Utils.MakeGray( pixel2 == tGray4 ? 0 : 255, pixel2 * 255 / 15)); } } } else if (bitDepth == 8) { for (int i = 0; i < hdr.Width; i++) { _bitmap.SetPixel(i, line, Utils.MakeGray(decoded[i] == tGray8 ? 0 : 255, decoded[i])); } } else if (bitDepth == 16) { for (int i = 0; i < hdr.Width; i++) { int value = Utils.BytesToUShort(decoded, i * 2, Utils.Endianness.Big); _bitmap.SetPixel(i, line, Utils.MakeGray( value == tGray16 ? 0 : 255, value * 255 / 65535)); } } break; case ColorType.GrayscaleWithAlpha: if (bitDepth == 8) { for (int i = 0; i < hdr.Width; i++) { _bitmap.SetPixel(i, line, Color.FromArgb( decoded[i * 2 + 1], decoded[i * 2], decoded[i * 2], decoded[i * 2] )); } } else if (bitDepth == 16) { for (int i = 0; i < hdr.Width; i++) { _bitmap.SetPixel(i, line, Color.FromArgb( Utils.BytesToUShort(decoded, i * 4 + 2, Utils.Endianness.Big) * 255 / 65535, Utils.BytesToUShort(decoded, i * 4, Utils.Endianness.Big) * 255 / 65535, Utils.BytesToUShort(decoded, i * 4, Utils.Endianness.Big) * 255 / 65535, Utils.BytesToUShort(decoded, i * 4, Utils.Endianness.Big) * 255 / 65535 )); } } break; case ColorType.IndexedColor: if (bitDepth == 1) { for (int i = 0; i < Utils.IntCeilDiv(width, 8); i++) { int[] pixels = new int[8]; for (int j = 0; j < 8; j++) { pixels[j] = (decoded[i] >> (7 - j)) & 0x1; } for (int j = 0; j < 8; j++) { if (i * 8 + j < hdr.Width) { _bitmap.SetPixel(i * 8 + j, line, Color.FromArgb(tPalette[pixels[j]], palette.Entries[pixels[j]])); } } } } else if (bitDepth == 2) { for (int i = 0; i < Utils.IntCeilDiv(width, 4); i++) { int[] pixels = new int[4]; for (int j = 0; j < 4; j++) { pixels[j] = (decoded[i] >> ((3 - j) * 2)) & 0x3; } for (int j = 0; j < 4; j++) { if (i * 4 + j < hdr.Width) { _bitmap.SetPixel(i * 4 + j, line, Color.FromArgb(tPalette[pixels[j]], palette.Entries[pixels[j]])); } } } } else if (bitDepth == 4) { for (int i = 0; i < Utils.IntCeilDiv(width, 2); i++) { int pixel1 = decoded[i] >> 4; // upper four bits int pixel2 = decoded[i] & 0xf; // lower two bits _bitmap.SetPixel(i * 2, line, Color.FromArgb(tPalette[pixel1], palette.Entries[pixel1])); if (i * 2 + 1 < hdr.Width) { _bitmap.SetPixel(i * 2 + 1, line, Color.FromArgb(tPalette[pixel2], palette.Entries[pixel2])); } } } else if (bitDepth == 8) { for (int i = 0; i < hdr.Width; i++) { _bitmap.SetPixel(i, line, Color.FromArgb(tPalette[decoded[i]], palette.Entries[decoded[i]])); } } break; case ColorType.Truecolor: if (bitDepth == 8) { for (int i = 0; i < hdr.Width; i++) { Color c = Color.FromArgb( decoded[i * 3], decoded[i * 3 + 1], decoded[i * 3 + 2] ); _bitmap.SetPixel(i, line, Color.FromArgb( Utils.ColorsEqual(c, tRgb8) ? 0 : 255, c)); } } else if (bitDepth == 16) { // .NET doesn't support 16-bit bit depths for (int i = 0; i < hdr.Width; i++) { Color c = Color.FromArgb( Utils.BytesToUShort(decoded, i * 6, Utils.Endianness.Big) * 255 / 65535, Utils.BytesToUShort(decoded, i * 6 + 2, Utils.Endianness.Big) * 255 / 65535, Utils.BytesToUShort(decoded, i * 6 + 4, Utils.Endianness.Big) * 255 / 65535 ); _bitmap.SetPixel(i, line, Color.FromArgb( Utils.ColorsEqual(c, tRgb16) ? 0 : 255, c)); } } break; case ColorType.TruecolorWithAlpha: if (bitDepth == 8) { for (int i = 0; i < hdr.Width; i++) { _bitmap.SetPixel(i, line, Color.FromArgb( decoded[i * 4 + 3], decoded[i * 4], decoded[i * 4 + 1], decoded[i * 4 + 2])); } } else if (bitDepth == 16) { for (int i = 0; i < hdr.Width; i++) { _bitmap.SetPixel(i, line, Color.FromArgb( Utils.BytesToUShort(decoded, i * 8 + 6, Utils.Endianness.Big) * 255 / 65535, Utils.BytesToUShort(decoded, i * 8, Utils.Endianness.Big) * 255 / 65535, Utils.BytesToUShort(decoded, i * 8 + 2, Utils.Endianness.Big) * 255 / 65535, Utils.BytesToUShort(decoded, i * 8 + 4, Utils.Endianness.Big) * 255 / 65535 )); } } break; default: throw new Exception("Invalid color type."); } } #endregion } }