diff --git a/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs b/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs index bca0c6665..2e04c1e81 100644 --- a/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs +++ b/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs @@ -11,9 +11,16 @@ namespace ImageProcessor.Web { #region Using + + using System; using System.Collections.Generic; using System.Drawing; + using System.Drawing.Imaging; + using System.IO; using System.Linq; + + using ImageProcessor.Extensions; + using ImageProcessor.Imaging; using ImageProcessor.Processors; using ImageProcessor.Web.Config; #endregion @@ -63,5 +70,28 @@ namespace ImageProcessor.Web return factory; } + + private void ProcessImage(Func processor) + { + ImageInfo imageInfo = this.Image.GetImageInfo(); + + if (imageInfo.IsAnimated) + { + using (GifEncoder encoder = new GifEncoder(new MemoryStream(4096), 0, 0, imageInfo.LoopCount)) + { + foreach (GifFrame frame in imageInfo.GifFrames) + { + frame.Image = ColorQuantizer.Quantize(processor.Invoke(this), PixelFormat.Format8bppIndexed); + encoder.AddFrame(frame); + } + + this.Image = encoder.Save(); + } + } + else + { + this.Image = processor.Invoke(this); + } + } } } diff --git a/src/ImageProcessor.sln b/src/ImageProcessor.sln index beee7760a..a8060449d 100644 --- a/src/ImageProcessor.sln +++ b/src/ImageProcessor.sln @@ -32,6 +32,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET45", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_Webforms_NET45", "TestWebsites\NET45\Test_Website_Webforms_NET45\Test_Website_Webforms_NET45.csproj", "{8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessorConsole", "ImageProcessorConsole\ImageProcessorConsole.csproj", "{7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Any CPU = All|Any CPU @@ -170,6 +172,21 @@ Global {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Mixed Platforms.Build.0 = Release|Any CPU {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|x86.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Any CPU.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Any CPU.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Mixed Platforms.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|x86.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|x86.ActiveCfg = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Any CPU.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/ImageProcessor/Extensions/ImageExtensions.cs b/src/ImageProcessor/Extensions/ImageExtensions.cs index 5ddcd96de..a2a967a61 100644 --- a/src/ImageProcessor/Extensions/ImageExtensions.cs +++ b/src/ImageProcessor/Extensions/ImageExtensions.cs @@ -14,6 +14,7 @@ namespace ImageProcessor.Extensions using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; + using System.IO; using ImageProcessor.Imaging; @@ -31,61 +32,76 @@ namespace ImageProcessor.Extensions /// /// The . /// - public static ImageInfo GetImageInfo(this Image image) + public static ImageInfo GetImageInfo(this Image imagex) { - ImageInfo info = new ImageInfo + string path = new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath; + // ReSharper disable once AssignNullToNotNullAttribute + string resolvedPath = Path.Combine(Path.GetDirectoryName(path), "frames"); + DirectoryInfo di = new DirectoryInfo(resolvedPath); + if (!di.Exists) { - Height = image.Height, - Width = image.Width, + di.Create(); + } + + + ImageInfo info = new ImageInfo(); + + using (Image image = (Image)imagex.Clone()) + { + info.Height = image.Height; + info.Width = image.Width; // Test value of flags using bitwise AND. // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags - IsIndexed = (image.PixelFormat & PixelFormat.Indexed) != 0 - }; + info.IsIndexed = (image.PixelFormat & PixelFormat.Indexed) != 0; - if (image.RawFormat.Equals(ImageFormat.Gif)) - { - if (ImageAnimator.CanAnimate(image)) + if (image.RawFormat.Equals(ImageFormat.Gif)) { - FrameDimension frameDimension = new FrameDimension(image.FrameDimensionsList[0]); + if (ImageAnimator.CanAnimate(image)) + { + FrameDimension frameDimension = new FrameDimension(image.FrameDimensionsList[0]); - int frameCount = image.GetFrameCount(frameDimension); - int delay = 0; - int[] delays = new int[frameCount]; - int index = 0; - List gifFrames = new List(); + int frameCount = image.GetFrameCount(frameDimension); + int delay = 0; + int[] delays = new int[frameCount]; + int index = 0; + List gifFrames = new List(); - for (int f = 0; f < frameCount; f++) - { - int thisDelay = BitConverter.ToInt32(image.GetPropertyItem(20736).Value, index) * 10; - thisDelay = thisDelay < 100 ? 100 : thisDelay; // Minimum delay is 100 ms - delays[f] = thisDelay; - - // Find the frame - image.SelectActiveFrame(frameDimension, f); - - // TODO: Get positions. - gifFrames.Add(new GifFrame - { - Delay = thisDelay, - Image = (Image)image.Clone() - }); - - delay += thisDelay; - index += 4; - } + for (int f = 0; f < frameCount; f++) + { + int thisDelay = BitConverter.ToInt32(image.GetPropertyItem(20736).Value, index); + int toAddDelay = thisDelay * 10 < 100 ? 100 : thisDelay * 10; // Minimum delay is 100 ms + delays[f] = thisDelay; + + // Find the frame + image.SelectActiveFrame(frameDimension, f); + + image.Save(Path.Combine(resolvedPath, f + ".gif"), ImageFormat.Gif); + + // TODO: Get positions. + gifFrames.Add(new GifFrame + { + Delay = thisDelay, + Image = (Image)image.Clone() + }); - info.AnimationLength = delay; - info.IsAnimated = true; + delay += toAddDelay; + index += 4; + } - info.LoopCount = BitConverter.ToInt16(image.GetPropertyItem(20737).Value, 0); + info.GifFrames = gifFrames; + info.AnimationLength = delay; + info.IsAnimated = true; - // Loop info is stored at byte 20737. - info.IsLooped = info.LoopCount != 1; + info.LoopCount = BitConverter.ToInt16(image.GetPropertyItem(20737).Value, 0); + + // Loop info is stored at byte 20737. + info.IsLooped = info.LoopCount != 1; + } } - } - return info; + return info; + } } } } diff --git a/src/ImageProcessor/Extensions/ImageInfo.cs b/src/ImageProcessor/Extensions/ImageInfo.cs index 50efa85d9..720eb5a20 100644 --- a/src/ImageProcessor/Extensions/ImageInfo.cs +++ b/src/ImageProcessor/Extensions/ImageInfo.cs @@ -12,7 +12,6 @@ namespace ImageProcessor.Extensions { using System.Collections.Generic; - using ImageProcessor.Imaging; /// diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index 5facec8cd..ef403e9c9 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -624,13 +624,15 @@ namespace ImageProcessor int width = size.Width; int height = size.Height; - Dictionary resizeSettings = new Dictionary { { "MaxWidth", width.ToString("G") }, { "MaxHeight", height.ToString("G") } }; + //Dictionary resizeSettings = new Dictionary { { "MaxWidth", width.ToString("G") }, { "MaxHeight", height.ToString("G") } }; ResizeLayer resizeLayer = new ResizeLayer(new Size(width, height)); - Resize resize = new Resize { DynamicParameter = resizeLayer, Settings = resizeSettings }; + //Resize resize = new Resize { DynamicParameter = resizeLayer, Settings = resizeSettings }; + + //this.Image = resize.ProcessImage(this); - this.Image = resize.ProcessImage(this); + return this.Resize(resizeLayer); } return this; @@ -653,25 +655,27 @@ namespace ImageProcessor Resize resize = new Resize { DynamicParameter = resizeLayer, Settings = resizeSettings }; - ImageInfo imageInfo = this.Image.GetImageInfo(); - - if (imageInfo.IsAnimated) - { - using (GifEncoder encoder = new GifEncoder(new MemoryStream(4096), resizeLayer.Size.Width, resizeLayer.Size.Height, imageInfo.LoopCount)) - { - foreach (GifFrame frame in imageInfo.GifFrames) - { - frame.Image = ColorQuantizer.Quantize(resize.ProcessImage(this), PixelFormat.Format8bppIndexed); - encoder.AddFrame(frame); - } - - - } - } - else - { - this.Image = resize.ProcessImage(this); - } + this.ProcessImage(resize.ProcessImage, resizeLayer.Size.Width, resizeLayer.Size.Height); + + //ImageInfo imageInfo = this.Image.GetImageInfo(); + + //if (imageInfo.IsAnimated) + //{ + // using (GifEncoder encoder = new GifEncoder(new MemoryStream(4096), resizeLayer.Size.Width, resizeLayer.Size.Height, imageInfo.LoopCount)) + // { + // foreach (GifFrame frame in imageInfo.GifFrames) + // { + // frame.Image = ColorQuantizer.Quantize(resize.ProcessImage(this), PixelFormat.Format8bppIndexed); + // encoder.AddFrame(frame); + // } + + // this.Image = encoder.Save(); + // } + //} + //else + //{ + // this.Image = resize.ProcessImage(this); + //} } return this; @@ -1013,6 +1017,77 @@ namespace ImageProcessor this.Image = ColorQuantizer.Quantize(this.Image, PixelFormat.Format8bppIndexed); } } + + private void ProcessImage(Func processor, int width, int height) + { + + string path = new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath; + // ReSharper disable once AssignNullToNotNullAttribute + string resolvedPath = Path.Combine(Path.GetDirectoryName(path), "frames-resized"); + DirectoryInfo di = new DirectoryInfo(resolvedPath); + if (!di.Exists) + { + di.Create(); + } + + ImageInfo imageInfo = this.Image.GetImageInfo(); + + if (imageInfo.IsAnimated) + { + using (GifEncoder encoder = new GifEncoder(new MemoryStream(4096), width, height, imageInfo.LoopCount)) + { + int counter = 0; + foreach (GifFrame frame in imageInfo.GifFrames) + { + this.Image = frame.Image; + + frame.Image = new Bitmap(ColorQuantizer.Quantize(processor.Invoke(this), PixelFormat.Format8bppIndexed)); + //using (Image temp = new Bitmap(ColorQuantizer.Quantize(processor.Invoke(this), PixelFormat.Format8bppIndexed))) + //{ + + encoder.AddFrame(frame); + + //frame.Image.Save(Path.Combine(resolvedPath, counter + ".gif"), ImageFormat.Gif); + counter++; + } + + this.Image = encoder.Save(); + + + } + //var stream = new MemoryStream(); + //using (GifEncoder2 encoder = new GifEncoder2(stream, width, height, imageInfo.LoopCount)) + //{ + // foreach (GifFrame frame in imageInfo.GifFrames) + // { + // this.Image = frame.Image; + + // using (Image temp = new Bitmap(ColorQuantizer.Quantize(processor.Invoke(this), PixelFormat.Format8bppIndexed))) + // { + // encoder.AddFrame(temp, frame.X, frame.Y, TimeSpan.FromMilliseconds(frame.Delay)); + // } + // } + + // stream.Position = 0; + // this.Image = Image.FromStream(stream); + + // string path = new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath; + // // ReSharper disable once AssignNullToNotNullAttribute + // string resolvedPath = Path.Combine(Path.GetDirectoryName(path), "output"); + // DirectoryInfo di = new DirectoryInfo(resolvedPath); + // if (!di.Exists) + // { + // di.Create(); + // } + + // this.Image.Save(Path.Combine(resolvedPath, "test.gif"), ImageFormat.Gif); + //} + } + else + { + this.Image = processor.Invoke(this); + } + } #endregion } } diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 66959a3d7..70471dc0e 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -72,6 +72,7 @@ + diff --git a/src/ImageProcessor/Imaging/GifEncoder - Copy.cs b/src/ImageProcessor/Imaging/GifEncoder - Copy.cs new file mode 100644 index 000000000..075e5ec17 --- /dev/null +++ b/src/ImageProcessor/Imaging/GifEncoder - Copy.cs @@ -0,0 +1,409 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Imaging +{ + #region + + using System; + using System.Drawing; + using System.Drawing.Imaging; + using System.IO; + using System.Linq; + + #endregion + + /// + /// Encodes multiple images as an animated gif to a stream. + /// + /// Always wire this up in a using block. + /// Disposing the encoder will complete the file. + /// Uses default .NET GIF encoding and adds animation headers. + /// + /// + /// + /// Encodes multiple images as an animated gif to a stream.
+ /// ALWAYS ALWAYS ALWAYS wire this up in a using block
+ /// Disposing the encoder will complete the file.
+ /// Uses default .net GIF encoding and adds animation headers. + ///
+ public class GifEncoder2 : IDisposable + { + #region Constants + + /// + /// The application block size. + /// + private const byte ApplicationBlockSize = 0x0b; + + /// + /// The application extension block identifier. + /// + private const int ApplicationExtensionBlockIdentifier = 0xff21; + + /// + /// The application identification. + /// + private const string ApplicationIdentification = "NETSCAPE2.0"; + + /// + /// The file trailer. + /// + private const byte FileTrailer = 0x3b; + + /// + /// The file type. + /// + private const string FileType = "GIF"; + + /// + /// The file version. + /// + private const string FileVersion = "89a"; + + /// + /// The graphic control extension block identifier. + /// + private const int GraphicControlExtensionBlockIdentifier = 0xf921; + + /// + /// The graphic control extension block size. + /// + private const byte GraphicControlExtensionBlockSize = 0x04; + + /// + /// The source color block length. + /// + private const long SourceColorBlockLength = 768; + + /// + /// The source color block position. + /// + private const long SourceColorBlockPosition = 13; + + /// + /// The source global color info position. + /// + private const long SourceGlobalColorInfoPosition = 10; + + /// + /// The source graphic control extension length. + /// + private const long SourceGraphicControlExtensionLength = 8; + + /// + /// The source graphic control extension position. + /// + private const long SourceGraphicControlExtensionPosition = 781; + + /// + /// The source image block header length. + /// + private const long SourceImageBlockHeaderLength = 11; + + /// + /// The source image block position. + /// + private const long SourceImageBlockPosition = 789; + + #endregion + + #region Fields + + /// + /// The _stream. + /// + private readonly Stream _stream; + + /// + /// The _height. + /// + private int? _height; + + /// + /// The _is first image. + /// + private bool _isFirstImage = true; + + /// + /// The _repeat count. + /// + private int? _repeatCount; + + /// + /// The _width. + /// + private int? _width; + + #endregion + + #region Constructors and Destructors + + /// + /// Initializes a new instance of the class. + /// Encodes multiple images as an animated gif to a stream.
+ /// ALWAYS ALWAYS ALWAYS wire this in a using block
+ /// Disposing the encoder will complete the file.
+ /// Uses default .net GIF encoding and adds animation headers. + ///
+ /// + /// The stream that will be written to. + /// + /// + /// Sets the width for this gif or null to use the first frame's width. + /// + /// + /// Sets the height for this gif or null to use the first frame's height. + /// + /// + /// The repeat Count. + /// + public GifEncoder2(Stream stream, int? width = null, int? height = null, int? repeatCount = null) + { + this._stream = stream; + this._width = width; + this._height = height; + this._repeatCount = repeatCount; + } + + #endregion + + #region Public Properties + + /// + /// Gets or sets the frame delay. + /// + public TimeSpan FrameDelay { get; set; } + + #endregion + + #region Public Methods and Operators + + /// + /// Adds a frame to this animation. + /// + /// + /// The image to add + /// + /// + /// The positioning x offset this image should be displayed at. + /// + /// + /// The positioning y offset this image should be displayed at. + /// + /// + /// The frame Delay. + /// + public void AddFrame(Image img, int x = 0, int y = 0, TimeSpan? frameDelay = null) + { + using (var gifStream = new MemoryStream()) + { + img.Save(gifStream, ImageFormat.Gif); + if (this._isFirstImage) + { + // Steal the global color table info + this.InitHeader(gifStream, img.Width, img.Height); + } + + this.WriteGraphicControlBlock(gifStream, frameDelay.GetValueOrDefault(this.FrameDelay)); + this.WriteImageBlock(gifStream, !this._isFirstImage, x, y, img.Width, img.Height); + } + + this._isFirstImage = false; + } + + /// + /// The dispose. + /// + public void Dispose() + { + // Complete Application Block + this.WriteByte(0); + + // Complete File + this.WriteByte(FileTrailer); + + // Pushing data + this._stream.Flush(); + } + + #endregion + + #region Methods + + /// + /// The init header. + /// + /// + /// The source gif. + /// + /// + /// The w. + /// + /// + /// The h. + /// + private void InitHeader(Stream sourceGif, int w, int h) + { + // File Header + this.WriteString(FileType); + this.WriteString(FileVersion); + this.WriteShort(this._width.GetValueOrDefault(w)); // Initial Logical Width + this.WriteShort(this._height.GetValueOrDefault(h)); // Initial Logical Height + sourceGif.Position = SourceGlobalColorInfoPosition; + this.WriteByte(sourceGif.ReadByte()); // Global Color Table Info + this.WriteByte(0); // Background Color Index + this.WriteByte(0); // Pixel aspect ratio + this.WriteColorTable(sourceGif); + + // App Extension Header + this.WriteShort(ApplicationExtensionBlockIdentifier); + this.WriteByte(ApplicationBlockSize); + this.WriteString(ApplicationIdentification); + this.WriteByte(3); // Application block length + this.WriteByte(1); + this.WriteShort(this._repeatCount.GetValueOrDefault(0)); // Repeat count for images. + this.WriteByte(0); // terminator + } + + /// + /// The write byte. + /// + /// + /// The value. + /// + private void WriteByte(int value) + { + this._stream.WriteByte(Convert.ToByte(value)); + } + + /// + /// The write color table. + /// + /// + /// The source gif. + /// + private void WriteColorTable(Stream sourceGif) + { + sourceGif.Position = SourceColorBlockPosition; // Locating the image color table + var colorTable = new byte[SourceColorBlockLength]; + sourceGif.Read(colorTable, 0, colorTable.Length); + this._stream.Write(colorTable, 0, colorTable.Length); + } + + /// + /// The write graphic control block. + /// + /// + /// The source gif. + /// + /// + /// The frame delay. + /// + private void WriteGraphicControlBlock(Stream sourceGif, TimeSpan frameDelay) + { + sourceGif.Position = SourceGraphicControlExtensionPosition; // Locating the source GCE + var blockhead = new byte[SourceGraphicControlExtensionLength]; + sourceGif.Read(blockhead, 0, blockhead.Length); // Reading source GCE + + this.WriteShort(GraphicControlExtensionBlockIdentifier); // Identifier + this.WriteByte(GraphicControlExtensionBlockSize); // Block Size + this.WriteByte(blockhead[3] & 0xf7 | 0x08); // Setting disposal flag + this.WriteShort(Convert.ToInt32(frameDelay.TotalMilliseconds / 10)); // Setting frame delay + this.WriteByte(blockhead[6]); // Transparent color index + this.WriteByte(0); // Terminator + } + + /// + /// The write image block. + /// + /// + /// The source gif. + /// + /// + /// The include color table. + /// + /// + /// The x. + /// + /// + /// The y. + /// + /// + /// The h. + /// + /// + /// The w. + /// + private void WriteImageBlock(Stream sourceGif, bool includeColorTable, int x, int y, int h, int w) + { + sourceGif.Position = SourceImageBlockPosition; // Locating the image block + var header = new byte[SourceImageBlockHeaderLength]; + sourceGif.Read(header, 0, header.Length); + this.WriteByte(header[0]); // Separator + this.WriteShort(x); // Position X + this.WriteShort(y); // Position Y + this.WriteShort(h); // Height + this.WriteShort(w); // Width + + if (includeColorTable) + { + // If first frame, use global color table - else use local + sourceGif.Position = SourceGlobalColorInfoPosition; + this.WriteByte(sourceGif.ReadByte() & 0x3f | 0x80); // Enabling local color table + this.WriteColorTable(sourceGif); + } + else + { + this.WriteByte(header[9] & 0x07 | 0x07); // Disabling local color table + } + + this.WriteByte(header[10]); // LZW Min Code Size + + // Read/Write image data + sourceGif.Position = SourceImageBlockPosition + SourceImageBlockHeaderLength; + + int dataLength = sourceGif.ReadByte(); + while (dataLength > 0) + { + var imgData = new byte[dataLength]; + sourceGif.Read(imgData, 0, dataLength); + + this._stream.WriteByte(Convert.ToByte(dataLength)); + this._stream.Write(imgData, 0, dataLength); + dataLength = sourceGif.ReadByte(); + } + + this._stream.WriteByte(0); // Terminator + } + + /// + /// The write short. + /// + /// + /// The value. + /// + private void WriteShort(int value) + { + this._stream.WriteByte(Convert.ToByte(value & 0xff)); + this._stream.WriteByte(Convert.ToByte((value >> 8) & 0xff)); + } + + /// + /// The write string. + /// + /// + /// The value. + /// + private void WriteString(string value) + { + this._stream.Write(value.ToArray().Select(c => (byte)c).ToArray(), 0, value.Length); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/ImageProcessor/Imaging/GifEncoder.cs b/src/ImageProcessor/Imaging/GifEncoder.cs index 4b00a873e..04050c386 100644 --- a/src/ImageProcessor/Imaging/GifEncoder.cs +++ b/src/ImageProcessor/Imaging/GifEncoder.cs @@ -225,9 +225,24 @@ namespace ImageProcessor.Imaging this.isFirstImage = false; } + /// + /// Returns the gif as an image. + /// + /// + /// The containing the animated gif. + /// public Image Save() { - + // Complete Application Block + this.WriteByte(0); + + // Complete File + this.WriteByte(FileTrailer); + + // Push the data + // this.inputStream.Flush(); + this.inputStream.Position = 0; + return Image.FromStream(this.inputStream); } /// @@ -263,16 +278,6 @@ namespace ImageProcessor.Imaging if (disposing) { // Dispose of any managed resources here. - // Complete Application Block - this.WriteByte(0); - - // Complete File - this.WriteByte(FileTrailer); - - // Pushing data - this.inputStream.Flush(); - - // Dispose of the memory stream from Load and the image. if (this.inputStream != null) { this.inputStream.Dispose(); @@ -324,7 +329,7 @@ namespace ImageProcessor.Imaging this.WriteString(ApplicationIdentification); this.WriteByte(3); // Application block length this.WriteByte(1); - this.WriteShort(this.repeatCount.GetValueOrDefault(0)); // Repeat count for images. + this.WriteShort(count); // Repeat count for images. this.WriteByte(0); // Terminator } } diff --git a/src/ImageProcessorConsole/App.config b/src/ImageProcessorConsole/App.config new file mode 100644 index 000000000..9c05822ff --- /dev/null +++ b/src/ImageProcessorConsole/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/ImageProcessorConsole/ImageProcessorConsole.csproj b/src/ImageProcessorConsole/ImageProcessorConsole.csproj new file mode 100644 index 000000000..39b66751b --- /dev/null +++ b/src/ImageProcessorConsole/ImageProcessorConsole.csproj @@ -0,0 +1,66 @@ + + + + + Debug + AnyCPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7} + Exe + Properties + ImageProcessorConsole + ImageProcessorConsole + v4.5.1 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} + ImageProcessor + + + + + \ No newline at end of file diff --git a/src/ImageProcessorConsole/Program.cs b/src/ImageProcessorConsole/Program.cs new file mode 100644 index 000000000..c73615a61 --- /dev/null +++ b/src/ImageProcessorConsole/Program.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ImageProcessorConsole +{ + using System.Drawing; + using System.Drawing.Imaging; + using System.IO; + + using ImageProcessor; + + class Program + { + static void Main(string[] args) + { + string path = new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath; + // ReSharper disable once AssignNullToNotNullAttribute + string resolvedPath = Path.Combine(Path.GetDirectoryName(path), "images"); + DirectoryInfo di = new DirectoryInfo(resolvedPath); + if (!di.Exists) + { + di.Create(); + } + + FileInfo[] files = di.GetFiles("*.gif"); + + foreach (FileInfo fileInfo in files) + { + byte[] photoBytes = File.ReadAllBytes(fileInfo.FullName); + + // ImageProcessor + using (MemoryStream inStream = new MemoryStream(photoBytes)) + { + using (ImageFactory imageFactory = new ImageFactory()) + { + Size size = new Size(150, 150); + ImageFormat format = ImageFormat.Gif; + + // Load, resize, set the format and quality and save an image. + imageFactory.Load(inStream) + .Constrain(size) + .Format(format) + .Save(Path.Combine(Path.GetDirectoryName(path), "output", fileInfo.Name)); + } + } + } + } + } +} diff --git a/src/ImageProcessorConsole/Properties/AssemblyInfo.cs b/src/ImageProcessorConsole/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..a39a9ca43 --- /dev/null +++ b/src/ImageProcessorConsole/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ImageProcessorConsole")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ImageProcessorConsole")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ac215639-6e27-4b9c-9ebb-9116c7a5d8a6")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")]