PageRenderTime 40ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Data/PngFileType.cs

https://bitbucket.org/tuldok89/openpdn
C# | 241 lines | 195 code | 35 blank | 11 comment | 3 complexity | d64d908f0517b23d17770d63dfb82739 MD5 | raw file
  1. /////////////////////////////////////////////////////////////////////////////////
  2. // Paint.NET //
  3. // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. //
  4. // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
  5. // See src/Resources/Files/License.txt for full licensing and attribution //
  6. // details. //
  7. // . //
  8. /////////////////////////////////////////////////////////////////////////////////
  9. using PaintDotNet.Base;
  10. using PaintDotNet.Base.PropertySystem;
  11. using PaintDotNet.IndirectUI;
  12. using System.Collections.Generic;
  13. using System.ComponentModel;
  14. using System.Drawing;
  15. using System.Drawing.Imaging;
  16. using System.IO;
  17. namespace PaintDotNet
  18. {
  19. public sealed class PngFileType
  20. : InternalFileType
  21. {
  22. protected override bool IsReflexive(PropertyBasedSaveConfigToken token)
  23. {
  24. var bitDepth = (PngBitDepthUIChoices)token.GetProperty<StaticListChoiceProperty>(PropertyNames.BitDepth).Value;
  25. // Only 32-bit is reflexive
  26. return (bitDepth == PngBitDepthUIChoices.Bpp32);
  27. }
  28. public PngFileType()
  29. : base("PNG", FileTypeFlags.SupportsLoading | FileTypeFlags.SupportsSaving, new[] { ".png" })
  30. {
  31. }
  32. public enum PropertyNames
  33. {
  34. BitDepth = 0,
  35. DitherLevel = 1,
  36. Threshold = 2
  37. }
  38. public enum PngBitDepthUIChoices
  39. {
  40. AutoDetect = 0,
  41. Bpp32 = 1,
  42. Bpp24 = 2,
  43. Bpp8 = 3
  44. }
  45. public override ControlInfo OnCreateSaveConfigUI(PropertyCollection props)
  46. {
  47. ControlInfo configUI = CreateDefaultSaveConfigUI(props);
  48. configUI.SetPropertyControlValue(
  49. PropertyNames.BitDepth,
  50. ControlInfoPropertyNames.DisplayName,
  51. PdnResources.GetString("PngFileType.ConfigUI.BitDepth.DisplayName"));
  52. PropertyControlInfo bitDepthPCI = configUI.FindControlForPropertyName(PropertyNames.BitDepth);
  53. bitDepthPCI.SetValueDisplayName(PngBitDepthUIChoices.AutoDetect, PdnResources.GetString("PngFileType.ConfigUI.BitDepth.AutoDetect.DisplayName"));
  54. bitDepthPCI.SetValueDisplayName(PngBitDepthUIChoices.Bpp32, PdnResources.GetString("PngFileType.ConfigUI.BitDepth.Bpp32.DisplayName"));
  55. bitDepthPCI.SetValueDisplayName(PngBitDepthUIChoices.Bpp24, PdnResources.GetString("PngFileType.ConfigUI.BitDepth.Bpp24.DisplayName"));
  56. bitDepthPCI.SetValueDisplayName(PngBitDepthUIChoices.Bpp8, PdnResources.GetString("PngFileType.ConfigUI.BitDepth.Bpp8.DisplayName"));
  57. configUI.SetPropertyControlType(PropertyNames.BitDepth, PropertyControlType.RadioButton);
  58. configUI.SetPropertyControlValue(
  59. PropertyNames.DitherLevel,
  60. ControlInfoPropertyNames.DisplayName,
  61. PdnResources.GetString("PngFileType.ConfigUI.DitherLevel.DisplayName"));
  62. configUI.SetPropertyControlValue(
  63. PropertyNames.Threshold,
  64. ControlInfoPropertyNames.DisplayName,
  65. PdnResources.GetString("PngFileType.ConfigUI.Threshold.DisplayName"));
  66. configUI.SetPropertyControlValue(
  67. PropertyNames.Threshold,
  68. ControlInfoPropertyNames.Description,
  69. PdnResources.GetString("PngFileType.ConfigUI.Threshold.Description"));
  70. return configUI;
  71. }
  72. public override PropertyCollection OnCreateSavePropertyCollection()
  73. {
  74. var props = new List<Property>
  75. {
  76. StaticListChoiceProperty.CreateForEnum(PropertyNames.BitDepth,
  77. PngBitDepthUIChoices.
  78. AutoDetect, false),
  79. new Int32Property(PropertyNames.DitherLevel, 7, 0, 8),
  80. new Int32Property(PropertyNames.Threshold, 128, 0, 255)
  81. };
  82. var rules = new List<PropertyCollectionRule>
  83. {
  84. new ReadOnlyBoundToValueRule<object, StaticListChoiceProperty>(
  85. PropertyNames.Threshold,
  86. PropertyNames.BitDepth,
  87. PngBitDepthUIChoices.Bpp8,
  88. true),
  89. new ReadOnlyBoundToValueRule<object, StaticListChoiceProperty>(
  90. PropertyNames.DitherLevel,
  91. PropertyNames.BitDepth,
  92. PngBitDepthUIChoices.Bpp8,
  93. true)
  94. };
  95. var pc = new PropertyCollection(props, rules);
  96. return pc;
  97. }
  98. protected override Document OnLoad(Stream input)
  99. {
  100. using (Image image = PdnResources.LoadImage(input))
  101. {
  102. Document document = Document.FromImage(image);
  103. return document;
  104. }
  105. }
  106. internal override Set<SavableBitDepths> CreateAllowedBitDepthListFromToken(PropertyBasedSaveConfigToken token)
  107. {
  108. var bitDepthFromToken = (PngBitDepthUIChoices)token.GetProperty<StaticListChoiceProperty>(PropertyNames.BitDepth).Value;
  109. var bitDepths = new Set<SavableBitDepths>();
  110. switch (bitDepthFromToken)
  111. {
  112. case PngBitDepthUIChoices.AutoDetect:
  113. bitDepths.AddRange(SavableBitDepths.Rgb24, SavableBitDepths.Rgb8, SavableBitDepths.Rgba32, SavableBitDepths.Rgba8);
  114. break;
  115. case PngBitDepthUIChoices.Bpp24:
  116. bitDepths.AddRange(SavableBitDepths.Rgb24);
  117. break;
  118. case PngBitDepthUIChoices.Bpp32:
  119. bitDepths.AddRange(SavableBitDepths.Rgba32);
  120. break;
  121. case PngBitDepthUIChoices.Bpp8:
  122. bitDepths.AddRange(SavableBitDepths.Rgb8, SavableBitDepths.Rgba8);
  123. break;
  124. default:
  125. throw new InvalidEnumArgumentException("bitDepthFromToken", (int)bitDepthFromToken, typeof(PngBitDepthUIChoices));
  126. }
  127. return bitDepths;
  128. }
  129. internal override int GetThresholdFromToken(PropertyBasedSaveConfigToken token)
  130. {
  131. int threshold = token.GetProperty<Int32Property>(PropertyNames.Threshold).Value;
  132. return threshold;
  133. }
  134. internal override int GetDitherLevelFromToken(PropertyBasedSaveConfigToken token)
  135. {
  136. int ditherLevel = token.GetProperty<Int32Property>(PropertyNames.DitherLevel).Value;
  137. return ditherLevel;
  138. }
  139. internal override void FinalSave(
  140. Document input,
  141. Stream output,
  142. Surface scratchSurface,
  143. int ditherLevel,
  144. SavableBitDepths bitDepth,
  145. PropertyBasedSaveConfigToken token,
  146. ProgressEventHandler progressCallback)
  147. {
  148. switch (bitDepth)
  149. {
  150. case SavableBitDepths.Rgba32:
  151. {
  152. ImageCodecInfo icf = GdiPlusFileType.GetImageCodecInfo(ImageFormat.Png);
  153. var parms = new EncoderParameters(1);
  154. var parm = new EncoderParameter(Encoder.ColorDepth, 32);
  155. parms.Param[0] = parm;
  156. using (Bitmap bitmap = scratchSurface.CreateAliasedBitmap())
  157. {
  158. GdiPlusFileType.LoadProperties(bitmap, input);
  159. bitmap.Save(output, icf, parms);
  160. }
  161. }
  162. break;
  163. case SavableBitDepths.Rgb24:
  164. {
  165. // In order to save memory, we 'squish' the 32-bit bitmap down to 24-bit in-place
  166. // instead of allocating a new bitmap and copying it over.
  167. SquishSurfaceTo24Bpp(scratchSurface);
  168. ImageCodecInfo icf = GdiPlusFileType.GetImageCodecInfo(ImageFormat.Png);
  169. var parms = new EncoderParameters(1);
  170. var parm = new EncoderParameter(Encoder.ColorDepth, 24);
  171. parms.Param[0] = parm;
  172. using (Bitmap bitmap = CreateAliased24BppBitmap(scratchSurface))
  173. {
  174. GdiPlusFileType.LoadProperties(bitmap, input);
  175. bitmap.Save(output, icf, parms);
  176. }
  177. }
  178. break;
  179. case SavableBitDepths.Rgb8:
  180. using (Bitmap quantized = Quantize(scratchSurface, ditherLevel, 256, false, progressCallback))
  181. {
  182. ImageCodecInfo icf = GdiPlusFileType.GetImageCodecInfo(ImageFormat.Png);
  183. var parms = new EncoderParameters(1);
  184. var parm = new EncoderParameter(Encoder.ColorDepth, 8);
  185. parms.Param[0] = parm;
  186. GdiPlusFileType.LoadProperties(quantized, input);
  187. quantized.Save(output, icf, parms);
  188. }
  189. break;
  190. case SavableBitDepths.Rgba8:
  191. using (Bitmap quantized = Quantize(scratchSurface, ditherLevel, 256, true, progressCallback))
  192. {
  193. ImageCodecInfo icf = GdiPlusFileType.GetImageCodecInfo(ImageFormat.Png);
  194. var parms = new EncoderParameters(1);
  195. var parm = new EncoderParameter(Encoder.ColorDepth, 8);
  196. parms.Param[0] = parm;
  197. GdiPlusFileType.LoadProperties(quantized, input);
  198. quantized.Save(output, icf, parms);
  199. }
  200. break;
  201. default:
  202. throw new InvalidEnumArgumentException("bitDepth", (int)bitDepth, typeof(SavableBitDepths));
  203. }
  204. }
  205. }
  206. }