diff --git a/Hjg.Pngcs.Portable/Hjg.Pngcs.Portable.csproj b/Hjg.Pngcs.Portable/Hjg.Pngcs.Portable.csproj new file mode 100644 index 0000000..766a8a3 --- /dev/null +++ b/Hjg.Pngcs.Portable/Hjg.Pngcs.Portable.csproj @@ -0,0 +1,265 @@ + + + + + 10.0 + Debug + AnyCPU + {CCF5E155-ECF0-4DBC-BC7C-69FE1AAAF235} + Library + Properties + Ar.Com.Hjg.Pngcs + Pngcs.Portable + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile111 + v4.5 + + + true + full + false + bin\Debug\ + TRACE;DEBUG;NET45;PORTABLE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE;NET45;PORTABLE + prompt + 4 + + + + + + + BufferedStreamReader.cs + + + ChunkReaderMode.cs + + + Chunks\ChunkCopyBehaviour.cs + + + Chunks\ChunkHelper.cs + + + Chunks\ChunkLoadBehaviour.cs + + + Chunks\ChunkPredicate.cs + + + Chunks\ChunkPredicateEquiv.cs + + + Chunks\ChunkPredicateId.cs + + + Chunks\ChunkPredicateId2.cs + + + Chunks\ChunkRaw.cs + + + Chunks\ChunksList.cs + + + Chunks\ChunksListForWrite.cs + + + Chunks\PngChunk.cs + + + Chunks\PngChunkBKGD.cs + + + Chunks\PngChunkCHRM.cs + + + Chunks\PngChunkGAMA.cs + + + Chunks\PngChunkHIST.cs + + + Chunks\PngChunkICCP.cs + + + Chunks\PngChunkIDAT.cs + + + Chunks\PngChunkIEND.cs + + + Chunks\PngChunkIHDR.cs + + + Chunks\PngChunkITXT.cs + + + Chunks\PngChunkMultiple.cs + + + Chunks\PngChunkOFFS.cs + + + Chunks\PngChunkPHYS.cs + + + Chunks\PngChunkPLTE.cs + + + Chunks\PngChunkSBIT.cs + + + Chunks\PngChunkSingle.cs + + + Chunks\PngChunkSkipped.cs + + + Chunks\PngChunkSPLT.cs + + + Chunks\PngChunkSRGB.cs + + + Chunks\PngChunkSTER.cs + + + Chunks\PngChunkTEXT.cs + + + Chunks\PngChunkTextVar.cs + + + Chunks\PngChunkTIME.cs + + + Chunks\PngChunkTRNS.cs + + + Chunks\PngChunkUNKNOWN.cs + + + Chunks\PngChunkZTXT.cs + + + Chunks\PngMetadata.cs + + + FilterType.cs + + + FilterWriteStrategy.cs + + + IBytesConsumer.cs + + + ImageInfo.cs + + + ImageLine.cs + + + ImageLineHelper.cs + + + ImageLines.cs + + + PngCsUtils.cs + + + PngDeinterlacer.cs + + + PngHelperInternal.cs + + + PngIDatChunkInputStream.cs + + + PngIDatChunkOutputStream.cs + + + PngjBadCrcException.cs + + + PngjException.cs + + + PngjExceptionInternal.cs + + + PngjInputException.cs + + + PngjOutputException.cs + + + PngjUnsupportedException.cs + + + PngReader.cs + + + PngWriter.cs + + + ProgressiveOutputStream.cs + + + Properties\AssemblyInfo.cs + + + Zlib\Adler32.cs + + + Zlib\AZlibInputStream.cs + + + Zlib\AZlibOutputStream.cs + + + Zlib\CRC32.cs + + + Zlib\DeflateCompressLevel.cs + + + Zlib\EDeflateCompressStrategy.cs + + + Zlib\ZlibInputStreamIs.cs + + + Zlib\ZlibInputStreamMs.cs + + + Zlib\ZlibOutputStreamIs.cs + + + Zlib\ZlibOutputStreamMs.cs + + + Zlib\ZlibStreamFactory.cs + + + + + \ No newline at end of file diff --git a/Hjg.Pngcs/BufferedStreamReader.cs b/Hjg.Pngcs/BufferedStreamReader.cs index 92726a6..7628648 100644 --- a/Hjg.Pngcs/BufferedStreamReader.cs +++ b/Hjg.Pngcs/BufferedStreamReader.cs @@ -15,7 +15,7 @@ class BufferedStreamFeeder private bool eof = false; private bool closeStream = true; private bool failIfNoFeed = false; - private static const int DEFAULTSIZE = 8192; + private const int DEFAULTSIZE = 8192; public BufferedStreamFeeder(Stream ist) : this(ist,DEFAULTSIZE) { } @@ -126,7 +126,7 @@ public void close() try { if (_stream != null && closeStream) - _stream.Close(); + _stream.Dispose(); } catch (Exception e) { diff --git a/Hjg.Pngcs/Chunks/ChunkHelper.cs b/Hjg.Pngcs/Chunks/ChunkHelper.cs index 4971bfe..7b5bb17 100644 --- a/Hjg.Pngcs/Chunks/ChunkHelper.cs +++ b/Hjg.Pngcs/Chunks/ChunkHelper.cs @@ -53,7 +53,7 @@ public static byte[] ToBytes(String x) { /// /// public static String ToString(byte[] x) { - return Hjg.Pngcs.PngHelperInternal.charsetLatin1.GetString(x); + return Hjg.Pngcs.PngHelperInternal.charsetLatin1.GetString(x, 0, x.Length); } /// /// Converts to String using Latin1 (ISO-8859-1) @@ -81,7 +81,7 @@ public static byte[] ToBytesUTF8(String x) { /// /// public static String ToStringUTF8(byte[] x) { - return Hjg.Pngcs.PngHelperInternal.charsetUtf8.GetString(x); + return Hjg.Pngcs.PngHelperInternal.charsetUtf8.GetString(x, 0, x.Length); } /// /// Converts to string using UTF-8 @@ -187,8 +187,8 @@ internal static byte[] compressBytes(byte[] ori, int offset, int len, bool compr Stream outx = outb; if (compress) outx = ZlibStreamFactory.createZlibOutputStream(outb); shovelInToOut(inx, outx); - inx.Close(); - outx.Close(); + inx.Dispose(); + outx.Dispose(); byte[] res = outb.ToArray(); return res; } catch (Exception e) { diff --git a/Hjg.Pngcs/Chunks/ChunkRaw.cs b/Hjg.Pngcs/Chunks/ChunkRaw.cs index bcfe0f0..83c7f77 100644 --- a/Hjg.Pngcs/Chunks/ChunkRaw.cs +++ b/Hjg.Pngcs/Chunks/ChunkRaw.cs @@ -101,7 +101,16 @@ internal MemoryStream GetAsByteStream() { // only the data return new MemoryStream(Data); } - private void AllocData() { + /** + * offset in the full PNG stream, in bytes. only informational, for read chunks (0=NA) + */ + public void setOffset(long offset) + { + this.offset = offset; + } + + private void AllocData() + { if (Data == null || Data.Length < Len) Data = new byte[Len]; } diff --git a/Hjg.Pngcs/Chunks/PngChunk.cs b/Hjg.Pngcs/Chunks/PngChunk.cs index 0dc1d41..a0a76e6 100644 --- a/Hjg.Pngcs/Chunks/PngChunk.cs +++ b/Hjg.Pngcs/Chunks/PngChunk.cs @@ -1,13 +1,14 @@ -namespace Hjg.Pngcs.Chunks { +namespace Hjg.Pngcs.Chunks +{ using Hjg.Pngcs; using System; - using System.Collections; using System.Collections.Generic; - using System.ComponentModel; using System.IO; - using System.Runtime.CompilerServices; - +#if PORTABLE + using System.Linq; + using System.Reflection; +#endif /// /// Represents a instance of a PNG chunk @@ -165,8 +166,17 @@ internal static PngChunk FactoryFromId(String cid, ImageInfo info) { if (factoryMap == null) initFactory(); if (isKnown(cid)) { Type t = factoryMap[cid]; - if (t == null) Console.Error.WriteLine("What?? " + cid); + if (t == null) System.Diagnostics.Debug.WriteLine("What?? " + cid); +#if PORTABLE + System.Reflection.ConstructorInfo cons = t.GetTypeInfo().DeclaredConstructors.Single( + c => + { + var p = c.GetParameters(); + return p.Length == 1 && p[0].ParameterType == typeof(ImageInfo); + }); +#else System.Reflection.ConstructorInfo cons = t.GetConstructor(new Type[] { typeof(ImageInfo) }); +#endif object o = cons.Invoke(new object[] { info }); chunk = (PngChunk)o; } diff --git a/Hjg.Pngcs/Hjg.Pngcs.csproj b/Hjg.Pngcs/Hjg.Pngcs.csproj index eff3e36..fc7d5b6 100644 --- a/Hjg.Pngcs/Hjg.Pngcs.csproj +++ b/Hjg.Pngcs/Hjg.Pngcs.csproj @@ -64,7 +64,7 @@ - ..\..\..\..\..\..\..\temp\ICSharpCode.SharpZipLib.dll + ..\ICSharpCode.SharpZipLib.dll diff --git a/Hjg.Pngcs/IBytesConsumer.cs b/Hjg.Pngcs/IBytesConsumer.cs index d53a4a4..ee9b51e 100644 --- a/Hjg.Pngcs/IBytesConsumer.cs +++ b/Hjg.Pngcs/IBytesConsumer.cs @@ -6,5 +6,6 @@ namespace Ar.Com.Hjg.Pngcs { interface IBytesConsumer { + int consume(byte[] buf, int offset, int len); } } diff --git a/Hjg.Pngcs/ImageInfo.cs b/Hjg.Pngcs/ImageInfo.cs index 0482edb..3f95029 100644 --- a/Hjg.Pngcs/ImageInfo.cs +++ b/Hjg.Pngcs/ImageInfo.cs @@ -16,7 +16,7 @@ namespace Hjg.Pngcs { /// http://www.w3.org/TR/PNG/#11IHDR /// public class ImageInfo { - private const int MAX_COLS_ROWS_VAL = 400000; // very big value, but no so ridiculous as 2^32 + private const int MAX_COLS_ROWS_VAL = 0X7FEFFFFF; // very big value, but no so ridiculous as 2^32 /// /// Image width, in pixels diff --git a/Hjg.Pngcs/PngHelperInternal.cs b/Hjg.Pngcs/PngHelperInternal.cs index 69b6c7e..7d2b938 100644 --- a/Hjg.Pngcs/PngHelperInternal.cs +++ b/Hjg.Pngcs/PngHelperInternal.cs @@ -203,7 +203,7 @@ public static int FilterPaethPredictor(int a, int b, int c) { public static void Logdebug(String msg) { if (DEBUG) - System.Console.Out.WriteLine(msg); + System.Diagnostics.Debug.WriteLine(msg); } @@ -218,7 +218,7 @@ public static long GetCrctestVal(PngReader pngr) { internal static void Log(string p, Exception e) { - Console.Error.WriteLine(p); + System.Diagnostics.Debug.WriteLine(p); } } } diff --git a/Hjg.Pngcs/PngIDatChunkInputStream.cs b/Hjg.Pngcs/PngIDatChunkInputStream.cs index 53de140..b2046d7 100644 --- a/Hjg.Pngcs/PngIDatChunkInputStream.cs +++ b/Hjg.Pngcs/PngIDatChunkInputStream.cs @@ -70,8 +70,12 @@ public PngIDatChunkInputStream(Stream iStream, int lenFirstChunk, long offset_0) /// does NOT close the associated stream! /// /// +#if PORTABLE + public virtual void Close() { +#else public override void Close() { - base.Close(); // nothing +#endif + base.Dispose(); // nothing } private void EndChunkGoForNext() { diff --git a/Hjg.Pngcs/PngReader.cs b/Hjg.Pngcs/PngReader.cs index 76666cb..1611dca 100644 --- a/Hjg.Pngcs/PngReader.cs +++ b/Hjg.Pngcs/PngReader.cs @@ -225,7 +225,7 @@ private bool FirstChunksNotYetRead() { private void ReadLastAndClose() { if (CurrentChunkGroup < ChunksList.CHUNK_GROUP_5_AFTERIDAT) { try { - idatIstream.Close(); + idatIstream.Dispose(); } catch (Exception ) { } ReadLastChunks(); } @@ -235,13 +235,13 @@ private void ReadLastAndClose() { private void Close() { if (CurrentChunkGroup < ChunksList.CHUNK_GROUP_6_END) { // this could only happen if forced close try { - idatIstream.Close(); + idatIstream.Dispose(); } catch (Exception ) { } CurrentChunkGroup = ChunksList.CHUNK_GROUP_6_END; } if (ShouldCloseStream) - inputStream.Close(); + inputStream.Dispose(); } @@ -451,7 +451,7 @@ private PngChunk ReadChunk(byte[] chunkid, int clen, bool skipforced) { /// /// internal void logWarn(String warn) { - Console.Error.WriteLine(warn); + System.Diagnostics.Debug.WriteLine(warn); } /// diff --git a/Hjg.Pngcs/PngWriter.cs b/Hjg.Pngcs/PngWriter.cs index 584e8d4..6d187f4 100644 --- a/Hjg.Pngcs/PngWriter.cs +++ b/Hjg.Pngcs/PngWriter.cs @@ -474,12 +474,12 @@ public void End() { if (rowNum != ImgInfo.Rows - 1) throw new PngjOutputException("all rows have not been written"); try { - datStreamDeflated.Close(); - datStream.Close(); + datStreamDeflated.Dispose(); + datStream.Dispose(); WriteLastChunks(); WriteEndChunk(); if (this.ShouldCloseStream) - outputStream.Close(); + outputStream.Dispose(); } catch (IOException e) { throw new PngjOutputException(e); } diff --git a/Hjg.Pngcs/Pngcs.xml b/Hjg.Pngcs/Pngcs.xml index 422c584..7179d43 100644 --- a/Hjg.Pngcs/Pngcs.xml +++ b/Hjg.Pngcs/Pngcs.xml @@ -4,6 +4,20 @@ Pngcs + + + Stream from which bytes are read + + + + + Feeds bytes to the consumer + Returns bytes actually consumed + This should return 0 only if the stream is EOF or the consumer is done + + + + Static utility methods for CHunks @@ -277,7 +291,7 @@ See http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html - + The length counts only the data field, not itself, the chunk type code, or the CRC. Zero is a valid length. Although encoders and decoders should treat the length as unsigned, its value must not exceed 2^31-1 bytes. @@ -293,13 +307,10 @@ Raw data, crc not included - + Creates an empty raw chunk - - - pre allocate the data buffer? @@ -313,6 +324,9 @@ + + offset in the full PNG stream, in bytes. only informational, for read chunks (0=NA) + Just id and length @@ -497,144 +511,6 @@ A Chunk type that allows duplicate in an image - - - Represents a instance of a PNG chunk - - - Concrete classes should extend PngChunkSingle or PngChunkMultiple - - Note that some methods/fields are type-specific (GetOrderingConstraint(), AllowsMultiple()) - some are 'almost' type-specific (Id,Crit,Pub,Safe; the exception is PngUKNOWN), - and some are instance-specific - - Ref: http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html - - - - - 4 letters. The Id almost determines the concrete type (except for PngUKNOWN) - - - - - Standard basic properties, implicit in the Id - - - - - Standard basic properties, implicit in the Id - - - - - Standard basic properties, implicit in the Id - - - - - Image basic info, mostly for some checks - - - - - Constructs an empty chunk - - - - - - - Registers a Chunk ID in the factory, to instantiate a given type - - - This can be called by client code to register additional chunk types - - - should extend PngChunkSingle or PngChunkMultiple - - - - Creates one new blank chunk of the corresponding type, according to factoryMap (PngChunkUNKNOWN if not known) - - Chunk Id - - - - - - Basic info: Id, length, Type name - - - - - - Serialization. Creates a Raw chunk, ready for write, from this chunk content - - - - - Deserialization. Given a Raw chunk, just rad, fills this chunk content - - - - - Override to make a copy (normally deep) from other chunk - - - - - - This is implemented in PngChunkMultiple/PngChunSingle - - Allows more than one chunk of this type in a image - - - - Get ordering constrain - - - - - - For writing. Queued chunks with high priority will be written as soon as possible - - - - - Chunk group where it was read or writen - - - - - Restrictions for chunk ordering, for ancillary chunks - - - - - No constraint, the chunk can go anywhere - - - - - Before PLTE (palette) - and hence, also before IDAT - - - - - After PLTE (palette), but before IDAT - - - - - Before IDAT (before or after PLTE) - - - - - Does not apply - - A Chunk type that does not allow duplicate in an image @@ -837,101 +713,467 @@ sRGB chunk: http://www.w3.org/TR/PNG/#11sRGB - + - Wraps a set of rows from a image, read in a single operation, stored in a int[][] or byte[][] matrix + Represents a instance of a PNG chunk + + + Concrete classes should extend PngChunkSingle or PngChunkMultiple - They can be a subset of the total rows, but in this case they are equispaced. + Note that some methods/fields are type-specific (GetOrderingConstraint(), AllowsMultiple()) + some are 'almost' type-specific (Id,Crit,Pub,Safe; the exception is PngUKNOWN), + and some are instance-specific - See also ImageLine - + Ref: http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html + - + - Translates from image row number to matrix row. - If you are not sure if this image row in included, use better ImageRowToMatrixRowStrict - + 4 letters. The Id almost determines the concrete type (except for PngUKNOWN) - Row number in the original image (from 0) - Row number in the wrapped matrix. Undefined result if invalid - + - translates from image row number to matrix row + Standard basic properties, implicit in the Id - Row number in the original image (from 0) - Row number in the wrapped matrix. Returns -1 if invalid - + - Translates from matrix row number to real image row number + Standard basic properties, implicit in the Id - - - + - Constructs and returns an ImageLine object backed by a matrix row. - This is quite efficient, no deep copy. + Standard basic properties, implicit in the Id - Row number inside the matrix - - - - this refers to the row currRowSubimg - - - Is current row the last row for the lass pass?? - - - current row number inside the "sub image" - - current row number inside the "real image" + + + Image basic info, mostly for some checks + - - current pass number (1-7) + + + For writing. Queued chunks with high priority will be written as soon as possible + - - How many rows has the current pass? - + + + Chunk group where it was read or writen + - - How many columns (pixels) are there in the current row + + + Restrictions for chunk ordering, for ancillary chunks + - + - Exception for internal problems + No constraint, the chunk can go anywhere - + - Manages the writer strategy for selecting the internal png predictor filter + Before PLTE (palette) - and hence, also before IDAT - - - A few utility static methods to read and write files - - + + + After PLTE (palette), but before IDAT + - + - Given a filename and a ImageInfo, produces a PngWriter object, ready for writing. - Path of file - ImageInfo object - Flag: if false and file exists, a PngjOutputException is thrown - A PngWriter object, ready for writing + Before IDAT (before or after PLTE) + - + - Given a filename, produces a PngReader object, ready for reading. + Does not apply - Path of file - PngReader, ready for reading - - + + + Constructs an empty chunk + + + + + + + Registers a Chunk ID in the factory, to instantiate a given type + + + This can be called by client code to register additional chunk types + + + should extend PngChunkSingle or PngChunkMultiple + + + + Creates one new blank chunk of the corresponding type, according to factoryMap (PngChunkUNKNOWN if not known) + + Chunk Id + + + + + + Basic info: Id, length, Type name + + + + + + Serialization. Creates a Raw chunk, ready for write, from this chunk content + + + + + Deserialization. Given a Raw chunk, just rad, fills this chunk content + + + + + Override to make a copy (normally deep) from other chunk + + + + + + This is implemented in PngChunkMultiple/PngChunSingle + + Allows more than one chunk of this type in a image + + + + Get ordering constrain + + + + + + bKGD chunk, see http://www.w3.org/TR/PNG/#11bKGD + + + + + Set gray value (0-255 if bitdept=8) + + + + + + Gets gray value + + gray value (0-255 if bitdept=8) + + + + Set pallette index - only for indexed + + + + + + Get pallette index - only for indexed + + + + + + Sets rgb value, only for rgb images + + + + + + + + Gets rgb value, only for rgb images + + [r , g, b] array + + + + gAMA chunk, see http://www.w3.org/TR/PNG/#11gAMA + + + + + iCCP Chunk: see http://www.w3.org/TR/PNG/#11iCCP + + + + + Sets profile name and profile + + profile name + profile (latin1 string) + + + + Sets profile name and profile + + profile name + profile (uncompressed) + + + + This uncompresses the string! + + + + + + IDAT chunk http://www.w3.org/TR/PNG/#11IDAT + + This object is dummy placeholder - We treat this chunk in a very different way than ancillary chnks + + + + + IEND chunk http://www.w3.org/TR/PNG/#11IEND + + + + + IHDR chunk: http://www.w3.org/TR/PNG/#11IHDR + + + + + iTXt chunk: http://www.w3.org/TR/PNG/#11iTXt + One of the three text chunks + + + + + Unknown (for our chunk factory) chunk type. + + + + + pHYs chunk: http://www.w3.org/TR/PNG/#11pHYs + + + + + 0: unknown 1:metre + + + + + returns -1 if not in meters, or not equal + + + + + + returns -1 if the physicial unit is unknown + + + + + + same in both directions + + + + + + PLTE Palette chunk: this is the only optional critical chunk + + http://www.w3.org/TR/PNG/#11PLTE + + + + + + + + + + Also allocates array + + 1-256 + + + + as packed RGB8 + + + + + + + Gets n'th entry, filling 3 positions of given array, at given offset + + + + + + + + shortcut: GetEntryRgb(index, int[] rgb, 0) + + + + + + + minimum allowed bit depth, given palette size + + 1-2-4-8 + + + + tEXt chunk: latin1 uncompressed text + + + + + general class for textual chunks + + + + + + + + + + + tIME chunk: http://www.w3.org/TR/PNG/#11tIME + + + + format YYYY/MM/DD HH:mm:SS + + + + tRNS chunk: http://www.w3.org/TR/PNG/#11tRNS + + + + + WARNING: non deep copy + + + + + + utiliy method : to use when only one pallete index is set as totally transparent + + + + + + WARNING: non deep copy + + + + + + zTXt chunk: http://www.w3.org/TR/PNG/#11zTXt + + + + + + Wraps a set of rows from a image, read in a single operation, stored in a int[][] or byte[][] matrix + + They can be a subset of the total rows, but in this case they are equispaced. + + See also ImageLine + + + + + Translates from image row number to matrix row. + If you are not sure if this image row in included, use better ImageRowToMatrixRowStrict + + + Row number in the original image (from 0) + Row number in the wrapped matrix. Undefined result if invalid + + + + translates from image row number to matrix row + + Row number in the original image (from 0) + Row number in the wrapped matrix. Returns -1 if invalid + + + + Translates from matrix row number to real image row number + + + + + + + Constructs and returns an ImageLine object backed by a matrix row. + This is quite efficient, no deep copy. + + Row number inside the matrix + + + + this refers to the row currRowSubimg + + + Is current row the last row for the lass pass?? + + + current row number inside the "sub image" + + + current row number inside the "real image" + + + current pass number (1-7) + + + How many rows has the current pass? + + + + How many columns (pixels) are there in the current row + + + + Exception for internal problems + + + + + Manages the writer strategy for selecting the internal png predictor filter + + + + + A few utility static methods to read and write files + + + + + + Given a filename and a ImageInfo, produces a PngWriter object, ready for writing. + Path of file + ImageInfo object + Flag: if false and file exists, a PngjOutputException is thrown + A PngWriter object, ready for writing + + + + Given a filename, produces a PngReader object, ready for reading. + + Path of file + PngReader, ready for reading + + + Utility functions for C# porting @@ -1060,31 +1302,6 @@ See scanline field doc, to understand the format. - - - Constructs an ImageLine - - Inmutable copy of PNG ImageInfo - Storage for samples:INT (default) or BYTE - If true and bitdepth less than 8, samples are unpacked. This has no effect if biddepth 8 or 16 - - - size original: samplesPerRow sizeFinal: samplesPerRowPacked (trailing elements are trash!) * - - - - Makes a deep copy - - You should rarely use this - - - - - Makes a deep copy - - You should rarely use this - - ImageInfo (readonly inmutable) @@ -1123,281 +1340,78 @@ Hown many elements has the scanline array - =imgInfo.samplePerRowPacked, if packed, imgInfo.samplePerRow elsewhere - - - - - Maximum sample value that this line admits: typically 255; less if bitdepth less than 8, 65535 if 16bits - - - - - Determines if samples are stored in integers or in bytes - - - - - True: each scanline element is a sample. - False: each scanline element has severals samples packed in a byte - - - - - informational only ; filled by the reader - - - - - Bunch of utility static methods to process/analyze an image line. - - Not essential at all, some methods are probably to be removed if future releases. - - TODO: document this better - - - - - - - Given an indexed line with a palette, unpacks as a RGB array - - ImageLine as returned from PngReader - Palette chunk - TRNS chunk (optional) - Preallocated array, optional - R G B (one byte per sample) - - - [0,1) - - - - bKGD chunk, see http://www.w3.org/TR/PNG/#11bKGD - - - - - Set gray value (0-255 if bitdept=8) - - - - - - Gets gray value - - gray value (0-255 if bitdept=8) - - - - Set pallette index - only for indexed - - - - - - Get pallette index - only for indexed - - - - - - Sets rgb value, only for rgb images - - - - - - - - Gets rgb value, only for rgb images - - [r , g, b] array - - - - gAMA chunk, see http://www.w3.org/TR/PNG/#11gAMA - - - - - iCCP Chunk: see http://www.w3.org/TR/PNG/#11iCCP - - - - - Sets profile name and profile - - profile name - profile (latin1 string) - - - - Sets profile name and profile - - profile name - profile (uncompressed) - - - - This uncompresses the string! - - - - - - IDAT chunk http://www.w3.org/TR/PNG/#11IDAT - - This object is dummy placeholder - We treat this chunk in a very different way than ancillary chnks - - - - - IEND chunk http://www.w3.org/TR/PNG/#11IEND - - - - - IHDR chunk: http://www.w3.org/TR/PNG/#11IHDR - - - - - iTXt chunk: http://www.w3.org/TR/PNG/#11iTXt - One of the three text chunks - - - - - general class for textual chunks - - - - - - - - - - - Unknown (for our chunk factory) chunk type. - - - - - pHYs chunk: http://www.w3.org/TR/PNG/#11pHYs - - - - - returns -1 if not in meters, or not equal - - - - - - returns -1 if the physicial unit is unknown - - - - - - same in both directions - - - - - - 0: unknown 1:metre - - - - - PLTE Palette chunk: this is the only optional critical chunk - - http://www.w3.org/TR/PNG/#11PLTE - - - - - - - - - - Also allocates array - - 1-256 - - - - as packed RGB8 - - - - - - - Gets n'th entry, filling 3 positions of given array, at given offset - - - - - - - - shortcut: GetEntryRgb(index, int[] rgb, 0) + =imgInfo.samplePerRowPacked, if packed, imgInfo.samplePerRow elsewhere - - - + - minimum allowed bit depth, given palette size + Maximum sample value that this line admits: typically 255; less if bitdepth less than 8, 65535 if 16bits - 1-2-4-8 - + - tEXt chunk: latin1 uncompressed text + Determines if samples are stored in integers or in bytes - + - tIME chunk: http://www.w3.org/TR/PNG/#11tIME + True: each scanline element is a sample. + False: each scanline element has severals samples packed in a byte - - format YYYY/MM/DD HH:mm:SS - - + - tRNS chunk: http://www.w3.org/TR/PNG/#11tRNS + informational only ; filled by the reader - + - WARNING: non deep copy + Constructs an ImageLine - + Inmutable copy of PNG ImageInfo + Storage for samples:INT (default) or BYTE + If true and bitdepth less than 8, samples are unpacked. This has no effect if biddepth 8 or 16 - + + size original: samplesPerRow sizeFinal: samplesPerRowPacked (trailing elements are trash!) * + + - utiliy method : to use when only one pallete index is set as totally transparent + Makes a deep copy - + You should rarely use this + - + - WARNING: non deep copy + Makes a deep copy - + You should rarely use this + - - - zTXt chunk: http://www.w3.org/TR/PNG/#11zTXt + + + Bunch of utility static methods to process/analyze an image line. + + Not essential at all, some methods are probably to be removed if future releases. + + TODO: document this better + + + + + + Given an indexed line with a palette, unpacks as a RGB array + ImageLine as returned from PngReader + Palette chunk + TRNS chunk (optional) + Preallocated array, optional + R G B (one byte per sample) + + + [0,1) @@ -1525,20 +1539,6 @@ outputs the stream for IDAT chunk , fragmented at fixed size (32k default). - - - - stream that outputs to memory and allows to flush fragments every 'size' - bytes to some other destination - - - - - - if it's time to flush data (or if forced==true) calls abstract method - flushBuffer() and cleans those bytes from own buffer - - @@ -1590,11 +1590,58 @@ + + + Basic image info, inmutable + + filename, or description - merely informative, can be empty + + + Strategy for chunk loading. Default: LOAD_CHUNK_ALWAYS + + + + + Should close the underlying Input Stream when ends? + + + + + Maximum amount of bytes from ancillary chunks to load in memory + + + Default: 5MB. 0: unlimited. If exceeded, chunks will be skipped + + + + + Maximum total bytes to read from stream + + + Default: 200MB. 0: Unlimited. If exceeded, an exception will be thrown + + + + + Maximum ancillary chunk size + + + Default: 2MB, 0: unlimited. Chunks exceeding this size will be skipped (nor even CRC checked) + + + + + Ancillary chunks to skip + + + Default: { "fdAT" }. chunks with these ids will be skipped (nor even CRC checked) + + A high level wrapper of a ChunksList : list of read chunks @@ -1625,6 +1672,12 @@ raw current row, after unfiltered + + + number of chunk group (0-6) last read, or currently reading + + see ChunksList.CHUNK_GROUP_NNN + last read row number @@ -1725,74 +1778,47 @@ @see PngReader#setUnpackedMode(boolean) - + - Basic image info, inmutable + Writes a PNG image, line by line. - + - Strategy for chunk loading. Default: LOAD_CHUNK_ALWAYS + Basic image info, inmutable - + - Should close the underlying Input Stream when ends? + filename, or description - merely informative, can be empty - - - Maximum amount of bytes from ancillary chunks to load in memory - - - Default: 5MB. 0: unlimited. If exceeded, chunks will be skipped - + + Deflate algortithm compression strategy - + - Maximum total bytes to read from stream + zip compression level (0 - 9) - Default: 200MB. 0: Unlimited. If exceeded, an exception will be thrown + default:6 + + 9 is the maximum compression - + - Maximum ancillary chunk size + true: closes stream after ending write - - Default: 2MB, 0: unlimited. Chunks exceeding this size will be skipped (nor even CRC checked) - - + - Ancillary chunks to skip + Maximum size of IDAT chunks - Default: { "fdAT" }. chunks with these ids will be skipped (nor even CRC checked) + 0=use default (PngIDatChunkOutputStream 32768) - - - number of chunk group (0-6) last read, or currently reading - - see ChunksList.CHUNK_GROUP_NNN - - - - Writes a PNG image, line by line. - - - - - Basic image info, inmutable - - - - - filename, or description - merely informative, can be empty - - A high level wrapper of a ChunksList : list of written/queued chunks @@ -1818,6 +1844,12 @@ raw current row, after filtered + + + number of chunk group (0-6) last writen, or currently writing + + see ChunksList.CHUNK_GROUP_NNN + Constructs a PngWriter from a outputStream, with no filename information @@ -1917,55 +1949,32 @@ One of the five prediction types or strategy to choose it - - Deflate algortithm compression strategy - - - - zip compression level (0 - 9) - - - default:6 + + + stream that outputs to memory and allows to flush fragments every 'size' + bytes to some other destination + - 9 is the maximum compression - - - - - true: closes stream after ending write - - - - - Maximum size of IDAT chunks - - - 0=use default (PngIDatChunkOutputStream 32768) - - - - number of chunk group (0-6) last writen, or currently writing - - see ChunksList.CHUNK_GROUP_NNN + + + if it's time to flush data (or if forced==true) calls abstract method + flushBuffer() and cleans those bytes from own buffer + + - + - Zlib output (deflater) based on ShaprZipLib + Zip input (deflater) based on Ms DeflateStream (.net 4.5) - + mainly for debugging - - - Zip input (inflater) based on ShaprZipLib - - - + mainly for debugging diff --git a/Hjg.Pngcs/PngjBadCrcException.cs b/Hjg.Pngcs/PngjBadCrcException.cs index 0de3733..fd70f6c 100644 --- a/Hjg.Pngcs/PngjBadCrcException.cs +++ b/Hjg.Pngcs/PngjBadCrcException.cs @@ -10,7 +10,9 @@ namespace Hjg.Pngcs { /// /// Exception for CRC check /// +#if !PORTABLE [Serializable] +#endif public class PngjBadCrcException : PngjException { private const long serialVersionUID = 1L; diff --git a/Hjg.Pngcs/PngjException.cs b/Hjg.Pngcs/PngjException.cs index 3304300..a5f0b9d 100644 --- a/Hjg.Pngcs/PngjException.cs +++ b/Hjg.Pngcs/PngjException.cs @@ -10,7 +10,9 @@ namespace Hjg.Pngcs { /// /// Gral exception class for PNGCS library /// +#if !PORTABLE [Serializable] +#endif public class PngjException : Exception { private const long serialVersionUID = 1L; diff --git a/Hjg.Pngcs/PngjExceptionInternal.cs b/Hjg.Pngcs/PngjExceptionInternal.cs index 91af2c2..2bcd6d4 100644 --- a/Hjg.Pngcs/PngjExceptionInternal.cs +++ b/Hjg.Pngcs/PngjExceptionInternal.cs @@ -10,7 +10,9 @@ namespace Hjg.Pngcs { /// /// Exception for internal problems /// +#if !PORTABLE [Serializable] +#endif public class PngjExceptionInternal : Exception { private const long serialVersionUID = 1L; diff --git a/Hjg.Pngcs/PngjInputException.cs b/Hjg.Pngcs/PngjInputException.cs index 40a9939..6b8bc05 100644 --- a/Hjg.Pngcs/PngjInputException.cs +++ b/Hjg.Pngcs/PngjInputException.cs @@ -10,7 +10,9 @@ namespace Hjg.Pngcs { /// /// Exception associated with input (reading) operations /// +#if !PORTABLE [Serializable] +#endif public class PngjInputException : PngjException { private const long serialVersionUID = 1L; diff --git a/Hjg.Pngcs/PngjOutputException.cs b/Hjg.Pngcs/PngjOutputException.cs index fa7d9ae..78b14cb 100644 --- a/Hjg.Pngcs/PngjOutputException.cs +++ b/Hjg.Pngcs/PngjOutputException.cs @@ -10,7 +10,9 @@ namespace Hjg.Pngcs { /// /// Exception associated with input (reading) operations /// +#if !PORTABLE [Serializable] +#endif public class PngjOutputException : PngjException { private const long serialVersionUID = 1L; diff --git a/Hjg.Pngcs/PngjUnsupportedException.cs b/Hjg.Pngcs/PngjUnsupportedException.cs index e2c9345..824307d 100644 --- a/Hjg.Pngcs/PngjUnsupportedException.cs +++ b/Hjg.Pngcs/PngjUnsupportedException.cs @@ -10,7 +10,9 @@ namespace Hjg.Pngcs { /// /// Exception for unsupported operation or feature /// +#if !PORTABLE [Serializable] +#endif public class PngjUnsupportedException : Exception { private const long serialVersionUID = 1L; diff --git a/Hjg.Pngcs/ProgressiveOutputStream.cs b/Hjg.Pngcs/ProgressiveOutputStream.cs index 1234bbc..be7e59b 100644 --- a/Hjg.Pngcs/ProgressiveOutputStream.cs +++ b/Hjg.Pngcs/ProgressiveOutputStream.cs @@ -1,4 +1,5 @@ -namespace Hjg.Pngcs { +namespace Hjg.Pngcs +{ using System; using System.Collections; @@ -12,31 +13,42 @@ namespace Hjg.Pngcs { /// bytes to some other destination /// /// - abstract internal class ProgressiveOutputStream : MemoryStream { + abstract internal class ProgressiveOutputStream : MemoryStream + { private readonly int size; private long countFlushed = 0; - public ProgressiveOutputStream(int size_0) { + public ProgressiveOutputStream(int size_0) + { this.size = size_0; if (size < 8) throw new PngjException("bad size for ProgressiveOutputStream: " + size); } - public override void Close() { +#if PORTABLE + public virtual void Close() + { +#else + public override void Close() + { +#endif Flush(); - base.Close(); + base.Dispose(); } - public override void Flush() { + public override void Flush() + { base.Flush(); CheckFlushBuffer(true); } - public override void Write(byte[] b, int off, int len) { + public override void Write(byte[] b, int off, int len) + { base.Write(b, off, len); CheckFlushBuffer(false); } - public void Write(byte[] b) { + public void Write(byte[] b) + { Write(b, 0, b.Length); CheckFlushBuffer(false); } @@ -47,29 +59,52 @@ public void Write(byte[] b) { /// flushBuffer() and cleans those bytes from own buffer /// /// - private void CheckFlushBuffer(bool forced) { + private void CheckFlushBuffer(bool forced) + { int count = (int)Position; - byte[] buf = GetBuffer(); - while (forced || count >= size) { + + while (forced || count >= size) + { int nb = size; if (nb > count) nb = count; if (nb == 0) return; + + byte[] buf = ToArray(); + FlushBuffer(buf, nb); countFlushed += nb; int bytesleft = count - nb; count = bytesleft; - Position = count; + + Position = 0; if (bytesleft > 0) - System.Array.Copy((Array)(buf), nb, (Array)(buf), 0, bytesleft); + base.Write(buf, nb, bytesleft); } } protected abstract void FlushBuffer(byte[] b, int n); - public long GetCountFlushed() { + public long GetCountFlushed() + { return countFlushed; } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + this.Close(); + // Free any other managed objects here. + // + } + + // Free any unmanaged objects here. + // + + // Call base class implementation. + base.Dispose(disposing); + } } } diff --git a/Hjg.Pngcs/Zlib/ZlibInputStreamMs.cs b/Hjg.Pngcs/Zlib/ZlibInputStreamMs.cs index 9aa05a5..26fe03d 100644 --- a/Hjg.Pngcs/Zlib/ZlibInputStreamMs.cs +++ b/Hjg.Pngcs/Zlib/ZlibInputStreamMs.cs @@ -40,20 +40,21 @@ public override int Read(byte[] array, int offset, int count) { } return r; } + + public virtual void Close() { - public override void Close() { if (!initdone) doInit(); // can happen if never called write if (closed) return; closed = true; if (deflateStream != null) { - deflateStream.Close(); + deflateStream.Dispose(); } if (crcread == null) { // eat trailing 4 bytes crcread = new byte[4]; for (int i = 0; i < 4; i++) crcread[i] = (byte)rawStream.ReadByte(); } if (!leaveOpen) - rawStream.Close(); + rawStream.Dispose(); } private void initStream() { @@ -86,6 +87,23 @@ public override void Flush() { public override String getImplementationId() { return "Zlib inflater: .Net CLR 4.5"; } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + this.Close(); + // Free any other managed objects here. + // + } + + // Free any unmanaged objects here. + // + + // Call base class implementation. + base.Dispose(disposing); + } + } #endif diff --git a/Hjg.Pngcs/Zlib/ZlibOutputStreamMs.cs b/Hjg.Pngcs/Zlib/ZlibOutputStreamMs.cs index ce1fbf4..0c4a6ea 100644 --- a/Hjg.Pngcs/Zlib/ZlibOutputStreamMs.cs +++ b/Hjg.Pngcs/Zlib/ZlibOutputStreamMs.cs @@ -32,15 +32,16 @@ public override void Write(byte[] array, int offset, int count) { deflateStream.Write(array, offset, count); adler32.Update(array, offset, count); } + + public virtual void Close() { - public override void Close() { if (!initdone) doInit(); // can happen if never called write if (closed) return; closed = true; // sigh ... no only must I close the parent stream to force a flush, but I must save a reference // raw stream because (apparently) Close() sets it to null (shame on you, MS developers) if (deflateStream != null) { - deflateStream.Close(); + deflateStream.Dispose(); } else { // second hack: empty input? rawStream.WriteByte(3); rawStream.WriteByte(0); @@ -52,7 +53,7 @@ public override void Close() { rawStream.WriteByte((byte)((crcv >> 8) & 0xFF)); rawStream.WriteByte((byte)((crcv) & 0xFF)); if (!leaveOpen) - rawStream.Close(); + rawStream.Dispose(); } @@ -91,6 +92,22 @@ public override String getImplementationId() { return "Zlib deflater: .Net CLR 4.5"; } + protected override void Dispose(bool disposing) + { + if (disposing) + { + this.Close(); + // Free any other managed objects here. + // + } + + // Free any unmanaged objects here. + // + + // Call base class implementation. + base.Dispose(disposing); + } + } #endif } diff --git a/SamplesTests.Portable/App.config b/SamplesTests.Portable/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/SamplesTests.Portable/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SamplesTests.Portable/SamplesTests.Portable.csproj b/SamplesTests.Portable/SamplesTests.Portable.csproj new file mode 100644 index 0000000..9b72baf --- /dev/null +++ b/SamplesTests.Portable/SamplesTests.Portable.csproj @@ -0,0 +1,103 @@ + + + + + Debug + AnyCPU + {FC944235-D299-4EEF-BE46-D5A83C591048} + Exe + Properties + SamplesTests + SamplesTests + v4.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + TRACE;DEBUG;NET45 + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE;NET45 + prompt + 4 + + + + + + + + + + + + {ccf5e155-ecf0-4dbc-bc7c-69fe1aaaf235} + Hjg.Pngcs.Portable + + + + + FileHelper.cs + + + MainProgram.cs + + + NullOutputStream.cs + + + Properties\AssemblyInfo.cs + + + SampleConvertToTrueCol.cs + + + SampleCreateOrange.cs + + + SampleCustomChunk.cs + + + SampleDecreaseRed.cs + + + SampleMirrorImage.cs + + + SampleShowChunks.cs + + + SampleTileImage.cs + + + TestPngSuite.cs + + + TestsHelper.cs + + + TestTextChunks.cs + + + TestZlib.cs + + + + + \ No newline at end of file diff --git a/SamplesTests/SampleTileImage.cs b/SamplesTests/SampleTileImage.cs index 35d7b41..626f181 100644 --- a/SamplesTests/SampleTileImage.cs +++ b/SamplesTests/SampleTileImage.cs @@ -17,7 +17,6 @@ public static void tile(String orig, String dest,int factor) { if (factor<2 || factor>100) throw new PngjException("bad factor "); PngReader pngr = FileHelper.CreatePngReader(orig); var x = pngr.ImgInfo; - x. PngWriter pngw = FileHelper.CreatePngWriter(dest, pngr.ImgInfo, true); pngr.SetUnpackedMode(true); // we dont want to do the unpacking ourselves, we want a sample per array element pngw.SetUseUnPackedMode(true); // not really necesary here, as we pass the ImageLine, but anyway... diff --git a/pngcs.portable.sln b/pngcs.portable.sln new file mode 100644 index 0000000..4bd271f --- /dev/null +++ b/pngcs.portable.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hjg.Pngcs.Portable", "Hjg.Pngcs.Portable\Hjg.Pngcs.Portable.csproj", "{CCF5E155-ECF0-4DBC-BC7C-69FE1AAAF235}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamplesTests.Portable", "SamplesTests.Portable\SamplesTests.Portable.csproj", "{FC944235-D299-4EEF-BE46-D5A83C591048}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CCF5E155-ECF0-4DBC-BC7C-69FE1AAAF235}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CCF5E155-ECF0-4DBC-BC7C-69FE1AAAF235}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CCF5E155-ECF0-4DBC-BC7C-69FE1AAAF235}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CCF5E155-ECF0-4DBC-BC7C-69FE1AAAF235}.Release|Any CPU.Build.0 = Release|Any CPU + {FC944235-D299-4EEF-BE46-D5A83C591048}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC944235-D299-4EEF-BE46-D5A83C591048}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC944235-D299-4EEF-BE46-D5A83C591048}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC944235-D299-4EEF-BE46-D5A83C591048}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal