internal ImageLine( ImageInfo imgInfo, ESampleType stype, bool unpackedMode, int [] sci, byte [] scb ) { this.ImgInfo = imgInfo; channels = imgInfo.Channels; this.bitDepth = imgInfo.BitDepth; this.FilterUsed = FilterType.FILTER_UNKNOWN; this.SampleType = stype; this.SamplesUnpacked = unpackedMode || !imgInfo.Packed; ElementsPerRow = this.SamplesUnpacked ? imgInfo.SamplesPerRow : imgInfo.SamplesPerRowPacked; if ( stype == ESampleType.INT ) { Scanline = sci != null ? sci : new int [ ElementsPerRow ]; ScanlineB = null; maxSampleVal = bitDepth == 16 ? 0xFFFF : GetMaskForPackedFormatsLs ( bitDepth ); } else if ( stype == ESampleType.BYTE ) { ScanlineB = scb != null ? scb : new byte [ ElementsPerRow ]; Scanline = null; maxSampleVal = bitDepth == 16 ? 0xFF : GetMaskForPackedFormatsLs ( bitDepth ); } else throw new PngjExceptionInternal ( "bad ImageLine initialization" ); this.Rown = -1; }
/// <summary> /// Encodes a raw file buffer of image data into a PNG image. /// </summary> /// <param name="outputStream">Png bytes.</param> public ImageLines Translate(ImageData image, IProgress prog = null) { if (image is null) { throw new ArgumentNullException(nameof(image)); } var imageInfo = new Hjg.Pngcs.ImageInfo( image.Info.Dimensions.Width, image.Info.Dimensions.Height, image.Info.BitsPerSample / image.Info.Components, image.Info.Components == 4); var imageLines = new ImageLines( imageInfo, ImageLine.ESampleType.BYTE, true, 0, image.Info.Dimensions.Height, image.Info.Stride); for (var y = 0; y < image.Info.Dimensions.Height; ++y) { prog.Report(y, image.Info.Dimensions.Height); var dataIndex = y * image.Info.Stride; var line = imageLines.ScanlinesB[y]; Array.Copy(image.GetData(), dataIndex, line, 0, image.Info.Stride); prog.Report(y + 1, image.Info.Dimensions.Height); } return(imageLines); }
public static ImageLine generateNoiseLine(ImageInfo imi) { // byte format! ImageLine line = new ImageLine(imi, ImageLine.ESampleType.BYTE, true); Random r = new Random(); r.NextBytes(line.ScanlineB); return line; }
public static byte[] Pack( ImageInfo imgInfo, byte [] src, byte [] dst, bool scale ) { int len0 = imgInfo.SamplesPerRowPacked; if ( dst == null || dst.Length < len0 ) dst = new byte [ len0 ]; if ( imgInfo.Packed ) ImageLine.packInplaceByte ( imgInfo, src, dst, scale ); else Array.Copy ( src, 0, dst, 0, len0 ); return dst; }
private static void mirrorLineInt(ImageInfo imgInfo, int[] line) { // unpacked line int channels = imgInfo.Channels; for (int c1 = 0, c2 = imgInfo.Cols - 1; c1 < c2; c1++, c2--) { // swap pixels (not samples!) for (int i = 0; i < channels; i++) { int aux = line[c1 * channels + i]; line[c1 * channels + i] = line[c2 * channels + i]; line[c2 * channels + i] = aux; } } }
public PngReader( Stream inputStream, String filename ) { this.filename = ( filename == null ) ? "" : filename; this.inputStream = inputStream; this.chunksList = new ChunksList ( null ); this.metadata = new PngMetadata ( chunksList ); this.offset = 0; this.CurrentChunkGroup = -1; this.ShouldCloseStream = true; this.MaxBytesMetadata = 5 * 1024 * 1024; this.MaxTotalBytesRead = 200 * 1024 * 1024; this.SkipChunkMaxSize = 2 * 1024 * 1024; this.SkipChunkIds = new string [] { "fdAT" }; this.ChunkLoadBehaviour = Hjg.Pngcs.Chunks.ChunkLoadBehaviour.LOAD_CHUNK_ALWAYS; byte [] pngid = new byte [ 8 ]; PngHelperInternal.ReadBytes ( inputStream, pngid, 0, pngid.Length ); offset += pngid.Length; if ( !PngCsUtils.arraysEqual ( pngid, PngHelperInternal.PNG_ID_SIGNATURE ) ) throw new PngjInputException ( "Bad PNG signature" ); CurrentChunkGroup = ChunksList.CHUNK_GROUP_0_IDHR; int clen = PngHelperInternal.ReadInt4 ( inputStream ); offset += 4; if ( clen != 13 ) throw new Exception ( "IDHR chunk len != 13 ?? " + clen ); byte [] chunkid = new byte [ 4 ]; PngHelperInternal.ReadBytes ( inputStream, chunkid, 0, 4 ); if ( !PngCsUtils.arraysEqual4 ( chunkid, ChunkHelper.b_IHDR ) ) throw new PngjInputException ( "IHDR not found as first chunk??? [" + ChunkHelper.ToString ( chunkid ) + "]" ); offset += 4; PngChunkIHDR ihdr = ( PngChunkIHDR ) ReadChunk ( chunkid, clen, false ); bool alpha = ( ihdr.Colormodel & 0x04 ) != 0; bool palette = ( ihdr.Colormodel & 0x01 ) != 0; bool grayscale = ( ihdr.Colormodel == 0 || ihdr.Colormodel == 4 ); ImgInfo = new ImageInfo ( ihdr.Cols, ihdr.Rows, ihdr.Bitspc, alpha, grayscale, palette ); rowb = new byte [ ImgInfo.BytesPerRow + 1 ]; rowbprev = new byte [ rowb.Length ]; rowbfilter = new byte [ rowb.Length ]; interlaced = ihdr.Interlaced == 1; deinterlacer = interlaced ? new PngDeinterlacer ( ImgInfo ) : null; if ( ihdr.Filmeth != 0 || ihdr.Compmeth != 0 || ( ihdr.Interlaced & 0xFFFE ) != 0 ) throw new PngjInputException ( "compmethod or filtermethod or interlaced unrecognized" ); if ( ihdr.Colormodel < 0 || ihdr.Colormodel > 6 || ihdr.Colormodel == 1 || ihdr.Colormodel == 5 ) throw new PngjInputException ( "Invalid colormodel " + ihdr.Colormodel ); if ( ihdr.Bitspc != 1 && ihdr.Bitspc != 2 && ihdr.Bitspc != 4 && ihdr.Bitspc != 8 && ihdr.Bitspc != 16 ) throw new PngjInputException ( "Invalid bit depth " + ihdr.Bitspc ); }
public ImageLines Concatenate(ImageLines[,] images, IProgress prog = null) { if (images is null) { throw new ArgumentNullException(nameof(images)); } this.ValidateImages(images, prog, out var rows, out var columns, out var components, out var tileWidth, out var tileHeight); var combinedInfo = new Hjg.Pngcs.ImageInfo( columns * tileWidth, rows * tileHeight, Units.Bits.PER_BYTE, components == 4); var combinedLines = new ImageLines( combinedInfo, ImageLine.ESampleType.BYTE, true, 0, rows * tileHeight, rows * tileHeight * components); for (var y = 0; y < rows; ++y) { for (var x = 0; x < columns; ++x) { var tile = images[y, x]; if (tile is object) { for (var i = 0; i < tileHeight; ++i) { var bufferY = (y * tileHeight) + i; var bufferX = x * tileWidth; var bufferLine = combinedLines.ScanlinesB[bufferY]; var tileLine = tile.ScanlinesB[i]; Array.Copy(tileLine, 0, bufferLine, bufferX, tileLine.Length); } } } } return(combinedLines); }
private double[] preference = new double[] { 1.1, 1.1, 1.1, 1.1, 1.2 }; // a priori preference (NONE SUB UP AVERAGE PAETH) #endregion Fields #region Constructors internal FilterWriteStrategy(ImageInfo imgInfo, FilterType configuredType) { this.imgInfo = imgInfo; this.configuredType = configuredType; if (configuredType < 0) { // first guess if ((imgInfo.Rows < 8 && imgInfo.Cols < 8) || imgInfo.Indexed || imgInfo.BitDepth < 8) currentType = FilterType.FILTER_NONE; else currentType = FilterType.FILTER_PAETH; } else { currentType = configuredType; } if (configuredType == FilterType.FILTER_AGGRESSIVE) discoverEachLines = COMPUTE_STATS_EVERY_N_LINES; if (configuredType == FilterType.FILTER_VERYAGGRESSIVE) discoverEachLines = 1; }
private int rows, cols, dY, dX, oY, oX, oXsamples, dXsamples; // at current pass #endregion Fields #region Constructors internal PngDeinterlacer(ImageInfo iminfo) { this.imi = iminfo; pass = 0; if (imi.Packed) { packedValsPerPixel = 8 / imi.BitDepth; packedShift = imi.BitDepth; if (imi.BitDepth == 1) packedMask = 0x80; else if (imi.BitDepth == 2) packedMask = 0xc0; else packedMask = 0xf0; } else { packedMask = packedShift = packedValsPerPixel = 1;// dont care } setPass(1); setRow(0); }
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; rowb = new byte [ imgInfo.BytesPerRow + 1 ]; rowbprev = new byte [ rowb.Length ]; rowbfilter = new byte [ rowb.Length ]; chunksList = new ChunksListForWrite ( ImgInfo ); metadata = new PngMetadata ( chunksList ); filterStrat = new FilterWriteStrategy ( ImgInfo, FilterType.FILTER_DEFAULT ); unpackedMode = false; needsPack = unpackedMode && imgInfo.Packed; }
public static void Create(string filename, int cols, int rows) { ImageInfo imi = new ImageInfo(cols, rows, 8, false); // 8 bits per channel, no alpha // open image for writing PngWriter png = FileHelper.CreatePngWriter(filename, imi, true); // add some optional metadata (chunks) png.GetMetadata().SetDpi(100.0); png.GetMetadata().SetTimeNow(0); // 0 seconds fron now = now png.GetMetadata().SetText(PngChunkTextVar.KEY_Title, "Just a text image"); PngChunk chunk = png.GetMetadata().SetText("my key", "my text .. bla bla"); chunk.Priority = true; // this chunk will be written as soon as possible ImageLine iline = new ImageLine(imi); for (int col = 0; col < imi.Cols; col++) { // this line will be written to all rows int r = 255; int g = 127; int b = 255 * col / imi.Cols; ImageLineHelper.SetPixel(iline , col, r, g, b); // orange-ish gradient } for (int row = 0; row < png.ImgInfo.Rows; row++) { png.WriteRow(iline, row); } png.End(); }
public static string createWaves(String suffix, double scale, ImageInfo imi) { string f = getTmpFile(suffix); // open image for writing to a output stream PngWriter png = FileHelper.CreatePngWriter(f, imi, true); png.GetMetadata().SetText("key1", "val1"); ImageLine iline = new ImageLine(imi, ImageLine.ESampleType.BYTE, true); for (int row = 0; row < png.ImgInfo.Rows; row++) { for (int x = 0; x < imi.Cols; x++) { int r = (int)((Math.Sin((row + x) * 0.073 * scale) + 1) * 128); int g = (int)((Math.Sin((row + x * 0.22) * 0.08 * scale) + 1) * 128); int b = (int)((Math.Sin((row * 0.52 - x * 0.2) * 0.21 * scale) + 1) * 128); iline.ScanlineB[x * imi.Channels] = (byte)r; iline.ScanlineB[x * imi.Channels + 1] = (byte)g; iline.ScanlineB[x * imi.Channels + 2] = (byte)b; if (imi.Channels == 4) iline.ScanlineB[x * imi.Channels + 3] = (byte)((b + g) / 2); } png.WriteRow(iline, row); } png.End(); return f; }
public static void doit(String orig) { string copy= TestsHelper.addSuffixToName(orig, "_tc"); PngReader pngr = FileHelper.CreatePngReader(orig); if (!pngr.ImgInfo.Indexed) throw new Exception("Not indexed image"); PngChunkPLTE plte = pngr.GetMetadata().GetPLTE(); PngChunkTRNS trns = pngr.GetMetadata().GetTRNS(); // transparency metadata, can be null bool alpha = trns != null; ImageInfo im2 = new ImageInfo(pngr.ImgInfo.Cols, pngr.ImgInfo.Rows, 8, alpha); PngWriter pngw = FileHelper.CreatePngWriter(copy, im2, true); pngw.CopyChunksFirst(pngr, ChunkCopyBehaviour.COPY_ALL_SAFE); int[] buf = null; for (int row = 0; row < pngr.ImgInfo.Rows; row++) { ImageLine line = pngr.ReadRowInt(row); buf = ImageLineHelper.Palette2rgb(line, plte, trns, buf); pngw.WriteRowInt(buf, row); } pngw.CopyChunksLast(pngr, ChunkCopyBehaviour.COPY_ALL_SAFE); pngr.End(); pngw.End(); Console.WriteLine("True color: " + copy); }
public ImageLine(ImageInfo imgInfo) : this(imgInfo, ESampleType.INT, false) { }
public ImageLine(ImageInfo imgInfo, ESampleType stype) : this(imgInfo, stype, false) { }
public PngChunkSRGB( ImageInfo info ) : base(ID, info) { }
public PngChunkIHDR(ImageInfo info) : base(ID, info) { }
/// <summary> /// Constructs an ImageLine /// </summary> /// <param name="imgInfo">Inmutable copy of PNG ImageInfo</param> /// <param name="stype">Storage for samples:INT (default) or BYTE</param> /// <param name="unpackedMode">If true and bitdepth less than 8, samples are unpacked. This has no effect if biddepth 8 or 16</param> public ImageLine(ImageInfo imgInfo, ESampleType stype, bool unpackedMode) : this(imgInfo, stype, unpackedMode, null, null) { }
private static void additionalTestPalette(string orig, string truecolor) { // covnert to true color 8 bits and check equality PngReader pngr = FileHelper.CreatePngReader(orig); PngChunkPLTE plte = pngr.GetMetadata().GetPLTE(); PngChunkTRNS trns = pngr.GetMetadata().GetTRNS(); string copy = TestsHelper.addSuffixToName(orig, "_tccopy"); bool alpha = trns != null; ImageInfo im2 = new ImageInfo(pngr.ImgInfo.Cols, pngr.ImgInfo.Rows, 8, alpha); PngWriter pngw = FileHelper.CreatePngWriter(copy, im2, true); pngw.CopyChunksFirst(pngr, ChunkCopyBehaviour.COPY_ALL_SAFE); int[] buf = null; for (int row = 0; row < pngr.ImgInfo.Rows; row++) { ImageLine line = pngr.ReadRowInt(row); buf = ImageLineHelper.Palette2rgb(line, plte, trns, buf); pngw.WriteRowInt(buf, row); } pngr.End(); pngw.End(); TestsHelper.testEqual(copy, truecolor); System.IO.File.Delete(copy); }
public PngChunkGAMA(ImageInfo info) : base(ID, info) { }
public PngWriter( Stream outputStream, ImageInfo imgInfo ) : this(outputStream, imgInfo, "[NO FILENAME AVAILABLE]") { }
internal static void unpackInplaceInt(ImageInfo iminfo, int[] src, int[] dst, bool Scale) { int bitDepth = iminfo.BitDepth; if (bitDepth >= 8) return; // nothing to do int mask0 = GetMaskForPackedFormatsLs(bitDepth); int scalefactor = 8 - bitDepth; int offset0 = 8 * iminfo.SamplesPerRowPacked - bitDepth * iminfo.SamplesPerRow; int mask, offset, v; if (offset0 != 8) { mask = mask0 << offset0; offset = offset0; // how many bits to shift the mask to the right to recover mask0 } else { mask = mask0; offset = 0; } for (int j = iminfo.SamplesPerRow - 1, i = iminfo.SamplesPerRowPacked - 1; j >= 0; j--) { v = (src[i] & mask) >> offset; if (Scale) v <<= scalefactor; dst[j] = v; mask <<= bitDepth; offset += bitDepth; if (offset == 8) { mask = mask0; offset = 0; i--; } } }
internal static void packInplaceInt(ImageInfo iminfo, int[] src, int[] dst, bool scaled) { int bitDepth = iminfo.BitDepth; if (bitDepth >= 8) return; // nothing to do int mask0 = GetMaskForPackedFormatsLs(bitDepth); int scalefactor = 8 - bitDepth; int offset0 = 8 - bitDepth; int v, v0; int offset = 8 - bitDepth; v0 = src[0]; // first value is special for in place dst[0] = 0; if (scaled) v0 >>= scalefactor; v0 = ((v0 & mask0) << offset); for (int i = 0, j = 0; j < iminfo.SamplesPerRow; j++) { v = src[j]; if (scaled) v >>= scalefactor; dst[i] |= ((v & mask0) << offset); offset -= bitDepth; if (offset < 0) { offset = offset0; i++; dst[i] = 0; } } dst[0] |= v0; }
public static int[] Unpack( ImageInfo imgInfo, int [] src, int [] dst, bool scale ) { int len1 = imgInfo.SamplesPerRow; int len0 = imgInfo.SamplesPerRowPacked; if ( dst == null || dst.Length < len1 ) dst = new int [ len1 ]; if ( imgInfo.Packed ) ImageLine.unpackInplaceInt ( imgInfo, src, dst, scale ); else Array.Copy ( src, 0, dst, 0, len0 ); return dst; }
public PngChunkPHYS( ImageInfo info ) : base(ID, info) { }
internal readonly int channels; // copied from imgInfo, more handy #endregion Fields #region Constructors public ImageLine(ImageInfo imgInfo) : this(imgInfo, ESampleType.INT, false) { }
public PngWriter(Stream outputStream, ImageInfo imgInfo) : this(outputStream, imgInfo, "[NO FILENAME AVAILABLE]") { }
protected internal PngChunkTextVar(String id, ImageInfo info) : base(id, info) { }
public PngChunkSBIT(ImageInfo info) : base(ID, info) { }
private int[] hist = new int[0]; // should have same lenght as palette #endregion Fields #region Constructors public PngChunkHIST(ImageInfo info) : base(ID, info) { }
public PngChunkCHRM(ImageInfo info) : base(ID, info) { }
public PngChunkUNKNOWN(String id, ImageInfo info) : base(id, info) { }
private PngChunkUNKNOWN(PngChunkUNKNOWN c, ImageInfo info) : base(c.Id, info) { System.Array.Copy(c.data, 0, data, 0, c.data.Length); }
public PngChunkZTXT(ImageInfo info) : base(ID, info) { }
/// <summary> /// Constructs a PNGReader objet from a opened Stream /// </summary> /// <remarks>The constructor reads the signature and first chunk (IDHR)<seealso cref="FileHelper.CreatePngReader(string)"/> /// </remarks> /// /// <param name="inputStream"></param> /// <param name="filename">Optional, can be the filename or a description.</param> public PngReader(Stream inputStream, String filename) { this.filename = (filename == null) ? "" : filename; this.inputStream = inputStream; this.chunksList = new ChunksList(null); this.metadata = new PngMetadata(chunksList); this.offset = 0; // set default options this.CurrentChunkGroup = -1; this.ShouldCloseStream = true; this.MaxBytesMetadata = 5 * 1024 * 1024; this.MaxTotalBytesRead = 200 * 1024 * 1024; // 200MB this.SkipChunkMaxSize = 2 * 1024 * 1024; this.SkipChunkIds = new string[] { "fdAT" }; this.ChunkLoadBehaviour = Hjg.Pngcs.Chunks.ChunkLoadBehaviour.LOAD_CHUNK_ALWAYS; // starts reading: signature byte[] pngid = new byte[8]; PngHelperInternal.ReadBytes(inputStream, pngid, 0, pngid.Length); offset += pngid.Length; if (!PngCsUtils.arraysEqual(pngid, PngHelperInternal.PNG_ID_SIGNATURE)) { throw new PngjInputException("Bad PNG signature"); } CurrentChunkGroup = ChunksList.CHUNK_GROUP_0_IDHR; // reads first chunk IDHR int clen = PngHelperInternal.ReadInt4(inputStream); offset += 4; if (clen != 13) { throw new Exception("IDHR chunk len != 13 ?? " + clen); } byte[] chunkid = new byte[4]; PngHelperInternal.ReadBytes(inputStream, chunkid, 0, 4); if (!PngCsUtils.arraysEqual4(chunkid, ChunkHelper.b_IHDR)) { throw new PngjInputException("IHDR not found as first chunk??? [" + ChunkHelper.ToString(chunkid) + "]"); } offset += 4; PngChunkIHDR ihdr = (PngChunkIHDR)ReadChunk(chunkid, clen, false); bool alpha = (ihdr.Colormodel & 0x04) != 0; bool palette = (ihdr.Colormodel & 0x01) != 0; bool grayscale = (ihdr.Colormodel == 0 || ihdr.Colormodel == 4); // creates ImgInfo and imgLine, and allocates buffers ImgInfo = new ImageInfo(ihdr.Cols, ihdr.Rows, ihdr.Bitspc, alpha, grayscale, palette); rowb = new byte[ImgInfo.BytesPerRow + 1]; rowbprev = new byte[rowb.Length]; rowbfilter = new byte[rowb.Length]; interlaced = ihdr.Interlaced == 1; deinterlacer = interlaced ? new PngDeinterlacer(ImgInfo) : null; // some checks if (ihdr.Filmeth != 0 || ihdr.Compmeth != 0 || (ihdr.Interlaced & 0xFFFE) != 0) { throw new PngjInputException("compmethod or filtermethod or interlaced unrecognized"); } if (ihdr.Colormodel < 0 || ihdr.Colormodel > 6 || ihdr.Colormodel == 1 || ihdr.Colormodel == 5) { throw new PngjInputException("Invalid colormodel " + ihdr.Colormodel); } if (ihdr.Bitspc != 1 && ihdr.Bitspc != 2 && ihdr.Bitspc != 4 && ihdr.Bitspc != 8 && ihdr.Bitspc != 16) { throw new PngjInputException("Invalid bit depth " + ihdr.Bitspc); } }