public unsafe void SetData(ByteColor[] data, Rectangle? rect) { Threading.EnsureUIThread (delegate { fixed(ByteColor *ptr = data) { SetData ((IntPtr)ptr, rect); } }); }
static ByteColor[] GetData(byte[][] scanlines, int width, int height, ColorType colorType, int bitsPerSample, ByteColor[] palette) { var bytesPerPixel = BytesPerPixel(colorType, bitsPerSample); var bytesPerSample = bitsPerSample / 8; var bytesPerScanline = (bytesPerPixel * width) + 1; var data = new ByteColor[width * height]; byte[] previousScanline = new byte[bytesPerScanline]; for (int y = 0; y < height; y++) { var scanline = scanlines[y]; FilterType filterType = (FilterType)scanline[0]; byte[] defilteredScanline; switch (filterType) { case FilterType.None: defilteredScanline = new byte[scanline.Length]; Array.Copy(scanline, defilteredScanline, scanline.Length); break; case FilterType.Sub: defilteredScanline = SubDefilter(scanline, bytesPerPixel); break; case FilterType.Up: defilteredScanline = UpDefilter(scanline, previousScanline); break; case FilterType.Average: defilteredScanline = AverageDefilter(scanline, previousScanline, bytesPerPixel); break; case FilterType.Paeth: defilteredScanline = PaethDefilter(scanline, previousScanline, bytesPerPixel); break; default: throw new Exception("Unknown filter type."); } previousScanline = defilteredScanline; ConvertColors(defilteredScanline, y, width, colorType, bytesPerPixel, bytesPerSample, data, palette); } return(data); }
public static Texture LoadPng(Stream stream) { List<byte> idat = new List<byte> (); byte bitDepth = 0; ColorType colorType = ColorType.Grayscale; ByteColor[] palette = null; int width = 0, height = 0; using (var reader = new BinaryReader (stream)) { if (reader.ReadUInt64 () != PNG_SIGNATURE) { throw new Exception ("Not a PNG file"); } string chunktype = ""; byte[] typeBuf = new byte[4]; while (chunktype != "IEND") { var length = reader.ReadInt32BE (); reader.Read (typeBuf, 0, 4); chunktype = Encoding.ASCII.GetString (typeBuf); switch (chunktype) { case "IHDR": width = reader.ReadInt32BE (); height = reader.ReadInt32BE (); bitDepth = reader.ReadByte (); colorType = (ColorType)reader.ReadByte (); if (reader.ReadByte () != 0) { throw new Exception (); //Compression method } if (reader.ReadByte () != 0) { throw new Exception (); //Filter method } if (reader.ReadByte () != 0) { throw new NotImplementedException (); //Interlacing } break; case "PLTE": if (length % 3 != 0) throw new Exception (); //Invalid Palette int count = length / 3; palette = new ByteColor[length / 3]; for (int i = 0; i < count; i++) { palette [i] = new ByteColor ( reader.ReadByte (), reader.ReadByte (), reader.ReadByte (), 255); } break; case "tRNS": if (colorType == ColorType.Palette) { for (int i = 0; i < length; i++) { palette [i].A = reader.ReadByte (); } } else { throw new NotImplementedException (); //Are the others BigEndian? Investigate } break; case "IDAT": idat.AddRange (reader.ReadBytes (length)); break; default: reader.BaseStream.Seek (length, SeekOrigin.Current); break; } reader.BaseStream.Seek (4, SeekOrigin.Current); //Skip CRC } } byte[] decompressedBytes = null; using (var compressedStream = new MemoryStream (idat.ToArray (), 2, idat.Count - 6)) { //skip zlib header using (var decompressedStream = new MemoryStream ()) { try { using (var deflateStream = new DeflateStream (compressedStream, CompressionMode.Decompress)) { deflateStream.CopyTo (decompressedStream); } decompressedBytes = decompressedStream.ToArray (); } catch (Exception exception) { throw new Exception ("An error occurred during DEFLATE decompression.", exception); } } } var scanlines = GetScanlines (decompressedBytes, bitDepth, colorType, width); var colors = GetData (scanlines, width, height, colorType, bitDepth, palette); var texture = new Texture (width, height); texture.SetData (colors, null); return texture; }
static ByteColor[] GetData(byte[][] scanlines, int width, int height, ColorType colorType, int bitsPerSample, ByteColor[] palette) { var bytesPerPixel = BytesPerPixel(colorType, bitsPerSample); var bytesPerSample = bitsPerSample / 8; var bytesPerScanline = (bytesPerPixel * width) + 1; var data = new ByteColor[width * height]; byte[] previousScanline = new byte[bytesPerScanline]; for (int y = 0; y < height; y++) { var scanline = scanlines[y]; FilterType filterType = (FilterType)scanline[0]; byte[] defilteredScanline; switch (filterType) { case FilterType.None: defilteredScanline = new byte[scanline.Length]; Array.Copy (scanline, defilteredScanline, scanline.Length); break; case FilterType.Sub: defilteredScanline = SubDefilter(scanline, bytesPerPixel); break; case FilterType.Up: defilteredScanline = UpDefilter(scanline, previousScanline); break; case FilterType.Average: defilteredScanline = AverageDefilter(scanline, previousScanline, bytesPerPixel); break; case FilterType.Paeth: defilteredScanline = PaethDefilter(scanline, previousScanline, bytesPerPixel); break; default: throw new Exception("Unknown filter type."); } previousScanline = defilteredScanline; ConvertColors (defilteredScanline, y, width, colorType, bytesPerPixel, bytesPerSample, data, palette); } return data; }
static void ConvertColors(byte[] defilteredScanline, int y, int width, ColorType colorType, int bytesPerPixel, int bytesPerSample, ByteColor[] data, ByteColor[] palette) { switch (colorType) { case ColorType.Grayscale: for (int x = 0; x < width; x++) { int offset = 1 + (x * bytesPerPixel); byte intensity = defilteredScanline[offset]; data[(y * width) + x] = new ByteColor(intensity, intensity, intensity, 255); } break; case ColorType.GrayscaleAlpha: for (int x = 0; x < width; x++) { int offset = 1 + (x * bytesPerPixel); byte intensity = defilteredScanline[offset]; byte alpha = defilteredScanline[offset + bytesPerSample]; data[(y * width) + x] = new ByteColor(intensity, intensity, intensity, alpha); } break; case ColorType.Palette: for (int x = 0; x < width; x++) { var pixelColor = palette[defilteredScanline[x + 1]]; data[(y * width) + x] = pixelColor; } break; case ColorType.Rgb: for (int x = 0; x < width; x++) { int offset = 1 + (x * bytesPerPixel); int red = defilteredScanline[offset]; int green = defilteredScanline[offset + bytesPerSample]; int blue = defilteredScanline[offset + 2 * bytesPerSample]; data[(y * width) + x] = new ByteColor((byte)red, (byte)green, (byte)blue, 255); } break; case ColorType.Rgba: for (int x = 0; x < width; x++) { int offset = 1 + (x * bytesPerPixel); int red = defilteredScanline[offset]; int green = defilteredScanline[offset + bytesPerSample]; int blue = defilteredScanline[offset + 2 * bytesPerSample]; int alpha = defilteredScanline[offset + 3 * bytesPerSample]; data[(y * width) + x] = new ByteColor((byte)red, (byte)green, (byte)blue, (byte)alpha); } break; default: break; } }
unsafe void AddCharacter(uint codepoint) { if (codepoint == (uint)'\t') { var spaceGlyph = GetGlyph((uint)' '); glyphs.Add(codepoint, new GlyphInfo(spaceGlyph.AdvanceX * 4, spaceGlyph.AdvanceY, spaceGlyph.CharIndex, spaceGlyph.Face, spaceGlyph.Kerning)); return; } IntPtr face; uint index; if (!GetFace(codepoint, out index, out face)) { if (codepoint == (uint)'?') { throw new Exception("Font does not have required ASCII characters"); } var qmGlyph = GetGlyph((uint)'?'); glyphs.Add(codepoint, qmGlyph); return; } FT.FT_Load_Glyph(face, index, FT.FT_LOAD_DEFAULT | FT.FT_LOAD_TARGET_NORMAL); var faceRec = Marshal.PtrToStructure <FT.FaceRec> (face); //not exactly the right spot, but this is the only place we access the members of the face bool kerning = (((long)faceRec.face_flags) & FT.FT_FACE_FLAG_KERNING) == FT.FT_FACE_FLAG_KERNING; FT.FT_Render_Glyph(faceRec.glyph, FT.FT_RENDER_MODE_NORMAL); var glyphRec = Marshal.PtrToStructure <FT.GlyphSlotRec> (faceRec.glyph); if (glyphRec.bitmap.width == 0 || glyphRec.bitmap.rows == 0) { glyphs.Add(codepoint, new GlyphInfo( (int)Math.Ceiling(FTMath.From26Dot6(glyphRec.advance.x)), (int)Math.Ceiling(FTMath.From26Dot6(glyphRec.advance.y)), index, face, kerning ) ); } else { var colors = new ByteColor[glyphRec.bitmap.width * glyphRec.bitmap.rows]; if (glyphRec.bitmap.pixel_mode == 2) { byte *data = (byte *)glyphRec.bitmap.buffer; for (int i = 0; i < glyphRec.bitmap.width * glyphRec.bitmap.rows; i++) { //TODO: 4 bytes used for 1 byte of alpha data? investigate compression with GL_RED and shader. colors [i] = new ByteColor(255, 255, 255, data [i]); } } else { throw new NotImplementedException(); } if (currentX + glyphRec.bitmap.width > PAGE_SIZE) { currentX = 0; currentY += lineMax; lineMax = 0; } if (currentY + glyphRec.bitmap.rows > PAGE_SIZE) { currentX = 0; currentY = 0; lineMax = 0; pages.Add(new Texture(PAGE_SIZE, PAGE_SIZE)); //TODO: new font page! should probably log this } lineMax = (int)Math.Max(lineMax, glyphRec.bitmap.rows); var rect = new Rectangle(currentX, currentY, glyphRec.bitmap.width, glyphRec.bitmap.rows); var tex = pages [pages.Count - 1]; tex.SetData(colors, rect); currentX += glyphRec.bitmap.width; glyphs.Add(codepoint, new GlyphInfo( tex, rect, (int)Math.Ceiling(FTMath.From26Dot6(glyphRec.advance.x)), (int)Math.Ceiling(FTMath.From26Dot6(glyphRec.advance.y)), (int)Math.Ceiling(FTMath.From26Dot6(glyphRec.metrics.horiAdvance)), glyphRec.bitmap_left, glyphRec.bitmap_top, index, face, kerning ) ); } }
public static Texture LoadPng(Stream stream) { List <byte> idat = new List <byte> (); byte bitDepth = 0; ColorType colorType = ColorType.Grayscale; ByteColor[] palette = null; int width = 0, height = 0; using (var reader = new BinaryReader(stream)) { if (reader.ReadUInt64() != PNG_SIGNATURE) { throw new Exception("Not a PNG file"); } string chunktype = ""; byte[] typeBuf = new byte[4]; while (chunktype != "IEND") { var length = reader.ReadInt32BE(); reader.Read(typeBuf, 0, 4); chunktype = Encoding.ASCII.GetString(typeBuf); switch (chunktype) { case "IHDR": width = reader.ReadInt32BE(); height = reader.ReadInt32BE(); bitDepth = reader.ReadByte(); colorType = (ColorType)reader.ReadByte(); if (reader.ReadByte() != 0) { throw new Exception(); //Compression method } if (reader.ReadByte() != 0) { throw new Exception(); //Filter method } if (reader.ReadByte() != 0) { throw new NotImplementedException(); //Interlacing } break; case "PLTE": if (length % 3 != 0) { throw new Exception(); //Invalid Palette } int count = length / 3; palette = new ByteColor[length / 3]; for (int i = 0; i < count; i++) { palette [i] = new ByteColor( reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), 255); } break; case "tRNS": if (colorType == ColorType.Palette) { for (int i = 0; i < length; i++) { palette [i].A = reader.ReadByte(); } } else { throw new NotImplementedException(); //Are the others BigEndian? Investigate } break; case "IDAT": idat.AddRange(reader.ReadBytes(length)); break; default: reader.BaseStream.Seek(length, SeekOrigin.Current); break; } reader.BaseStream.Seek(4, SeekOrigin.Current); //Skip CRC } } byte[] decompressedBytes = null; using (var compressedStream = new MemoryStream(idat.ToArray(), 2, idat.Count - 6)) { //skip zlib header using (var decompressedStream = new MemoryStream()) { try { using (var deflateStream = new DeflateStream(compressedStream, CompressionMode.Decompress)) { deflateStream.CopyTo(decompressedStream); } decompressedBytes = decompressedStream.ToArray(); } catch (Exception exception) { throw new Exception("An error occurred during DEFLATE decompression.", exception); } } } var scanlines = GetScanlines(decompressedBytes, bitDepth, colorType, width); var colors = GetData(scanlines, width, height, colorType, bitDepth, palette); var texture = new Texture(width, height); texture.SetData(colors, null); return(texture); }