ImageExtensions.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. using System;
  2. using System.Drawing;
  3. using System.Drawing.Drawing2D;
  4. using System.Drawing.Imaging;
  5. using System.IO;
  6. namespace MediaBrowser.Controller.Drawing
  7. {
  8. /// <summary>
  9. /// Class ImageExtensions
  10. /// </summary>
  11. public static class ImageExtensions
  12. {
  13. /// <summary>
  14. /// Saves the image.
  15. /// </summary>
  16. /// <param name="outputFormat">The output format.</param>
  17. /// <param name="image">The image.</param>
  18. /// <param name="toStream">To stream.</param>
  19. /// <param name="quality">The quality.</param>
  20. public static void Save(this Image image, ImageFormat outputFormat, Stream toStream, int quality)
  21. {
  22. // Use special save methods for jpeg and png that will result in a much higher quality image
  23. // All other formats use the generic Image.Save
  24. if (ImageFormat.Jpeg.Equals(outputFormat))
  25. {
  26. SaveAsJpeg(image, toStream, quality);
  27. }
  28. else if (ImageFormat.Png.Equals(outputFormat))
  29. {
  30. image.Save(toStream, ImageFormat.Png);
  31. }
  32. else
  33. {
  34. image.Save(toStream, outputFormat);
  35. }
  36. }
  37. /// <summary>
  38. /// Saves the JPEG.
  39. /// </summary>
  40. /// <param name="image">The image.</param>
  41. /// <param name="target">The target.</param>
  42. /// <param name="quality">The quality.</param>
  43. public static void SaveAsJpeg(this Image image, Stream target, int quality)
  44. {
  45. using (var encoderParameters = new EncoderParameters(1))
  46. {
  47. encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
  48. image.Save(target, GetImageCodecInfo("image/jpeg"), encoderParameters);
  49. }
  50. }
  51. private static readonly ImageCodecInfo[] Encoders = ImageCodecInfo.GetImageEncoders();
  52. /// <summary>
  53. /// Gets the image codec info.
  54. /// </summary>
  55. /// <param name="mimeType">Type of the MIME.</param>
  56. /// <returns>ImageCodecInfo.</returns>
  57. private static ImageCodecInfo GetImageCodecInfo(string mimeType)
  58. {
  59. foreach (var encoder in Encoders)
  60. {
  61. if (string.Equals(encoder.MimeType, mimeType, StringComparison.OrdinalIgnoreCase))
  62. {
  63. return encoder;
  64. }
  65. }
  66. return Encoders.Length == 0 ? null : Encoders[0];
  67. }
  68. /// <summary>
  69. /// Determines whether [is pixel format supported by graphics object] [the specified format].
  70. /// </summary>
  71. /// <param name="format">The format.</param>
  72. /// <returns><c>true</c> if [is pixel format supported by graphics object] [the specified format]; otherwise, <c>false</c>.</returns>
  73. public static bool IsPixelFormatSupportedByGraphicsObject(PixelFormat format)
  74. {
  75. // http://msdn.microsoft.com/en-us/library/system.drawing.graphics.fromimage.aspx
  76. if ((format & PixelFormat.Indexed) == PixelFormat.Indexed)
  77. {
  78. return false;
  79. }
  80. if ((format & PixelFormat.Undefined) == PixelFormat.Undefined)
  81. {
  82. return false;
  83. }
  84. if ((format & PixelFormat.DontCare) == PixelFormat.DontCare)
  85. {
  86. return false;
  87. }
  88. if ((format & PixelFormat.Format16bppArgb1555) == PixelFormat.Format16bppArgb1555)
  89. {
  90. return false;
  91. }
  92. if ((format & PixelFormat.Format16bppGrayScale) == PixelFormat.Format16bppGrayScale)
  93. {
  94. return false;
  95. }
  96. return true;
  97. }
  98. /// <summary>
  99. /// Crops an image by removing whitespace and transparency from the edges
  100. /// </summary>
  101. /// <param name="bmp">The BMP.</param>
  102. /// <returns>Bitmap.</returns>
  103. /// <exception cref="System.Exception"></exception>
  104. public static Bitmap CropWhitespace(this Bitmap bmp)
  105. {
  106. var width = bmp.Width;
  107. var height = bmp.Height;
  108. var topmost = 0;
  109. for (int row = 0; row < height; ++row)
  110. {
  111. if (IsAllWhiteRow(bmp, row, width))
  112. topmost = row;
  113. else break;
  114. }
  115. int bottommost = 0;
  116. for (int row = height - 1; row >= 0; --row)
  117. {
  118. if (IsAllWhiteRow(bmp, row, width))
  119. bottommost = row;
  120. else break;
  121. }
  122. int leftmost = 0, rightmost = 0;
  123. for (int col = 0; col < width; ++col)
  124. {
  125. if (IsAllWhiteColumn(bmp, col, height))
  126. leftmost = col;
  127. else
  128. break;
  129. }
  130. for (int col = width - 1; col >= 0; --col)
  131. {
  132. if (IsAllWhiteColumn(bmp, col, height))
  133. rightmost = col;
  134. else
  135. break;
  136. }
  137. if (rightmost == 0) rightmost = width; // As reached left
  138. if (bottommost == 0) bottommost = height; // As reached top.
  139. var croppedWidth = rightmost - leftmost;
  140. var croppedHeight = bottommost - topmost;
  141. if (croppedWidth == 0) // No border on left or right
  142. {
  143. leftmost = 0;
  144. croppedWidth = width;
  145. }
  146. if (croppedHeight == 0) // No border on top or bottom
  147. {
  148. topmost = 0;
  149. croppedHeight = height;
  150. }
  151. // Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here
  152. var thumbnail = bmp.PixelFormat == PixelFormat.Indexed ? new Bitmap(croppedWidth, croppedHeight) : new Bitmap(croppedWidth, croppedHeight, bmp.PixelFormat);
  153. // Preserve the original resolution
  154. thumbnail.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);
  155. using (var thumbnailGraph = Graphics.FromImage(thumbnail))
  156. {
  157. thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality;
  158. thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
  159. thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
  160. thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
  161. thumbnailGraph.CompositingMode = CompositingMode.SourceOver;
  162. thumbnailGraph.DrawImage(bmp,
  163. new RectangleF(0, 0, croppedWidth, croppedHeight),
  164. new RectangleF(leftmost, topmost, croppedWidth, croppedHeight),
  165. GraphicsUnit.Pixel);
  166. }
  167. return thumbnail;
  168. }
  169. /// <summary>
  170. /// Determines whether or not a row of pixels is all whitespace
  171. /// </summary>
  172. /// <param name="bmp">The BMP.</param>
  173. /// <param name="row">The row.</param>
  174. /// <param name="width">The width.</param>
  175. /// <returns><c>true</c> if [is all white row] [the specified BMP]; otherwise, <c>false</c>.</returns>
  176. private static bool IsAllWhiteRow(Bitmap bmp, int row, int width)
  177. {
  178. for (var i = 0; i < width; ++i)
  179. {
  180. if (!IsWhiteSpace(bmp.GetPixel(i, row)))
  181. {
  182. return false;
  183. }
  184. }
  185. return true;
  186. }
  187. /// <summary>
  188. /// Determines whether or not a column of pixels is all whitespace
  189. /// </summary>
  190. /// <param name="bmp">The BMP.</param>
  191. /// <param name="col">The col.</param>
  192. /// <param name="height">The height.</param>
  193. /// <returns><c>true</c> if [is all white column] [the specified BMP]; otherwise, <c>false</c>.</returns>
  194. private static bool IsAllWhiteColumn(Bitmap bmp, int col, int height)
  195. {
  196. for (var i = 0; i < height; ++i)
  197. {
  198. if (!IsWhiteSpace(bmp.GetPixel(col, i)))
  199. {
  200. return false;
  201. }
  202. }
  203. return true;
  204. }
  205. /// <summary>
  206. /// Determines if a color is whitespace
  207. /// </summary>
  208. /// <param name="color">The color.</param>
  209. /// <returns><c>true</c> if [is white space] [the specified color]; otherwise, <c>false</c>.</returns>
  210. private static bool IsWhiteSpace(Color color)
  211. {
  212. return (color.R == 255 && color.G == 255 && color.B == 255) || color.A == 0;
  213. }
  214. }
  215. }