1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Entities;
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
namespace MediaBrowser.Controller.Drawing
{
public static class ImageProcessor
{
/// <summary>
/// Processes an image by resizing to target dimensions
/// </summary>
/// <param name="entity">The entity that owns the image</param>
/// <param name="imageType">The image type</param>
/// <param name="imageIndex">The image index (currently only used with backdrops)</param>
/// <param name="toStream">The stream to save the new image to</param>
/// <param name="width">Use if a fixed width is required. Aspect ratio will be preserved.</param>
/// <param name="height">Use if a fixed height is required. Aspect ratio will be preserved.</param>
/// <param name="maxWidth">Use if a max width is required. Aspect ratio will be preserved.</param>
/// <param name="maxHeight">Use if a max height is required. Aspect ratio will be preserved.</param>
/// <param name="quality">Quality level, from 0-100. Currently only applies to JPG. The default value should suffice.</param>
public static void ProcessImage(BaseEntity entity, ImageType imageType, int imageIndex, Stream toStream, int? width, int? height, int? maxWidth, int? maxHeight, int? quality)
{
Image originalImage = Image.FromFile(GetImagePath(entity, imageType, imageIndex));
// Determine the output size based on incoming parameters
Size newSize = DrawingUtils.Resize(originalImage.Size, width, height, maxWidth, maxHeight);
Bitmap thumbnail;
// Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here
if (originalImage.PixelFormat.HasFlag(PixelFormat.Indexed))
{
thumbnail = new Bitmap(originalImage, newSize.Width, newSize.Height);
}
else
{
thumbnail = new Bitmap(newSize.Width, newSize.Height, originalImage.PixelFormat);
}
thumbnail.MakeTransparent();
// Preserve the original resolution
thumbnail.SetResolution(originalImage.HorizontalResolution, originalImage.VerticalResolution);
Graphics thumbnailGraph = Graphics.FromImage(thumbnail);
thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality;
thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
thumbnailGraph.CompositingMode = CompositingMode.SourceOver;
thumbnailGraph.DrawImage(originalImage, 0, 0, newSize.Width, newSize.Height);
ImageFormat outputFormat = originalImage.RawFormat;
// Write to the output stream
SaveImage(outputFormat, thumbnail, toStream, quality);
thumbnailGraph.Dispose();
thumbnail.Dispose();
originalImage.Dispose();
}
public static string GetImagePath(BaseEntity entity, ImageType imageType, int imageIndex)
{
var item = entity as BaseItem;
if (item != null)
{
if (imageType == ImageType.Logo)
{
return item.LogoImagePath;
}
if (imageType == ImageType.Backdrop)
{
return item.BackdropImagePaths.ElementAt(imageIndex);
}
if (imageType == ImageType.Banner)
{
return item.BannerImagePath;
}
if (imageType == ImageType.Art)
{
return item.ArtImagePath;
}
if (imageType == ImageType.Thumbnail)
{
return item.ThumbnailImagePath;
}
}
return entity.PrimaryImagePath;
}
public static void SaveImage(ImageFormat outputFormat, Image newImage, Stream toStream, int? quality)
{
// Use special save methods for jpeg and png that will result in a much higher quality image
// All other formats use the generic Image.Save
if (ImageFormat.Jpeg.Equals(outputFormat))
{
SaveJpeg(newImage, toStream, quality);
}
else if (ImageFormat.Png.Equals(outputFormat))
{
newImage.Save(toStream, ImageFormat.Png);
}
else
{
newImage.Save(toStream, outputFormat);
}
}
public static void SaveJpeg(Image image, Stream target, int? quality)
{
if (!quality.HasValue)
{
quality = 90;
}
using (var encoderParameters = new EncoderParameters(1))
{
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality.Value);
image.Save(target, GetImageCodecInfo("image/jpeg"), encoderParameters);
}
}
public static ImageCodecInfo GetImageCodecInfo(string mimeType)
{
ImageCodecInfo[] info = ImageCodecInfo.GetImageEncoders();
for (int i = 0; i < info.Length; i++)
{
ImageCodecInfo ici = info[i];
if (ici.MimeType.Equals(mimeType, StringComparison.OrdinalIgnoreCase))
{
return ici;
}
}
return info[1];
}
}
}
|