ZipImage.cs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. /////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Photoshop PSD FileType Plugin for Paint.NET
  4. // http://psdplugin.codeplex.com/
  5. //
  6. // This software is provided under the MIT License:
  7. // Copyright (c) 2006-2007 Frank Blumenberg
  8. // Copyright (c) 2010-2017 Tao Yue
  9. //
  10. // See LICENSE.txt for complete licensing and attribution information.
  11. //
  12. /////////////////////////////////////////////////////////////////////////////////
  13. using System;
  14. using System.Drawing;
  15. using System.IO;
  16. using System.IO.Compression;
  17. namespace PhotoshopFile.Compression
  18. {
  19. public class ZipImage : ImageData
  20. {
  21. private MemoryStream zipDataStream;
  22. private DeflateStream zipStream;
  23. protected override bool AltersWrittenData => false;
  24. public ZipImage(byte[] data, Size size, int bitDepth)
  25. : base(size, bitDepth)
  26. {
  27. if (data == null)
  28. {
  29. InitCompress();
  30. }
  31. else
  32. {
  33. InitDecompress(data);
  34. }
  35. }
  36. private void InitCompress()
  37. {
  38. zipDataStream = new MemoryStream();
  39. // Write 2-byte zlib (RFC 1950) header
  40. //
  41. // CMF Compression Method and flags:
  42. // CM 0:3 = 8 = deflate
  43. // CINFO 4:7 = 4 = undefined, RFC 1950 only defines CINFO = 8
  44. //
  45. // FLG Flags:
  46. // FCHECK 0:4 = 9 = check bits for CMF and FLG
  47. // FDICT 5 = 0 = no preset dictionary
  48. // FLEVEL 6:7 = 2 = default compression level
  49. zipDataStream.WriteByte(0x48);
  50. zipDataStream.WriteByte(0x89);
  51. zipStream = new DeflateStream(zipDataStream, CompressionMode.Compress,
  52. true);
  53. }
  54. private void InitDecompress(byte[] data)
  55. {
  56. zipDataStream = new MemoryStream(data);
  57. // .NET implements Deflate (RFC 1951) but not zlib (RFC 1950),
  58. // so we have to skip the first two bytes.
  59. zipDataStream.ReadByte();
  60. zipDataStream.ReadByte();
  61. zipStream = new DeflateStream(zipDataStream, CompressionMode.Decompress,
  62. true);
  63. }
  64. internal override void Read(byte[] buffer)
  65. {
  66. var bytesToRead = (long)Size.Height * BytesPerRow;
  67. Util.CheckByteArrayLength(bytesToRead);
  68. var bytesRead = zipStream.Read(buffer, 0, (int)bytesToRead);
  69. if (bytesRead != bytesToRead)
  70. {
  71. throw new Exception("ZIP stream was not fully decompressed.");
  72. }
  73. }
  74. public override byte[] ReadCompressed()
  75. {
  76. // Write out the last block. (Flush leaves the last block open.)
  77. zipStream.Close();
  78. // Do not write the zlib header when the image data is empty
  79. var result = (zipDataStream.Length == 2)
  80. ? new byte[0]
  81. : zipDataStream.ToArray();
  82. return result;
  83. }
  84. internal override void WriteInternal(byte[] array)
  85. {
  86. zipStream.Write(array, 0, array.Length);
  87. }
  88. }
  89. }