From 4820fe80971c83cde97a445e45b9e0b1952b0d90 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 8 Apr 2015 10:38:02 -0400 Subject: added drawing project --- Emby.Drawing/Common/ImageHeader.cs | 223 +++++++++ Emby.Drawing/Emby.Drawing.csproj | 34 +- Emby.Drawing/GDI/GDIImageEncoder.cs | 233 +++++++++ Emby.Drawing/GDI/ImageExtensions.cs | 217 +++++++++ Emby.Drawing/GDI/PercentPlayedDrawer.cs | 34 ++ Emby.Drawing/GDI/PlayedIndicatorDrawer.cs | 32 ++ Emby.Drawing/GDI/UnplayedCountIndicator.cs | 50 ++ Emby.Drawing/IImageEncoder.cs | 48 ++ Emby.Drawing/ImageHeader.cs | 223 --------- Emby.Drawing/ImageMagick/ImageMagickEncoder.cs | 224 +++++++++ Emby.Drawing/ImageMagick/PercentPlayedDrawer.cs | 40 ++ Emby.Drawing/ImageMagick/PlayedIndicatorDrawer.cs | 86 ++++ Emby.Drawing/ImageMagick/StripCollageBuilder.cs | 518 +++++++++++++++++++++ Emby.Drawing/ImageMagick/UnplayedCountIndicator.cs | 70 +++ Emby.Drawing/ImageProcessor.cs | 153 +----- Emby.Drawing/PercentPlayedDrawer.cs | 40 -- Emby.Drawing/PlayedIndicatorDrawer.cs | 86 ---- Emby.Drawing/UnplayedCountIndicator.cs | 70 --- MediaBrowser.Controller/Drawing/IImageProcessor.cs | 12 + .../Drawing/ImageCollageOptions.cs | 32 ++ .../MediaBrowser.Controller.csproj | 1 + .../Collections/CollectionImageProvider.cs | 3 +- .../Library/Resolvers/PhotoAlbumResolver.cs | 13 +- .../Library/Resolvers/PhotoResolver.cs | 18 +- .../MediaBrowser.Server.Implementations.csproj | 2 - .../Photos/BaseDynamicImageProvider.cs | 63 ++- .../Photos/DynamicImageHelpers.cs | 132 ------ .../Photos/PhotoAlbumImageProvider.cs | 3 +- .../Playlists/PlaylistImageProvider.cs | 3 +- .../UserViews/DynamicImageProvider.cs | 20 +- .../UserViews/StripCollageBuilder.cs | 512 -------------------- .../ApplicationHost.cs | 25 +- MediaBrowser.ServerApplication/MainStartup.cs | 1 - 33 files changed, 1972 insertions(+), 1249 deletions(-) create mode 100644 Emby.Drawing/Common/ImageHeader.cs create mode 100644 Emby.Drawing/GDI/GDIImageEncoder.cs create mode 100644 Emby.Drawing/GDI/ImageExtensions.cs create mode 100644 Emby.Drawing/GDI/PercentPlayedDrawer.cs create mode 100644 Emby.Drawing/GDI/PlayedIndicatorDrawer.cs create mode 100644 Emby.Drawing/GDI/UnplayedCountIndicator.cs create mode 100644 Emby.Drawing/IImageEncoder.cs delete mode 100644 Emby.Drawing/ImageHeader.cs create mode 100644 Emby.Drawing/ImageMagick/ImageMagickEncoder.cs create mode 100644 Emby.Drawing/ImageMagick/PercentPlayedDrawer.cs create mode 100644 Emby.Drawing/ImageMagick/PlayedIndicatorDrawer.cs create mode 100644 Emby.Drawing/ImageMagick/StripCollageBuilder.cs create mode 100644 Emby.Drawing/ImageMagick/UnplayedCountIndicator.cs delete mode 100644 Emby.Drawing/PercentPlayedDrawer.cs delete mode 100644 Emby.Drawing/PlayedIndicatorDrawer.cs delete mode 100644 Emby.Drawing/UnplayedCountIndicator.cs create mode 100644 MediaBrowser.Controller/Drawing/ImageCollageOptions.cs delete mode 100644 MediaBrowser.Server.Implementations/Photos/DynamicImageHelpers.cs delete mode 100644 MediaBrowser.Server.Implementations/UserViews/StripCollageBuilder.cs diff --git a/Emby.Drawing/Common/ImageHeader.cs b/Emby.Drawing/Common/ImageHeader.cs new file mode 100644 index 0000000000..b66bd71ea5 --- /dev/null +++ b/Emby.Drawing/Common/ImageHeader.cs @@ -0,0 +1,223 @@ +using MediaBrowser.Common.IO; +using MediaBrowser.Model.Drawing; +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Emby.Drawing.Common +{ + /// + /// Taken from http://stackoverflow.com/questions/111345/getting-image-dimensions-without-reading-the-entire-file/111349 + /// http://www.codeproject.com/Articles/35978/Reading-Image-Headers-to-Get-Width-and-Height + /// Minor improvements including supporting unsigned 16-bit integers when decoding Jfif and added logic + /// to load the image using new Bitmap if reading the headers fails + /// + public static class ImageHeader + { + /// + /// The error message + /// + const string ErrorMessage = "Could not recognize image format."; + + /// + /// The image format decoders + /// + private static readonly KeyValuePair>[] ImageFormatDecoders = new Dictionary> + { + { new byte[] { 0x42, 0x4D }, DecodeBitmap }, + { new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, DecodeGif }, + { new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif }, + { new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DecodePng }, + { new byte[] { 0xff, 0xd8 }, DecodeJfif } + + }.ToArray(); + + private static readonly int MaxMagicBytesLength = ImageFormatDecoders.Select(i => i.Key.Length).OrderByDescending(i => i).First(); + + /// + /// Gets the dimensions of an image. + /// + /// The path of the image to get the dimensions of. + /// The logger. + /// The file system. + /// The dimensions of the specified image. + /// The image was of an unrecognised format. + public static ImageSize GetDimensions(string path, ILogger logger, IFileSystem fileSystem) + { + using (var fs = File.OpenRead(path)) + { + using (var binaryReader = new BinaryReader(fs)) + { + return GetDimensions(binaryReader); + } + } + } + + /// + /// Gets the dimensions of an image. + /// + /// The binary reader. + /// Size. + /// binaryReader + /// The image was of an unrecognized format. + private static ImageSize GetDimensions(BinaryReader binaryReader) + { + var magicBytes = new byte[MaxMagicBytesLength]; + + for (var i = 0; i < MaxMagicBytesLength; i += 1) + { + magicBytes[i] = binaryReader.ReadByte(); + + foreach (var kvPair in ImageFormatDecoders) + { + if (StartsWith(magicBytes, kvPair.Key)) + { + return kvPair.Value(binaryReader); + } + } + } + + throw new ArgumentException(ErrorMessage, "binaryReader"); + } + + /// + /// Startses the with. + /// + /// The this bytes. + /// The that bytes. + /// true if XXXX, false otherwise + private static bool StartsWith(byte[] thisBytes, byte[] thatBytes) + { + for (int i = 0; i < thatBytes.Length; i += 1) + { + if (thisBytes[i] != thatBytes[i]) + { + return false; + } + } + + return true; + } + + /// + /// Reads the little endian int16. + /// + /// The binary reader. + /// System.Int16. + private static short ReadLittleEndianInt16(BinaryReader binaryReader) + { + var bytes = new byte[sizeof(short)]; + + for (int i = 0; i < sizeof(short); i += 1) + { + bytes[sizeof(short) - 1 - i] = binaryReader.ReadByte(); + } + return BitConverter.ToInt16(bytes, 0); + } + + /// + /// Reads the little endian int32. + /// + /// The binary reader. + /// System.Int32. + private static int ReadLittleEndianInt32(BinaryReader binaryReader) + { + var bytes = new byte[sizeof(int)]; + for (int i = 0; i < sizeof(int); i += 1) + { + bytes[sizeof(int) - 1 - i] = binaryReader.ReadByte(); + } + return BitConverter.ToInt32(bytes, 0); + } + + /// + /// Decodes the bitmap. + /// + /// The binary reader. + /// Size. + private static ImageSize DecodeBitmap(BinaryReader binaryReader) + { + binaryReader.ReadBytes(16); + int width = binaryReader.ReadInt32(); + int height = binaryReader.ReadInt32(); + return new ImageSize + { + Width = width, + Height = height + }; + } + + /// + /// Decodes the GIF. + /// + /// The binary reader. + /// Size. + private static ImageSize DecodeGif(BinaryReader binaryReader) + { + int width = binaryReader.ReadInt16(); + int height = binaryReader.ReadInt16(); + return new ImageSize + { + Width = width, + Height = height + }; + } + + /// + /// Decodes the PNG. + /// + /// The binary reader. + /// Size. + private static ImageSize DecodePng(BinaryReader binaryReader) + { + binaryReader.ReadBytes(8); + int width = ReadLittleEndianInt32(binaryReader); + int height = ReadLittleEndianInt32(binaryReader); + return new ImageSize + { + Width = width, + Height = height + }; + } + + /// + /// Decodes the jfif. + /// + /// The binary reader. + /// Size. + /// + private static ImageSize DecodeJfif(BinaryReader binaryReader) + { + while (binaryReader.ReadByte() == 0xff) + { + byte marker = binaryReader.ReadByte(); + short chunkLength = ReadLittleEndianInt16(binaryReader); + if (marker == 0xc0) + { + binaryReader.ReadByte(); + int height = ReadLittleEndianInt16(binaryReader); + int width = ReadLittleEndianInt16(binaryReader); + return new ImageSize + { + Width = width, + Height = height + }; + } + + if (chunkLength < 0) + { + var uchunkLength = (ushort)chunkLength; + binaryReader.ReadBytes(uchunkLength - 2); + } + else + { + binaryReader.ReadBytes(chunkLength - 2); + } + } + + throw new ArgumentException(ErrorMessage); + } + } +} diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj index 7e833eeeb5..1907381e9c 100644 --- a/Emby.Drawing/Emby.Drawing.csproj +++ b/Emby.Drawing/Emby.Drawing.csproj @@ -48,22 +48,42 @@ Properties\SharedVersion.cs - + + + + + + + + + - - + + - - - - + + + + + {9142eefa-7570-41e1-bfcc-468bb571af2f} + MediaBrowser.Common + + + {17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2} + MediaBrowser.Controller + + + {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} + MediaBrowser.Model + +