aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Api/ImageProcessor.cs
blob: a798123e458a4cfa39be2751bc26be47006b3338 (plain)
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 System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

namespace MediaBrowser.Api
{
    public static class ImageProcessor
    {
        public static void ProcessImage(string path, Stream toStream, int? width, int? height, int? maxWidth, int? maxHeight, int? quality)
        {
            Image originalImage = Image.FromFile(path);

            var newWidth = originalImage.Width;
            var newHeight = originalImage.Height;

            if (width.HasValue && height.HasValue)
            {
                newWidth = width.Value;
                newHeight = height.Value;
            }

            else if (height.HasValue)
            {
                newWidth = GetNewWidth(newHeight, newWidth, height.Value);
                newHeight = height.Value;
            }

            else if (width.HasValue)
            {
                newHeight = GetNewHeight(newHeight, newWidth, width.Value);
                newWidth = width.Value;
            }

            if (maxHeight.HasValue && maxHeight < newHeight)
            {
                newWidth = GetNewWidth(newHeight, newWidth, maxHeight.Value);
                newHeight = maxHeight.Value;
            }

            if (maxWidth.HasValue && maxWidth < newWidth)
            {
                newHeight = GetNewHeight(newHeight, newWidth, maxWidth.Value);
                newWidth = maxWidth.Value;
            }

            Bitmap thumbnail = new Bitmap(newWidth, newHeight, originalImage.PixelFormat);
            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, newWidth, newHeight);

            Write(originalImage, thumbnail, toStream, quality);

            thumbnailGraph.Dispose();
            thumbnail.Dispose();
            originalImage.Dispose();
        }
        
        private static void Write(Image originalImage, 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(originalImage.RawFormat))
            {
                SaveJpeg(newImage, toStream, quality);
            }
            else if (ImageFormat.Png.Equals(originalImage.RawFormat))
            {
                SavePng(newImage, toStream);
            }
            else
            {
                newImage.Save(toStream, originalImage.RawFormat);
            }
        }

        private static void SaveJpeg(Image newImage, Stream target, int? quality)
        {
            if (!quality.HasValue)
            {
                quality = 90;
            }

            using (EncoderParameters encoderParameters = new EncoderParameters(1))
            {
                encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality.Value);
                newImage.Save(target, GetImageCodeInfo("image/jpeg"), encoderParameters);
            }
        }

        private static void SavePng(Image newImage, Stream target)
        {
            if (target.CanSeek)
            {
                newImage.Save(target, ImageFormat.Png);
            }
            else
            {
                using (MemoryStream ms = new MemoryStream(4096))
                {
                    newImage.Save(ms, ImageFormat.Png);
                    ms.WriteTo(target);
                }
            }
        }

        private static ImageCodecInfo GetImageCodeInfo(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];
        }

        private static int GetNewWidth(int currentHeight, int currentWidth, int newHeight)
        {
            decimal scaleFactor = newHeight;
            scaleFactor /= currentHeight;
            scaleFactor *= currentWidth;

            return Convert.ToInt32(scaleFactor);
        }

        private static int GetNewHeight(int currentHeight, int currentWidth, int newWidth)
        {
            decimal scaleFactor = newWidth;
            scaleFactor /= currentWidth;
            scaleFactor *= currentHeight;

            return Convert.ToInt32(scaleFactor);
        }
    }
}