diff --git a/.gitignore b/.gitignore index 1350c51..163f6dc 100755 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ Debug *.suo packages *.user +.vs/ +*.lock.json TestResults */App_Data/user_uploads PublishProfiles diff --git a/PNGDecrush/BinaryReaderNetworkHostOrderAdditions.cs b/PNGDecrush/BinaryReaderNetworkHostOrderAdditions.cs index 5bda781..39e57e3 100755 --- a/PNGDecrush/BinaryReaderNetworkHostOrderAdditions.cs +++ b/PNGDecrush/BinaryReaderNetworkHostOrderAdditions.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Web; +using System.IO; namespace PNGDecrush { diff --git a/PNGDecrush/CRC32.cs b/PNGDecrush/CRC32.cs new file mode 100644 index 0000000..5d7c2bb --- /dev/null +++ b/PNGDecrush/CRC32.cs @@ -0,0 +1,225 @@ +// CRC32.cs +// ------------------------------------------------------------------ +// +// Copyright (c) 2011 Dino Chiesa. +// All rights reserved. +// +// This code module is part of DotNetZip, a zipfile class library. +// +// ------------------------------------------------------------------ +// +// This code is licensed under the Microsoft Public License. +// See the file License.txt for the license details. +// More info on: http://dotnetzip.codeplex.com +// +// ------------------------------------------------------------------ +// +// Last Saved: <2011-August-02 18:25:54> +// +// ------------------------------------------------------------------ +// +// This module defines the CRC32 class, which can do the CRC32 algorithm, using +// arbitrary starting polynomials, and bit reversal. The bit reversal is what +// distinguishes this CRC-32 used in BZip2 from the CRC-32 that is used in PKZIP +// files, or GZIP files. This class does both. +// +// ------------------------------------------------------------------ + + +using System; +using Interop = System.Runtime.InteropServices; + +namespace Ionic.Crc +{ + /// + /// Computes a CRC-32. The CRC-32 algorithm is parameterized - you + /// can set the polynomial and enable or disable bit + /// reversal. This can be used for GZIP, BZip2, or ZIP. + /// + /// + /// This type is used internally by DotNetZip; it is generally not used + /// directly by applications wishing to create, read, or manipulate zip + /// archive files. + /// + + [Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000C")] + [Interop.ComVisible(true)] +#if !NETCF + [Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)] +#endif + public class CRC32 + { + /// + /// Indicates the current CRC for all blocks slurped in. + /// + public Int32 Crc32Result + { + get + { + return unchecked((Int32)(~_register)); + } + } + + /// + /// Update the value for the running CRC32 using the given block of bytes. + /// This is useful when using the CRC32() class in a Stream. + /// + /// block of bytes to slurp + /// starting point in the block + /// how many bytes within the block to slurp + public void SlurpBlock(byte[] block, int offset, int count) + { + if (block == null) + throw new Exception("The data buffer must not be null."); + + // bzip algorithm + for (int i = 0; i < count; i++) + { + int x = offset + i; + byte b = block[x]; + if (this.reverseBits) + { + UInt32 temp = (_register >> 24) ^ b; + _register = (_register << 8) ^ crc32Table[temp]; + } + else + { + UInt32 temp = (_register & 0x000000FF) ^ b; + _register = (_register >> 8) ^ crc32Table[temp]; + } + } + _TotalBytesRead += count; + } + + private static uint ReverseBits(uint data) + { + unchecked + { + uint ret = data; + ret = (ret & 0x55555555) << 1 | (ret >> 1) & 0x55555555; + ret = (ret & 0x33333333) << 2 | (ret >> 2) & 0x33333333; + ret = (ret & 0x0F0F0F0F) << 4 | (ret >> 4) & 0x0F0F0F0F; + ret = (ret << 24) | ((ret & 0xFF00) << 8) | ((ret >> 8) & 0xFF00) | (ret >> 24); + return ret; + } + } + + private static byte ReverseBits(byte data) + { + unchecked + { + uint u = (uint)data * 0x00020202; + uint m = 0x01044010; + uint s = u & m; + uint t = (u << 2) & (m << 1); + return (byte)((0x01001001 * (s + t)) >> 24); + } + } + + + + private void GenerateLookupTable() + { + crc32Table = new UInt32[256]; + unchecked + { + UInt32 dwCrc; + byte i = 0; + do + { + dwCrc = i; + for (byte j = 8; j > 0; j--) + { + if ((dwCrc & 1) == 1) + { + dwCrc = (dwCrc >> 1) ^ dwPolynomial; + } + else + { + dwCrc >>= 1; + } + } + if (reverseBits) + { + crc32Table[ReverseBits(i)] = ReverseBits(dwCrc); + } + else + { + crc32Table[i] = dwCrc; + } + i++; + } while (i!=0); + } + } + + /// + /// Create an instance of the CRC32 class using the default settings: no + /// bit reversal, and a polynomial of 0xEDB88320. + /// + public CRC32() : this(false) + { + } + + /// + /// Create an instance of the CRC32 class, specifying whether to reverse + /// data bits or not. + /// + /// + /// specify true if the instance should reverse data bits. + /// + /// + /// + /// In the CRC-32 used by BZip2, the bits are reversed. Therefore if you + /// want a CRC32 with compatibility with BZip2, you should pass true + /// here. In the CRC-32 used by GZIP and PKZIP, the bits are not + /// reversed; Therefore if you want a CRC32 with compatibility with + /// those, you should pass false. + /// + /// + public CRC32(bool reverseBits) : + this( unchecked((int)0xEDB88320), reverseBits) + { + } + + + /// + /// Create an instance of the CRC32 class, specifying the polynomial and + /// whether to reverse data bits or not. + /// + /// + /// The polynomial to use for the CRC, expressed in the reversed (LSB) + /// format: the highest ordered bit in the polynomial value is the + /// coefficient of the 0th power; the second-highest order bit is the + /// coefficient of the 1 power, and so on. Expressed this way, the + /// polynomial for the CRC-32C used in IEEE 802.3, is 0xEDB88320. + /// + /// + /// specify true if the instance should reverse data bits. + /// + /// + /// + /// + /// In the CRC-32 used by BZip2, the bits are reversed. Therefore if you + /// want a CRC32 with compatibility with BZip2, you should pass true + /// here for the reverseBits parameter. In the CRC-32 used by + /// GZIP and PKZIP, the bits are not reversed; Therefore if you want a + /// CRC32 with compatibility with those, you should pass false for the + /// reverseBits parameter. + /// + /// + public CRC32(int polynomial, bool reverseBits) + { + this.reverseBits = reverseBits; + this.dwPolynomial = (uint) polynomial; + this.GenerateLookupTable(); + } + + // private member vars + private UInt32 dwPolynomial; + private Int64 _TotalBytesRead; + private bool reverseBits; + private UInt32[] crc32Table; + private const int BUFFER_SIZE = 8192; + private UInt32 _register = 0xFFFFFFFFU; + } +} \ No newline at end of file diff --git a/PNGDecrush/NuGet.config b/PNGDecrush/NuGet.config new file mode 100644 index 0000000..1cfaa82 --- /dev/null +++ b/PNGDecrush/NuGet.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/PNGDecrush/PNGChunk.cs b/PNGDecrush/PNGChunk.cs index cae6365..ff5997f 100755 --- a/PNGDecrush/PNGChunk.cs +++ b/PNGDecrush/PNGChunk.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; - -namespace PNGDecrush +namespace PNGDecrush { public class PNGChunk { diff --git a/PNGDecrush/PNGChunkParser.cs b/PNGDecrush/PNGChunkParser.cs index 67eeb47..b128b85 100755 --- a/PNGDecrush/PNGChunkParser.cs +++ b/PNGDecrush/PNGChunkParser.cs @@ -2,9 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; -using System.Web; namespace PNGDecrush { diff --git a/PNGDecrush/PNGDecrush.csproj b/PNGDecrush/PNGDecrush.csproj old mode 100755 new mode 100644 index 5aebf89..3918d30 --- a/PNGDecrush/PNGDecrush.csproj +++ b/PNGDecrush/PNGDecrush.csproj @@ -1,63 +1,28 @@ - - - + + - Debug - AnyCPU - {447066CB-DDC0-41C2-90F2-84F056786CC7} - Library - Properties - PNGDecrush - PNGDecrush - v4.5 - 512 + netcoreapp2.0;net45;netstandard1.3 + PNGDecrush is a C# library for reversing the optimization process that is applied to PNG files in an iOS project. + Mike Weller + Mike Weller + PNGDecrush - Decrush iOS PNG files + PNGDecrush - Decrush iOS PNG files + https://github.com/MikeWeller/PNGDecrush/ + https://github.com/MikeWeller/PNGDecrush/blob/master/LICENSE + true + PNGDecrush.snk + 1.0.1 - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - packages\DotNetZip.1.9.1.8\lib\net20\Ionic.Zip.dll - - - - - - - - - + + + - - - - - - + + + + - + - - - \ No newline at end of file + diff --git a/PNGDecrush/PNGDecrush.snk b/PNGDecrush/PNGDecrush.snk new file mode 100644 index 0000000..0d43480 Binary files /dev/null and b/PNGDecrush/PNGDecrush.snk differ diff --git a/PNGDecrush/PNGDecrusher.cs b/PNGDecrush/PNGDecrusher.cs index 460f068..cdd5567 100755 --- a/PNGDecrush/PNGDecrusher.cs +++ b/PNGDecrush/PNGDecrusher.cs @@ -1,4 +1,4 @@ -using Ionic.Zlib; +using Ionic.Crc; using System; using System.Collections.Generic; using System.Drawing; @@ -6,8 +6,8 @@ using System.IO; using System.IO.Compression; using System.Linq; +using System.Net; using System.Text; -using System.Web; namespace PNGDecrush { @@ -36,8 +36,8 @@ public static IEnumerable DecrushChunks(IEnumerable chunks) { throw new InvalidDataException("Could not find a CgBI chunk. Image wasn't crushed with Apple's -iohone option."); } - - return ConvertIDATChunksFromDeflateToZlib(chunksWithoutAppleChunk);; + + return ConvertIDATChunksFromDeflateToZlib(chunksWithoutAppleChunk); ; } private static IEnumerable ConvertIDATChunksFromDeflateToZlib(IEnumerable inputChunks) @@ -135,14 +135,72 @@ private static byte[] CombinedDataFromChunks(IEnumerable chunks) private static byte[] ConvertDeflateToZlib(byte[] input) { - using (MemoryStream deflateData = new MemoryStream(input)) - using (System.IO.Compression.DeflateStream deflateStream = new System.IO.Compression.DeflateStream(deflateData, System.IO.Compression.CompressionMode.Decompress)) - using (ZlibStream zlibStream = new ZlibStream(deflateStream, Ionic.Zlib.CompressionMode.Compress)) - using (MemoryStream zlibData = new MemoryStream()) + // Basically, we wrap the deflate stram in a zlib format. + // Because zlib includes a checksum of the decompressed data, + // we need to decompress all data. + + // The zlib format is as follows: + // zlib format (wrapper around the deflate format): + // +---+---+ + // |CMF|FLG| (2 bytes) + // +---+---+ + // +---+---+---+---+ + // | DICTID | (4 bytes. Present only when FLG.FDICT is set.) - Mostly not set + // +---+---+---+---+ + // +=====================+ + // |...compressed data...| (variable size of data) + // +=====================+ + // +---+---+---+---+ + // | ADLER32 | (4 bytes of checksum) + // +---+---+---+---+ + // + // +---+---+ + // |CMF|FLG| + // +---+---+ + // + // 78 01 - No Compression/low + // 78 9C - Default Compression + // 78 DA - Best Compression + + byte[] bytes; + + using (MemoryStream compressedData = new MemoryStream(input)) + using (DeflateStream deflateStream = new DeflateStream(compressedData, CompressionMode.Decompress)) + using (MemoryStream decompressedData = new MemoryStream()) + { + // Decompress all data + deflateStream.CopyTo(decompressedData); + bytes = decompressedData.ToArray(); + } + + using (MemoryStream recompressedData = new MemoryStream()) + { + recompressedData.WriteByte(0x78); + recompressedData.WriteByte(0x9C); + using (var compressor = new DeflateStream(recompressedData, CompressionMode.Compress, true)) + { + compressor.Write(bytes, 0, bytes.Length); + compressor.Flush(); + } + + recompressedData.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(Adler32(bytes))), 0, sizeof(uint)); + + return recompressedData.ToArray(); + } + } + + + // naive implementation of adler-32 checksum + static int Adler32(byte[] bytes) + { + const uint a32mod = 65521; + uint s1 = 1, s2 = 0; + foreach (byte b in bytes) { - zlibStream.CopyTo(zlibData); - return zlibData.ToArray(); + s1 = (s1 + b) % a32mod; + s2 = (s2 + s1) % a32mod; } + return unchecked((int)((s2 << 16) + s1)); } private static IEnumerable ChunksByRemovingAppleCgBIChunks(IEnumerable chunks) @@ -154,7 +212,7 @@ public static uint CalculateCRCForChunk(string chunkType, byte[] chunkData) { byte[] chunkTypeBytes = Encoding.UTF8.GetBytes(chunkType); - Ionic.Crc.CRC32 crc32calculator = new Ionic.Crc.CRC32(); + CRC32 crc32calculator = new CRC32(); crc32calculator.SlurpBlock(chunkTypeBytes, 0, chunkTypeBytes.Length); crc32calculator.SlurpBlock(chunkData, 0, chunkData.Length); @@ -260,4 +318,4 @@ private static void ReversePremultipliedAlpha(byte[] pixelData, uint startOffset pixelData[startOffset + 2] = (byte)((pixelData[startOffset + 2] * 255) / alpha); } } -} \ No newline at end of file +} diff --git a/PNGDecrush/Properties/AssemblyInfo.cs b/PNGDecrush/Properties/AssemblyInfo.cs deleted file mode 100755 index beee41d..0000000 --- a/PNGDecrush/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("PNGDecrush")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("PNGDecrush")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("4a3f1a2a-4d23-4f20-a67a-d411b0a7f457")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PNGDecrush/packages.config b/PNGDecrush/packages.config deleted file mode 100755 index 2a946e0..0000000 --- a/PNGDecrush/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/PNGDecrush/project.json b/PNGDecrush/project.json new file mode 100644 index 0000000..c0e68b0 --- /dev/null +++ b/PNGDecrush/project.json @@ -0,0 +1,42 @@ +{ + "version": "1.0.0-*", + + "authors": [ "Mike Weller" ], + "title": "PNGDecrush - Decrush iOS PNG files", + "description": "PNGDecrush is a C# library for reversing the optimization process that is applied to PNG files in an iOS project.", + + "packOptions": { + "licenseUrl": "https://github.com/MikeWeller/PNGDecrush/blob/master/LICENSE", + "owners": [ "Mike Weller" ], + "repository": { + "type": "git", + "url": "https://github.com/MikeWeller/PNGDecrush/" + }, + }, + + "dependencies": { + }, + + "buildOptions": { + "keyFile": "PNGDecrush.snk", + "strongName": true + }, + + + "frameworks": { + "netstandard1.3": { + "dependencies": { + "CoreCompat.System.Drawing": "1.0.0-beta006", + "System.IO.Compression": "4.1.0", + "System.Linq": "4.1.0", + "System.Net.Primitives": "4.0.11" + } + }, + + "net45": { + "frameworkAssemblies": { + "System.Drawing": "4.0.0.0" + } + } + } +} diff --git a/PNGDecrushTests/PNGDecrushTests.csproj b/PNGDecrushTests/PNGDecrushTests.csproj index 1d76a85..aa52e67 100755 --- a/PNGDecrushTests/PNGDecrushTests.csproj +++ b/PNGDecrushTests/PNGDecrushTests.csproj @@ -1,96 +1,23 @@ - - + + - Debug - AnyCPU - {B58EE7E0-77FE-44B3-9867-898D23408804} - Library - Properties - PNGDecrushTests - PNGDecrushTests - v4.5 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest + netcoreapp2.0 + + false - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\PNGDecrush\packages\DotNetZip.1.9.1.8\lib\net20\Ionic.Zip.dll - - - - - - - - - - - - - - - - + - - + + + + - + + - - {447066cb-ddc0-41c2-90f2-84f056786cc7} - PNGDecrush - + - - - - - False - - - False - - - False - - - False - - - - - - - - \ No newline at end of file + + diff --git a/PNGDecrushTests/Properties/AssemblyInfo.cs b/PNGDecrushTests/Properties/AssemblyInfo.cs deleted file mode 100755 index d021f23..0000000 --- a/PNGDecrushTests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("PNGDecrushTests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("PNGDecrushTests")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("51e51633-f7af-47ca-806b-cfa2256ad6d7")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PNGDecrushTests/packages.config b/PNGDecrushTests/packages.config deleted file mode 100755 index 2a946e0..0000000 --- a/PNGDecrushTests/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..2f05c32 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,8 @@ +image: Previous Visual Studio 2017 + +build_script: + - cmd: cd PNGDecrush + - cmd: dotnet restore + - cmd: dotnet build -c Release --version-suffix r%APPVEYOR_BUILD_NUMBER% + - cmd: dotnet pack -c Release --version-suffix r%APPVEYOR_BUILD_NUMBER% + - ps: Push-AppveyorArtifact "bin\Release\PNGDecrush.1.0.1-r$($env:APPVEYOR_BUILD_NUMBER).nupkg"