// Save a PNG image to the specified stream. public static void Save(Stream stream, PortableImage image) { Frame frame = image.GetFrame(0); byte[] buffer = new byte [1024]; ChunkWriter writer = new ChunkWriter(stream); int colorType, bitDepth; int sigRed, sigGreen, sigBlue, sigAlpha; int paletteSize, posn; int[] palette; ZlibCompressor compressor; ScanlineWriter scanlineWriter; OutputFunc func; int y; // Determine the color type and bit depth for the image. sigRed = -1; sigGreen = -1; sigBlue = -1; sigAlpha = -1; paletteSize = 0; switch (frame.PixelFormat) { case PixelFormat.Format16bppRgb555: { sigRed = 5; sigGreen = 5; sigBlue = 5; colorType = 2; bitDepth = 8; } break; case PixelFormat.Format16bppRgb565: { sigRed = 5; sigGreen = 6; sigBlue = 5; colorType = 2; bitDepth = 8; } break; case PixelFormat.Format24bppRgb: case PixelFormat.Format32bppRgb: { colorType = 2; bitDepth = 8; } break; case PixelFormat.Format1bppIndexed: { colorType = 3; bitDepth = 1; paletteSize = 2; } break; case PixelFormat.Format4bppIndexed: { colorType = 3; bitDepth = 4; paletteSize = 16; } break; case PixelFormat.Format8bppIndexed: { colorType = 3; bitDepth = 8; paletteSize = 256; } break; case PixelFormat.Format16bppArgb1555: { sigRed = 5; sigGreen = 5; sigBlue = 5; sigAlpha = 1; colorType = 6; bitDepth = 8; } break; case PixelFormat.Format32bppPArgb: case PixelFormat.Format32bppArgb: { colorType = 6; bitDepth = 8; } break; case PixelFormat.Format16bppGrayScale: { colorType = 0; bitDepth = 16; } break; case PixelFormat.Format48bppRgb: { colorType = 2; bitDepth = 16; } break; case PixelFormat.Format64bppPArgb: case PixelFormat.Format64bppArgb: { colorType = 6; bitDepth = 16; } break; default: throw new FormatException("unknown format"); } // Write out the PNG magic number. stream.Write(magic, 0, magic.Length); // Write the header chunk. Utils.WriteInt32B(buffer, 0, frame.Width); Utils.WriteInt32B(buffer, 4, frame.Height); buffer[8] = (byte)bitDepth; buffer[9] = (byte)colorType; buffer[10] = (byte)0; // Compression method. buffer[11] = (byte)0; // Filter method. buffer[12] = (byte)0; // Interlace method. writer.Write(PngReader.IHDR, buffer, 0, 13); // Write the significant bits chunk if necessary. if (sigAlpha != -1) { buffer[0] = (byte)sigRed; buffer[1] = (byte)sigGreen; buffer[2] = (byte)sigBlue; buffer[3] = (byte)sigAlpha; writer.Write(PngReader.sBIT, buffer, 0, 4); } else if (sigRed != -1) { buffer[0] = (byte)sigRed; buffer[1] = (byte)sigGreen; buffer[2] = (byte)sigBlue; writer.Write(PngReader.sBIT, buffer, 0, 3); } // Write the palette and transparency chunks. if (paletteSize > 0) { Array.Clear(buffer, 0, buffer.Length); palette = frame.Palette; if (palette != null) { for (posn = 0; posn < palette.Length && posn < paletteSize; ++posn) { buffer[posn * 3] = (byte)(palette[posn] >> 16); buffer[posn * 2 + 1] = (byte)(palette[posn] >> 8); buffer[posn * 2 + 2] = (byte)(palette[posn]); } } writer.Write(PngReader.PLTE, buffer, 0, paletteSize * 3); if (frame.TransparentPixel >= 0 && frame.TransparentPixel < paletteSize) { for (posn = 0; posn < paletteSize; ++posn) { buffer[posn] = (byte)0xFF; } buffer[frame.TransparentPixel] = (byte)0x00; writer.Write(PngReader.tRNS, buffer, 0, frame.TransparentPixel + 1); } } // Compress and write the scanlines to the output stream. compressor = new ZlibCompressor(writer); scanlineWriter = new ScanlineWriter (compressor, frame.Width, frame.PixelFormat); func = GetOutputFunc(frame.PixelFormat); for (y = 0; y < frame.Height; ++y) { func(frame, y, scanlineWriter.Buffer); scanlineWriter.FlushScanline(); } compressor.Finish(); // Write the end chunk. writer.Write(PngReader.IEND, buffer, 0, 0); }
// Save a PNG image to the specified stream. public static void Save(Stream stream, Image image) { Frame frame = image.GetFrame(0); byte[] buffer = new byte [1024]; ChunkWriter writer = new ChunkWriter(stream); int colorType, bitDepth; int sigRed, sigGreen, sigBlue, sigAlpha; int paletteSize, posn; int[] palette; ZlibCompressor compressor; ScanlineWriter scanlineWriter; OutputFunc func; int y; // Determine the color type and bit depth for the image. sigRed = -1; sigGreen = -1; sigBlue = -1; sigAlpha = -1; paletteSize = 0; switch(frame.PixelFormat) { case PixelFormat.Format16bppRgb555: { sigRed = 5; sigGreen = 5; sigBlue = 5; colorType = 2; bitDepth = 8; } break; case PixelFormat.Format16bppRgb565: { sigRed = 5; sigGreen = 6; sigBlue = 5; colorType = 2; bitDepth = 8; } break; case PixelFormat.Format24bppRgb: case PixelFormat.Format32bppRgb: { colorType = 2; bitDepth = 8; } break; case PixelFormat.Format1bppIndexed: { colorType = 3; bitDepth = 1; paletteSize = 2; } break; case PixelFormat.Format4bppIndexed: { colorType = 3; bitDepth = 4; paletteSize = 16; } break; case PixelFormat.Format8bppIndexed: { colorType = 3; bitDepth = 8; paletteSize = 256; } break; case PixelFormat.Format16bppArgb1555: { sigRed = 5; sigGreen = 5; sigBlue = 5; sigAlpha = 1; colorType = 6; bitDepth = 8; } break; case PixelFormat.Format32bppPArgb: case PixelFormat.Format32bppArgb: { colorType = 6; bitDepth = 8; } break; case PixelFormat.Format16bppGrayScale: { colorType = 0; bitDepth = 16; } break; case PixelFormat.Format48bppRgb: { colorType = 2; bitDepth = 16; } break; case PixelFormat.Format64bppPArgb: case PixelFormat.Format64bppArgb: { colorType = 6; bitDepth = 16; } break; default: throw new FormatException("unknown format"); } // Write out the PNG magic number. stream.Write(magic, 0, magic.Length); // Write the header chunk. Utils.WriteInt32B(buffer, 0, frame.Width); Utils.WriteInt32B(buffer, 4, frame.Height); buffer[8] = (byte)bitDepth; buffer[9] = (byte)colorType; buffer[10] = (byte)0; // Compression method. buffer[11] = (byte)0; // Filter method. buffer[12] = (byte)0; // Interlace method. writer.Write(PngReader.IHDR, buffer, 0, 13); // Write the significant bits chunk if necessary. if(sigAlpha != -1) { buffer[0] = (byte)sigRed; buffer[1] = (byte)sigGreen; buffer[2] = (byte)sigBlue; buffer[3] = (byte)sigAlpha; writer.Write(PngReader.sBIT, buffer, 0, 4); } else if(sigRed != -1) { buffer[0] = (byte)sigRed; buffer[1] = (byte)sigGreen; buffer[2] = (byte)sigBlue; writer.Write(PngReader.sBIT, buffer, 0, 3); } // Write the palette and transparency chunks. if(paletteSize > 0) { Array.Clear(buffer, 0, buffer.Length); palette = frame.Palette; if(palette != null) { for(posn = 0; posn < palette.Length && posn < paletteSize; ++posn) { buffer[posn * 3] = (byte)(palette[posn] >> 16); buffer[posn * 2 + 1] = (byte)(palette[posn] >> 8); buffer[posn * 2 + 2] = (byte)(palette[posn]); } } writer.Write(PngReader.PLTE, buffer, 0, paletteSize * 3); if(frame.TransparentPixel >= 0 && frame.TransparentPixel < paletteSize) { for(posn = 0; posn < paletteSize; ++posn) { buffer[posn] = (byte)0xFF; } buffer[frame.TransparentPixel] = (byte)0x00; writer.Write(PngReader.tRNS, buffer, 0, frame.TransparentPixel + 1); } } // Compress and write the scanlines to the output stream. compressor = new ZlibCompressor(writer); scanlineWriter = new ScanlineWriter (compressor, frame.Width, frame.PixelFormat); func = GetOutputFunc(frame.PixelFormat); for(y = 0; y < frame.Height; ++y) { func(frame, y, scanlineWriter.Buffer); scanlineWriter.FlushScanline(); } compressor.Finish(); // Write the end chunk. writer.Write(PngReader.IEND, buffer, 0, 0); }