private void ReadScanlines(MemoryStream dataStream, byte[] pixels, IColorReader colorReader, PngColorTypeInformation colorTypeInformation) { dataStream.Position = 0; int scanlineLength = CalculateScanlineLength(colorTypeInformation); int scanlineStep = CalculateScanlineStep(colorTypeInformation); byte[] lastScanline = new byte[scanlineLength]; byte[] currScanline = new byte[scanlineLength]; byte a = 0; byte b = 0; byte c = 0; int row = 0, filter = 0, column = -1; using (var compressedStream = new ZlibInflateStream(dataStream)) { int readByte = 0; while ((readByte = compressedStream.ReadByte()) >= 0) { if (column == -1) { filter = readByte; column++; } else { currScanline[column] = (byte)readByte; if (column >= scanlineStep) { a = currScanline[column - scanlineStep]; c = lastScanline[column - scanlineStep]; } else { a = 0; c = 0; } b = lastScanline[column]; if (filter == 1) { currScanline[column] = (byte)(currScanline[column] + a); } else if (filter == 2) { currScanline[column] = (byte)(currScanline[column] + b); } else if (filter == 3) { currScanline[column] = (byte)(currScanline[column] + (byte)((a + b) / 2)); } else if (filter == 4) { currScanline[column] = (byte)(currScanline[column] + PaethPredicator(a, b, c)); } column++; if (column == scanlineLength) { colorReader.ReadScanline(currScanline, pixels, _header); column = -1; row++; var tmp = currScanline; currScanline = lastScanline; lastScanline = tmp; } } } } }
private void ReadScanlines(MemoryStream dataStream, byte[] pixels, IColorReader colorReader, PngColorTypeInformation colorTypeInformation) { // Read the zlib header : http://tools.ietf.org/html/rfc1950 // CMF(Compression Method and flags) // This byte is divided into a 4 - bit compression method and a // 4-bit information field depending on the compression method. // bits 0 to 3 CM Compression method // bits 4 to 7 CINFO Compression info // // 0 1 // +---+---+ // |CMF|FLG| // +---+---+ int cmf = dataStream.ReadByte(); int flag = dataStream.ReadByte(); //please note that position=2 int scanlineLength = CalculateScanlineLength(colorTypeInformation); int scanlineStep = CalculateScanlineStep(colorTypeInformation); byte[] lastScanline = new byte[scanlineLength]; byte[] currScanline = new byte[scanlineLength]; byte a = 0; byte b = 0; byte c = 0; int row = 0, filter = 0, column = -1; //using (InflaterInputStream compressedStream = new InflaterInputStream(dataStream)) //{ // int readByte = 0; // while ((readByte = compressedStream.ReadByte()) >= 0) // { // if (column == -1) // { // filter = readByte; // column++; // } // else // { // currScanline[column] = (byte)readByte; // if (column >= scanlineStep) // { // a = currScanline[column - scanlineStep]; // c = lastScanline[column - scanlineStep]; // } // else // { // a = 0; // c = 0; // } // b = lastScanline[column]; // if (filter == 1) // { // currScanline[column] = (byte)(currScanline[column] + a); // } // else if (filter == 2) // { // currScanline[column] = (byte)(currScanline[column] + b); // } // else if (filter == 3) // { // currScanline[column] = (byte)(currScanline[column] + (byte)Math.Floor((double)(a + b) / 2)); // } // else if (filter == 4) // { // currScanline[column] = (byte)(currScanline[column] + PaethPredicator(a, b, c)); // } // column++; // if (column == scanlineLength) // { // colorReader.ReadScanline(currScanline, pixels, _header); // column = -1; // row++; // Extensions.Swap(ref currScanline, ref lastScanline); // } // } // } //} //using (Ionic.Zlib.DeflateStream compressedStream = new Ionic.Zlib.DeflateStream(dataStream, Ionic.Zlib.CompressionMode.Decompress)) using (System.IO.Compression.DeflateStream compressedStream = new System.IO.Compression.DeflateStream( dataStream, System.IO.Compression.CompressionMode.Decompress, true)) { int readByte = 0; //byte[] singleByte = new byte[1]; //compressedStream.Read(singleByte, 0, 1); while ((readByte = compressedStream.ReadByte()) >= 0) { if (column == -1) { filter = readByte; column++; } else { currScanline[column] = (byte)readByte; if (column >= scanlineStep) { a = currScanline[column - scanlineStep]; c = lastScanline[column - scanlineStep]; } else { a = 0; c = 0; } b = lastScanline[column]; if (filter == 1) { currScanline[column] = (byte)(currScanline[column] + a); } else if (filter == 2) { currScanline[column] = (byte)(currScanline[column] + b); } else if (filter == 3) { currScanline[column] = (byte)(currScanline[column] + (byte)Math.Floor((double)(a + b) / 2)); } else if (filter == 4) { currScanline[column] = (byte)(currScanline[column] + PaethPredicator(a, b, c)); } column++; if (column == scanlineLength) { colorReader.ReadScanline(currScanline, pixels, _header); column = -1; row++; // //Extensions.Swap(ref currScanline, ref lastScanline); var tmpA = currScanline; var tmpB = lastScanline; lastScanline = tmpA; currScanline = tmpB; } } } } }
private void ReadScanlines(MemoryStream dataStream, byte[] pixels, IColorReader colorReader, PngColorTypeInformation colorTypeInformation) { dataStream.Position = 0; int scanlineLength = CalculateScanlineLength(colorTypeInformation); int scanlineStep = CalculateScanlineStep(colorTypeInformation); byte[] lastScanline = new byte[scanlineLength]; byte[] currScanline = new byte[scanlineLength]; byte a = 0; byte b = 0; byte c = 0; int row = 0, filter = 0, column = -1; using (InflaterInputStream compressedStream = new InflaterInputStream(dataStream)) { int readByte = 0; while ((readByte = compressedStream.ReadByte()) >= 0) { if (column == -1) { filter = readByte; column++; } else { currScanline[column] = (byte)readByte; if (column >= scanlineStep) { a = currScanline[column - scanlineStep]; c = lastScanline[column - scanlineStep]; } else { a = 0; c = 0; } b = lastScanline[column]; if (filter == 1) { currScanline[column] = (byte)(currScanline[column] + a); } else if (filter == 2) { currScanline[column] = (byte)(currScanline[column] + b); } else if (filter == 3) { currScanline[column] = (byte)(currScanline[column] + (byte)Math.Floor((a + b) / 2d)); } else if (filter == 4) { currScanline[column] = (byte)(currScanline[column] + PaethPredicator(a, b, c)); } column++; if (column == scanlineLength) { colorReader.ReadScanline(currScanline, pixels, _header); column = -1; row++; Extensions.Swap(ref currScanline, ref lastScanline); } } } } }
private static void Parse(byte[] data, PngFileHeader fileHeader, int bytesPerPixel, IColorReader reader, byte[] pixels) { // Find the scan line length. int scanlineLength = GetScanlineLength(fileHeader.Width, fileHeader) + 1; int scanLineCount = data.Length / scanlineLength; // Run through all scanlines. var cannotParallel = new List <int>(); ParallelWork.FastLoops(scanLineCount, (start, end) => { int readOffset = start * scanlineLength; for (int i = start; i < end; i++) { // Early out for invalid data. if (data.Length - readOffset < scanlineLength) { break; } // Get the current scanline. var rowData = new Span <byte>(data, readOffset + 1, scanlineLength - 1); int filter = data[readOffset]; readOffset += scanlineLength; // Check if it has a filter. // PNG filters require the previous row. // We can't do those in parallel. if (filter != 0) { lock (cannotParallel) { cannotParallel.Add(i); } continue; } reader.ReadScanline(rowData, pixels, fileHeader, i); } }).Wait(); if (cannotParallel.Count == 0) { return; } PerfProfiler.ProfilerEventStart("PNG Parse Sequential", "Loading"); // Run scanlines which couldn't be parallel processed. if (scanLineCount >= 2000) { Engine.Log.Trace("Loaded a big PNG with scanlines which require filtering. If you re-export it without that, it will load faster.", MessageSource.ImagePng); } cannotParallel.Sort(); for (var i = 0; i < cannotParallel.Count; i++) { int idx = cannotParallel[i]; int rowStart = idx * scanlineLength; Span <byte> prevRowData = idx == 0 ? null : new Span <byte>(data, (idx - 1) * scanlineLength + 1, scanlineLength - 1); var rowData = new Span <byte>(data, rowStart + 1, scanlineLength - 1); // Apply filter to the whole row. int filter = data[rowStart]; for (var column = 0; column < rowData.Length; column++) { rowData[column] = ApplyFilter(rowData, prevRowData, filter, column, bytesPerPixel); } reader.ReadScanline(rowData, pixels, fileHeader, idx); } PerfProfiler.ProfilerEventEnd("PNG Parse Sequential", "Loading"); }
/// <summary> /// Reads the scanlines. /// </summary> /// <param name="dataStream">The data stream.</param> /// <param name="pixels">The pixels.</param> /// <param name="colorReader">The color reader.</param> /// <param name="colorTypeInformation">The color type information.</param> /// <param name="header">The header.</param> private void ReadScanlines(MemoryStream dataStream, Color[] pixels, IColorReader colorReader, ColorTypeInformation colorTypeInformation, Header header) { dataStream.Seek(0, SeekOrigin.Begin); var ScanlineLength = CalculateScanlineLength(colorTypeInformation, header); var ScanlineStep = CalculateScanlineStep(colorTypeInformation, header); byte[] LastScanline = new byte[ScanlineLength]; byte[] CurrentScanline = new byte[ScanlineLength]; int Filter = 0, Column = -1, Row = 0; using (InflateStream CompressedStream = new InflateStream(dataStream)) { int ReadByte; while ((ReadByte = CompressedStream.ReadByte()) >= 0) { if (Column == -1) { Filter = ReadByte; ++Column; } else { CurrentScanline[Column] = (byte)ReadByte; byte a; byte b; byte c; if (Column >= ScanlineStep) { a = CurrentScanline[Column - ScanlineStep]; c = LastScanline[Column - ScanlineStep]; } else { a = 0; c = 0; } b = LastScanline[Column]; switch (Filter) { case 1: CurrentScanline[Column] = (byte)(CurrentScanline[Column] + a); break; case 2: CurrentScanline[Column] = (byte)(CurrentScanline[Column] + b); break; case 3: CurrentScanline[Column] = (byte)(CurrentScanline[Column] + (byte)((a + b) / 2)); break; case 4: CurrentScanline[Column] = (byte)(CurrentScanline[Column] + PaethPredicator(a, b, c)); break; } ++Column; if (Column == ScanlineLength) { colorReader.ReadScanline(CurrentScanline, pixels, header, Row); ++Row; Column = -1; var Holder = CurrentScanline; CurrentScanline = LastScanline; LastScanline = Holder; } } } } //dataStream.Seek(0, SeekOrigin.Begin); //var ScanlineLength = CalculateScanlineLength(colorTypeInformation, header); //var ScanlineStep = CalculateScanlineStep(colorTypeInformation, header); //byte[] LastScanline = new byte[ScanlineLength]; //byte[] CurrentScanline = new byte[ScanlineLength]; //using (InflateStream CompressedStream = new InflateStream(dataStream)) //{ // using (MemoryStream DecompressedStream = new MemoryStream()) // { // CompressedStream.CopyTo(DecompressedStream); // DecompressedStream.Flush(); // byte[] DecompressedArray = DecompressedStream.ToArray(); // for (int y = 0, Column = 0; y < header.Height; ++y, Column += (ScanlineLength + 1)) // { // Array.Copy(DecompressedArray, Column + 1, CurrentScanline, 0, ScanlineLength); // if (DecompressedArray[Column] < 0) // break; // byte[] Result = Filters[(FilterType)DecompressedArray[Column]].Decode(CurrentScanline, LastScanline, ScanlineStep); // colorReader.ReadScanline(Result, pixels, header, y); // Array.Copy(CurrentScanline, LastScanline, ScanlineLength); // } // } //} }
private void ReadScanlines(MemoryStream dataStream, byte[] pixels, IColorReader colorReader, PngColorTypeInformation colorTypeInformation) { // Read the zlib header : http://tools.ietf.org/html/rfc1950 // CMF(Compression Method and flags) // This byte is divided into a 4 - bit compression method and a // 4-bit information field depending on the compression method. // bits 0 to 3 CM Compression method // bits 4 to 7 CINFO Compression info // // 0 1 // +---+---+ // |CMF|FLG| // +---+---+ int cmf = dataStream.ReadByte(); int flag = dataStream.ReadByte(); //please note that position=2 int scanlineLength = CalculateScanlineLength(colorTypeInformation); int scanlineStep = CalculateScanlineStep(colorTypeInformation); byte[] lastScanline = new byte[scanlineLength]; byte[] currScanline = new byte[scanlineLength]; byte a = 0; byte b = 0; byte c = 0; int row = 0, filter = 0, column = -1; //using (InflaterInputStream compressedStream = new InflaterInputStream(dataStream)) //{ // int readByte = 0; // while ((readByte = compressedStream.ReadByte()) >= 0) // { // if (column == -1) // { // filter = readByte; // column++; // } // else // { // currScanline[column] = (byte)readByte; // if (column >= scanlineStep) // { // a = currScanline[column - scanlineStep]; // c = lastScanline[column - scanlineStep]; // } // else // { // a = 0; // c = 0; // } // b = lastScanline[column]; // if (filter == 1) // { // currScanline[column] = (byte)(currScanline[column] + a); // } // else if (filter == 2) // { // currScanline[column] = (byte)(currScanline[column] + b); // } // else if (filter == 3) // { // currScanline[column] = (byte)(currScanline[column] + (byte)Math.Floor((double)(a + b) / 2)); // } // else if (filter == 4) // { // currScanline[column] = (byte)(currScanline[column] + PaethPredicator(a, b, c)); // } // column++; // if (column == scanlineLength) // { // colorReader.ReadScanline(currScanline, pixels, _header); // column = -1; // row++; // Extensions.Swap(ref currScanline, ref lastScanline); // } // } // } //} using (System.IO.Compression.DeflateStream compressedStream = new System.IO.Compression.DeflateStream( dataStream, System.IO.Compression.CompressionMode.Decompress, true)) //using (Ionic.Zlib.DeflateStream compressedStream = new Ionic.Zlib.DeflateStream(dataStream, Ionic.Zlib.CompressionMode.Decompress)) { int readByte = 0; //byte[] singleByte = new byte[1]; //compressedStream.Read(singleByte, 0, 1); while ((readByte = compressedStream.ReadByte()) >= 0) { if (column == -1) { filter = readByte; column++; } else { currScanline[column] = (byte)readByte; if (column >= scanlineStep) { a = currScanline[column - scanlineStep]; c = lastScanline[column - scanlineStep]; } else { a = 0; c = 0; } b = lastScanline[column]; if (filter == 1) { currScanline[column] = (byte)(currScanline[column] + a); } else if (filter == 2) { currScanline[column] = (byte)(currScanline[column] + b); } else if (filter == 3) { currScanline[column] = (byte)(currScanline[column] + (byte)Math.Floor((double)(a + b) / 2)); } else if (filter == 4) { currScanline[column] = (byte)(currScanline[column] + PaethPredicator(a, b, c)); } column++; if (column == scanlineLength) { colorReader.ReadScanline(currScanline, pixels, _header); column = -1; row++; // //Extensions.Swap(ref currScanline, ref lastScanline); var tmpA = currScanline; var tmpB = lastScanline; lastScanline = tmpA; currScanline = tmpB; } } } } }