using System; using System.Collections.Generic; using System.IO; using Hjg.Pngcs.Chunks; using Hjg.Pngcs.Zlib; namespace Hjg.Pngcs { // Token: 0x0200003F RID: 63 public class PngWriter { // Token: 0x17000037 RID: 55 // (get) Token: 0x06000248 RID: 584 RVA: 0x000097B0 File Offset: 0x000079B0 // (set) Token: 0x06000249 RID: 585 RVA: 0x000097B8 File Offset: 0x000079B8 public EDeflateCompressStrategy CompressionStrategy { get; set; } // Token: 0x17000038 RID: 56 // (get) Token: 0x0600024A RID: 586 RVA: 0x000097C1 File Offset: 0x000079C1 // (set) Token: 0x0600024B RID: 587 RVA: 0x000097C9 File Offset: 0x000079C9 public int CompLevel { get; set; } // Token: 0x17000039 RID: 57 // (get) Token: 0x0600024C RID: 588 RVA: 0x000097D2 File Offset: 0x000079D2 // (set) Token: 0x0600024D RID: 589 RVA: 0x000097DA File Offset: 0x000079DA public bool ShouldCloseStream { get; set; } // Token: 0x1700003A RID: 58 // (get) Token: 0x0600024E RID: 590 RVA: 0x000097E3 File Offset: 0x000079E3 // (set) Token: 0x0600024F RID: 591 RVA: 0x000097EB File Offset: 0x000079EB public int IdatMaxSize { get; set; } // Token: 0x1700003B RID: 59 // (get) Token: 0x06000250 RID: 592 RVA: 0x000097F4 File Offset: 0x000079F4 // (set) Token: 0x06000251 RID: 593 RVA: 0x000097FC File Offset: 0x000079FC public int CurrentChunkGroup { get; private set; } // Token: 0x06000252 RID: 594 RVA: 0x00009805 File Offset: 0x00007A05 public PngWriter(Stream outputStream, ImageInfo imgInfo) : this(outputStream, imgInfo, "[NO FILENAME AVAILABLE]") { } // Token: 0x06000253 RID: 595 RVA: 0x00009814 File Offset: 0x00007A14 public PngWriter(Stream outputStream, ImageInfo imgInfo, string filename) { this.filename = ((filename == null) ? "" : filename); this.outputStream = outputStream; this.ImgInfo = imgInfo; this.CompLevel = 6; this.ShouldCloseStream = true; this.IdatMaxSize = 0; this.CompressionStrategy = EDeflateCompressStrategy.Filtered; this.rowb = new byte[imgInfo.BytesPerRow + 1]; this.rowbprev = new byte[this.rowb.Length]; this.rowbfilter = new byte[this.rowb.Length]; this.chunksList = new ChunksListForWrite(this.ImgInfo); this.metadata = new PngMetadata(this.chunksList); this.filterStrat = new FilterWriteStrategy(this.ImgInfo, FilterType.FILTER_DEFAULT); this.unpackedMode = false; this.needsPack = this.unpackedMode && imgInfo.Packed; } // Token: 0x06000254 RID: 596 RVA: 0x00009904 File Offset: 0x00007B04 private void init() { this.datStream = new PngIDatChunkOutputStream(this.outputStream, this.IdatMaxSize); this.datStreamDeflated = ZlibStreamFactory.createZlibOutputStream(this.datStream, this.CompLevel, this.CompressionStrategy, true); this.WriteSignatureAndIHDR(); this.WriteFirstChunks(); } // Token: 0x06000255 RID: 597 RVA: 0x00009954 File Offset: 0x00007B54 private void reportResultsForFilter(int rown, FilterType type, bool tentative) { for (int i = 0; i < this.histox.Length; i++) { this.histox[i] = 0; } int num = 0; for (int j = 1; j <= this.ImgInfo.BytesPerRow; j++) { int num2 = (int)this.rowbfilter[j]; if (num2 < 0) { num -= num2; } else { num += num2; } this.histox[num2 & 255]++; } this.filterStrat.fillResultsForFilter(rown, type, (double)num, this.histox, tentative); } // Token: 0x06000256 RID: 598 RVA: 0x000099E4 File Offset: 0x00007BE4 private void WriteEndChunk() { PngChunkIEND pngChunkIEND = new PngChunkIEND(this.ImgInfo); pngChunkIEND.CreateRawChunk().WriteChunk(this.outputStream); } // Token: 0x06000257 RID: 599 RVA: 0x00009A10 File Offset: 0x00007C10 private void WriteFirstChunks() { this.CurrentChunkGroup = 1; int num = this.chunksList.writeChunks(this.outputStream, this.CurrentChunkGroup); this.CurrentChunkGroup = 2; num = this.chunksList.writeChunks(this.outputStream, this.CurrentChunkGroup); if (num > 0 && this.ImgInfo.Greyscale) { throw new PngjOutputException("cannot write palette for this format"); } if (num == 0 && this.ImgInfo.Indexed) { throw new PngjOutputException("missing palette"); } this.CurrentChunkGroup = 3; num = this.chunksList.writeChunks(this.outputStream, this.CurrentChunkGroup); this.CurrentChunkGroup = 4; } // Token: 0x06000258 RID: 600 RVA: 0x00009ABC File Offset: 0x00007CBC private void WriteLastChunks() { this.CurrentChunkGroup = 5; this.chunksList.writeChunks(this.outputStream, this.CurrentChunkGroup); List queuedChunks = this.chunksList.GetQueuedChunks(); if (queuedChunks.Count > 0) { throw new PngjOutputException(queuedChunks.Count + " chunks were not written! Eg: " + queuedChunks[0].ToString()); } this.CurrentChunkGroup = 6; } // Token: 0x06000259 RID: 601 RVA: 0x00009B2C File Offset: 0x00007D2C private void WriteSignatureAndIHDR() { this.CurrentChunkGroup = 0; PngHelperInternal.WriteBytes(this.outputStream, PngHelperInternal.PNG_ID_SIGNATURE); PngChunkIHDR pngChunkIHDR = new PngChunkIHDR(this.ImgInfo); pngChunkIHDR.Cols = this.ImgInfo.Cols; pngChunkIHDR.Rows = this.ImgInfo.Rows; pngChunkIHDR.Bitspc = this.ImgInfo.BitDepth; int num = 0; if (this.ImgInfo.Alpha) { num += 4; } if (this.ImgInfo.Indexed) { num++; } if (!this.ImgInfo.Greyscale) { num += 2; } pngChunkIHDR.Colormodel = num; pngChunkIHDR.Compmeth = 0; pngChunkIHDR.Filmeth = 0; pngChunkIHDR.Interlaced = 0; pngChunkIHDR.CreateRawChunk().WriteChunk(this.outputStream); } // Token: 0x0600025A RID: 602 RVA: 0x00009BF4 File Offset: 0x00007DF4 protected void encodeRowFromByte(byte[] row) { if (row.Length == this.ImgInfo.SamplesPerRowPacked && !this.needsPack) { int num = 1; if (this.ImgInfo.BitDepth <= 8) { foreach (byte b in row) { this.rowb[num++] = b; } return; } foreach (byte b2 in row) { this.rowb[num] = b2; num += 2; } return; } else { if (row.Length >= this.ImgInfo.SamplesPerRow && this.needsPack) { ImageLine.packInplaceByte(this.ImgInfo, row, row, false); } if (this.ImgInfo.BitDepth <= 8) { int k = 0; int num2 = 1; while (k < this.ImgInfo.SamplesPerRowPacked) { this.rowb[num2++] = row[k]; k++; } return; } int l = 0; int num3 = 1; while (l < this.ImgInfo.SamplesPerRowPacked) { this.rowb[num3++] = row[l]; this.rowb[num3++] = 0; l++; } return; } } // Token: 0x0600025B RID: 603 RVA: 0x00009D1C File Offset: 0x00007F1C protected void encodeRowFromInt(int[] row) { if (row.Length == this.ImgInfo.SamplesPerRowPacked && !this.needsPack) { int num = 1; if (this.ImgInfo.BitDepth <= 8) { foreach (int num2 in row) { this.rowb[num++] = (byte)num2; } return; } foreach (int num3 in row) { this.rowb[num++] = (byte)(num3 >> 8); this.rowb[num++] = (byte)num3; } return; } else { if (row.Length >= this.ImgInfo.SamplesPerRow && this.needsPack) { ImageLine.packInplaceInt(this.ImgInfo, row, row, false); } if (this.ImgInfo.BitDepth <= 8) { int k = 0; int num4 = 1; while (k < this.ImgInfo.SamplesPerRowPacked) { this.rowb[num4++] = (byte)row[k]; k++; } return; } int l = 0; int num5 = 1; while (l < this.ImgInfo.SamplesPerRowPacked) { this.rowb[num5++] = (byte)(row[l] >> 8); this.rowb[num5++] = (byte)row[l]; l++; } return; } } // Token: 0x0600025C RID: 604 RVA: 0x00009E5C File Offset: 0x0000805C private void FilterRow(int rown) { if (this.filterStrat.shouldTestAll(rown)) { this.FilterRowNone(); this.reportResultsForFilter(rown, FilterType.FILTER_NONE, true); this.FilterRowSub(); this.reportResultsForFilter(rown, FilterType.FILTER_SUB, true); this.FilterRowUp(); this.reportResultsForFilter(rown, FilterType.FILTER_UP, true); this.FilterRowAverage(); this.reportResultsForFilter(rown, FilterType.FILTER_AVERAGE, true); this.FilterRowPaeth(); this.reportResultsForFilter(rown, FilterType.FILTER_PAETH, true); } FilterType filterType = this.filterStrat.gimmeFilterType(rown, true); this.rowbfilter[0] = (byte)filterType; switch (filterType) { case FilterType.FILTER_NONE: this.FilterRowNone(); break; case FilterType.FILTER_SUB: this.FilterRowSub(); break; case FilterType.FILTER_UP: this.FilterRowUp(); break; case FilterType.FILTER_AVERAGE: this.FilterRowAverage(); break; case FilterType.FILTER_PAETH: this.FilterRowPaeth(); break; default: throw new PngjOutputException("Filter type " + filterType + " not implemented"); } this.reportResultsForFilter(rown, filterType, false); } // Token: 0x0600025D RID: 605 RVA: 0x00009F44 File Offset: 0x00008144 private void prepareEncodeRow(int rown) { if (this.datStream == null) { this.init(); } this.rowNum++; if (rown >= 0 && this.rowNum != rown) { throw new PngjOutputException(string.Concat(new object[] { "rows must be written in order: expected:", this.rowNum, " passed:", rown })); } byte[] array = this.rowb; this.rowb = this.rowbprev; this.rowbprev = array; } // Token: 0x0600025E RID: 606 RVA: 0x00009FCE File Offset: 0x000081CE private void filterAndSend(int rown) { this.FilterRow(rown); this.datStreamDeflated.Write(this.rowbfilter, 0, this.ImgInfo.BytesPerRow + 1); } // Token: 0x0600025F RID: 607 RVA: 0x00009FF8 File Offset: 0x000081F8 private void FilterRowAverage() { int bytesPerRow = this.ImgInfo.BytesPerRow; int num = 1 - this.ImgInfo.BytesPixel; int i = 1; while (i <= bytesPerRow) { this.rowbfilter[i] = this.rowb[i] - (this.rowbprev[i] + ((num > 0) ? this.rowb[num] : 0)) / 2; i++; num++; } } // Token: 0x06000260 RID: 608 RVA: 0x0000A05C File Offset: 0x0000825C private void FilterRowNone() { for (int i = 1; i <= this.ImgInfo.BytesPerRow; i++) { this.rowbfilter[i] = this.rowb[i]; } } // Token: 0x06000261 RID: 609 RVA: 0x0000A090 File Offset: 0x00008290 private void FilterRowPaeth() { int bytesPerRow = this.ImgInfo.BytesPerRow; int num = 1 - this.ImgInfo.BytesPixel; int i = 1; while (i <= bytesPerRow) { this.rowbfilter[i] = (byte)((int)this.rowb[i] - PngHelperInternal.FilterPaethPredictor((int)((num > 0) ? this.rowb[num] : 0), (int)this.rowbprev[i], (int)((num > 0) ? this.rowbprev[num] : 0))); i++; num++; } } // Token: 0x06000262 RID: 610 RVA: 0x0000A104 File Offset: 0x00008304 private void FilterRowSub() { int i; for (i = 1; i <= this.ImgInfo.BytesPixel; i++) { this.rowbfilter[i] = this.rowb[i]; } int num = 1; i = this.ImgInfo.BytesPixel + 1; while (i <= this.ImgInfo.BytesPerRow) { this.rowbfilter[i] = this.rowb[i] - this.rowb[num]; i++; num++; } } // Token: 0x06000263 RID: 611 RVA: 0x0000A17C File Offset: 0x0000837C private void FilterRowUp() { for (int i = 1; i <= this.ImgInfo.BytesPerRow; i++) { this.rowbfilter[i] = this.rowb[i] - this.rowbprev[i]; } } // Token: 0x06000264 RID: 612 RVA: 0x0000A1BC File Offset: 0x000083BC private long SumRowbfilter() { long num = 0L; for (int i = 1; i <= this.ImgInfo.BytesPerRow; i++) { if (this.rowbfilter[i] < 0) { num -= (long)((ulong)this.rowbfilter[i]); } else { num += (long)((ulong)this.rowbfilter[i]); } } return num; } // Token: 0x06000265 RID: 613 RVA: 0x0000A208 File Offset: 0x00008408 private void CopyChunks(PngReader reader, int copy_mask, bool onlyAfterIdat) { bool flag = this.CurrentChunkGroup >= 4; if (onlyAfterIdat && reader.CurrentChunkGroup < 6) { throw new PngjException("tried to copy last chunks but reader has not ended"); } foreach (PngChunk pngChunk in reader.GetChunksList().GetChunks()) { int chunkGroup = pngChunk.ChunkGroup; if (chunkGroup >= 4 || !flag) { bool flag2 = false; if (pngChunk.Crit) { if (pngChunk.Id.Equals("PLTE")) { if (this.ImgInfo.Indexed && ChunkHelper.maskMatch(copy_mask, ChunkCopyBehaviour.COPY_PALETTE)) { flag2 = true; } if (!this.ImgInfo.Greyscale && ChunkHelper.maskMatch(copy_mask, ChunkCopyBehaviour.COPY_ALL)) { flag2 = true; } } } else { bool flag3 = pngChunk is PngChunkTextVar; bool safe = pngChunk.Safe; if (ChunkHelper.maskMatch(copy_mask, ChunkCopyBehaviour.COPY_ALL)) { flag2 = true; } if (safe && ChunkHelper.maskMatch(copy_mask, ChunkCopyBehaviour.COPY_ALL_SAFE)) { flag2 = true; } if (pngChunk.Id.Equals("tRNS") && ChunkHelper.maskMatch(copy_mask, ChunkCopyBehaviour.COPY_TRANSPARENCY)) { flag2 = true; } if (pngChunk.Id.Equals("pHYs") && ChunkHelper.maskMatch(copy_mask, ChunkCopyBehaviour.COPY_PHYS)) { flag2 = true; } if (flag3 && ChunkHelper.maskMatch(copy_mask, ChunkCopyBehaviour.COPY_TEXTUAL)) { flag2 = true; } if (ChunkHelper.maskMatch(copy_mask, ChunkCopyBehaviour.COPY_ALMOSTALL) && !ChunkHelper.IsUnknown(pngChunk) && !flag3 && !pngChunk.Id.Equals("hIST") && !pngChunk.Id.Equals("tIME")) { flag2 = true; } if (pngChunk is PngChunkSkipped) { flag2 = false; } } if (flag2) { this.chunksList.Queue(PngChunk.CloneChunk(pngChunk, this.ImgInfo)); } } } } // Token: 0x06000266 RID: 614 RVA: 0x0000A3F4 File Offset: 0x000085F4 public void CopyChunksFirst(PngReader reader, int copy_mask) { this.CopyChunks(reader, copy_mask, false); } // Token: 0x06000267 RID: 615 RVA: 0x0000A3FF File Offset: 0x000085FF public void CopyChunksLast(PngReader reader, int copy_mask) { this.CopyChunks(reader, copy_mask, true); } // Token: 0x06000268 RID: 616 RVA: 0x0000A40C File Offset: 0x0000860C public double ComputeCompressionRatio() { if (this.CurrentChunkGroup < 6) { throw new PngjException("must be called after End()"); } double num = (double)this.datStream.GetCountFlushed(); double num2 = (double)((this.ImgInfo.BytesPerRow + 1) * this.ImgInfo.Rows); return num / num2; } // Token: 0x06000269 RID: 617 RVA: 0x0000A458 File Offset: 0x00008658 public void End() { if (this.rowNum != this.ImgInfo.Rows - 1) { throw new PngjOutputException("all rows have not been written"); } try { this.datStreamDeflated.Close(); this.datStream.Close(); this.WriteLastChunks(); this.WriteEndChunk(); if (this.ShouldCloseStream) { this.outputStream.Close(); } } catch (IOException ex) { throw new PngjOutputException(ex); } } // Token: 0x0600026A RID: 618 RVA: 0x0000A4D4 File Offset: 0x000086D4 public string GetFilename() { return this.filename; } // Token: 0x0600026B RID: 619 RVA: 0x0000A4DC File Offset: 0x000086DC public void WriteRow(ImageLine imgline, int rownumber) { this.SetUseUnPackedMode(imgline.SamplesUnpacked); if (imgline.SampleType == ImageLine.ESampleType.INT) { this.WriteRowInt(imgline.Scanline, rownumber); return; } this.WriteRowByte(imgline.ScanlineB, rownumber); } // Token: 0x0600026C RID: 620 RVA: 0x0000A50D File Offset: 0x0000870D public void WriteRow(int[] newrow) { this.WriteRow(newrow, -1); } // Token: 0x0600026D RID: 621 RVA: 0x0000A517 File Offset: 0x00008717 public void WriteRow(int[] newrow, int rown) { this.WriteRowInt(newrow, rown); } // Token: 0x0600026E RID: 622 RVA: 0x0000A521 File Offset: 0x00008721 public void WriteRowInt(int[] newrow, int rown) { this.prepareEncodeRow(rown); this.encodeRowFromInt(newrow); this.filterAndSend(rown); } // Token: 0x0600026F RID: 623 RVA: 0x0000A538 File Offset: 0x00008738 public void WriteRowByte(byte[] newrow, int rown) { this.prepareEncodeRow(rown); this.encodeRowFromByte(newrow); this.filterAndSend(rown); } // Token: 0x06000270 RID: 624 RVA: 0x0000A550 File Offset: 0x00008750 public void WriteRowsInt(int[][] image) { for (int i = 0; i < this.ImgInfo.Rows; i++) { this.WriteRowInt(image[i], i); } } // Token: 0x06000271 RID: 625 RVA: 0x0000A580 File Offset: 0x00008780 public void WriteRowsByte(byte[][] image) { for (int i = 0; i < this.ImgInfo.Rows; i++) { this.WriteRowByte(image[i], i); } } // Token: 0x06000272 RID: 626 RVA: 0x0000A5AD File Offset: 0x000087AD public PngMetadata GetMetadata() { return this.metadata; } // Token: 0x06000273 RID: 627 RVA: 0x0000A5B5 File Offset: 0x000087B5 public ChunksListForWrite GetChunksList() { return this.chunksList; } // Token: 0x06000274 RID: 628 RVA: 0x0000A5BD File Offset: 0x000087BD public void SetFilterType(FilterType filterType) { this.filterStrat = new FilterWriteStrategy(this.ImgInfo, filterType); } // Token: 0x06000275 RID: 629 RVA: 0x0000A5D1 File Offset: 0x000087D1 public bool IsUnpackedMode() { return this.unpackedMode; } // Token: 0x06000276 RID: 630 RVA: 0x0000A5D9 File Offset: 0x000087D9 public void SetUseUnPackedMode(bool useUnpackedMode) { this.unpackedMode = useUnpackedMode; this.needsPack = this.unpackedMode && this.ImgInfo.Packed; } // Token: 0x04000133 RID: 307 public readonly ImageInfo ImgInfo; // Token: 0x04000134 RID: 308 protected readonly string filename; // Token: 0x04000135 RID: 309 private FilterWriteStrategy filterStrat; // Token: 0x04000136 RID: 310 private readonly PngMetadata metadata; // Token: 0x04000137 RID: 311 private readonly ChunksListForWrite chunksList; // Token: 0x04000138 RID: 312 protected byte[] rowb; // Token: 0x04000139 RID: 313 protected byte[] rowbprev; // Token: 0x0400013A RID: 314 protected byte[] rowbfilter; // Token: 0x0400013B RID: 315 private int rowNum = -1; // Token: 0x0400013C RID: 316 private readonly Stream outputStream; // Token: 0x0400013D RID: 317 private PngIDatChunkOutputStream datStream; // Token: 0x0400013E RID: 318 private AZlibOutputStream datStreamDeflated; // Token: 0x0400013F RID: 319 private int[] histox = new int[256]; // Token: 0x04000140 RID: 320 private bool unpackedMode; // Token: 0x04000141 RID: 321 private bool needsPack; } }