Browse Source

First success!!

Code is an absolute mess just now.


Former-commit-id: 10e1e7f8b6806b1a83d1a54ae7d685e3d590cffc
pull/17/head
James South 12 years ago
parent
commit
4bcfe7ffcd
  1. 30
      src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs
  2. 17
      src/ImageProcessor.sln
  3. 98
      src/ImageProcessor/Extensions/ImageExtensions.cs
  4. 1
      src/ImageProcessor/Extensions/ImageInfo.cs
  5. 119
      src/ImageProcessor/ImageFactory.cs
  6. 1
      src/ImageProcessor/ImageProcessor.csproj
  7. 409
      src/ImageProcessor/Imaging/GifEncoder - Copy.cs
  8. 29
      src/ImageProcessor/Imaging/GifEncoder.cs
  9. 6
      src/ImageProcessorConsole/App.config
  10. 66
      src/ImageProcessorConsole/ImageProcessorConsole.csproj
  11. 52
      src/ImageProcessorConsole/Program.cs
  12. 36
      src/ImageProcessorConsole/Properties/AssemblyInfo.cs

30
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<ImageFactory, Image> 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);
}
}
}
}

17
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

98
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
/// <returns>
/// The <see cref="ImageInfo"/>.
/// </returns>
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<GifFrame> gifFrames = new List<GifFrame>();
int frameCount = image.GetFrameCount(frameDimension);
int delay = 0;
int[] delays = new int[frameCount];
int index = 0;
List<GifFrame> gifFrames = new List<GifFrame>();
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;
}
}
}
}

1
src/ImageProcessor/Extensions/ImageInfo.cs

@ -12,7 +12,6 @@
namespace ImageProcessor.Extensions
{
using System.Collections.Generic;
using ImageProcessor.Imaging;
/// <summary>

119
src/ImageProcessor/ImageFactory.cs

@ -624,13 +624,15 @@ namespace ImageProcessor
int width = size.Width;
int height = size.Height;
Dictionary<string, string> resizeSettings = new Dictionary<string, string> { { "MaxWidth", width.ToString("G") }, { "MaxHeight", height.ToString("G") } };
//Dictionary<string, string> resizeSettings = new Dictionary<string, string> { { "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<ImageFactory, Image> 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
}
}

1
src/ImageProcessor/ImageProcessor.csproj

@ -72,6 +72,7 @@
<Compile Include="Imaging\CropMode.cs" />
<Compile Include="Imaging\GaussianLayer.cs" />
<Compile Include="Imaging\ColorQuantizer.cs" />
<Compile Include="Imaging\GifEncoder - Copy.cs" />
<Compile Include="Imaging\GifEncoder.cs" />
<Compile Include="Imaging\GifFrame.cs" />
<Compile Include="Imaging\ResizeLayer.cs" />

409
src/ImageProcessor/Imaging/GifEncoder - Copy.cs

@ -0,0 +1,409 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="GifEncoder - Copy.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Imaging
{
#region
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
#endregion
/// <summary>
/// Encodes multiple images as an animated gif to a stream.
/// <remarks>
/// Always wire this up in a using block.
/// Disposing the encoder will complete the file.
/// Uses default .NET GIF encoding and adds animation headers.
/// </remarks>
/// </summary>
/// <summary>
/// Encodes multiple images as an animated gif to a stream. <br />
/// ALWAYS ALWAYS ALWAYS wire this up in a using block <br />
/// Disposing the encoder will complete the file. <br />
/// Uses default .net GIF encoding and adds animation headers.
/// </summary>
public class GifEncoder2 : IDisposable
{
#region Constants
/// <summary>
/// The application block size.
/// </summary>
private const byte ApplicationBlockSize = 0x0b;
/// <summary>
/// The application extension block identifier.
/// </summary>
private const int ApplicationExtensionBlockIdentifier = 0xff21;
/// <summary>
/// The application identification.
/// </summary>
private const string ApplicationIdentification = "NETSCAPE2.0";
/// <summary>
/// The file trailer.
/// </summary>
private const byte FileTrailer = 0x3b;
/// <summary>
/// The file type.
/// </summary>
private const string FileType = "GIF";
/// <summary>
/// The file version.
/// </summary>
private const string FileVersion = "89a";
/// <summary>
/// The graphic control extension block identifier.
/// </summary>
private const int GraphicControlExtensionBlockIdentifier = 0xf921;
/// <summary>
/// The graphic control extension block size.
/// </summary>
private const byte GraphicControlExtensionBlockSize = 0x04;
/// <summary>
/// The source color block length.
/// </summary>
private const long SourceColorBlockLength = 768;
/// <summary>
/// The source color block position.
/// </summary>
private const long SourceColorBlockPosition = 13;
/// <summary>
/// The source global color info position.
/// </summary>
private const long SourceGlobalColorInfoPosition = 10;
/// <summary>
/// The source graphic control extension length.
/// </summary>
private const long SourceGraphicControlExtensionLength = 8;
/// <summary>
/// The source graphic control extension position.
/// </summary>
private const long SourceGraphicControlExtensionPosition = 781;
/// <summary>
/// The source image block header length.
/// </summary>
private const long SourceImageBlockHeaderLength = 11;
/// <summary>
/// The source image block position.
/// </summary>
private const long SourceImageBlockPosition = 789;
#endregion
#region Fields
/// <summary>
/// The _stream.
/// </summary>
private readonly Stream _stream;
/// <summary>
/// The _height.
/// </summary>
private int? _height;
/// <summary>
/// The _is first image.
/// </summary>
private bool _isFirstImage = true;
/// <summary>
/// The _repeat count.
/// </summary>
private int? _repeatCount;
/// <summary>
/// The _width.
/// </summary>
private int? _width;
#endregion
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="GifEncoder2"/> class.
/// Encodes multiple images as an animated gif to a stream. <br/>
/// ALWAYS ALWAYS ALWAYS wire this in a using block <br/>
/// Disposing the encoder will complete the file. <br/>
/// Uses default .net GIF encoding and adds animation headers.
/// </summary>
/// <param name="stream">
/// The stream that will be written to.
/// </param>
/// <param name="width">
/// Sets the width for this gif or null to use the first frame's width.
/// </param>
/// <param name="height">
/// Sets the height for this gif or null to use the first frame's height.
/// </param>
/// <param name="repeatCount">
/// The repeat Count.
/// </param>
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
/// <summary>
/// Gets or sets the frame delay.
/// </summary>
public TimeSpan FrameDelay { get; set; }
#endregion
#region Public Methods and Operators
/// <summary>
/// Adds a frame to this animation.
/// </summary>
/// <param name="img">
/// The image to add
/// </param>
/// <param name="x">
/// The positioning x offset this image should be displayed at.
/// </param>
/// <param name="y">
/// The positioning y offset this image should be displayed at.
/// </param>
/// <param name="frameDelay">
/// The frame Delay.
/// </param>
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;
}
/// <summary>
/// The dispose.
/// </summary>
public void Dispose()
{
// Complete Application Block
this.WriteByte(0);
// Complete File
this.WriteByte(FileTrailer);
// Pushing data
this._stream.Flush();
}
#endregion
#region Methods
/// <summary>
/// The init header.
/// </summary>
/// <param name="sourceGif">
/// The source gif.
/// </param>
/// <param name="w">
/// The w.
/// </param>
/// <param name="h">
/// The h.
/// </param>
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
}
/// <summary>
/// The write byte.
/// </summary>
/// <param name="value">
/// The value.
/// </param>
private void WriteByte(int value)
{
this._stream.WriteByte(Convert.ToByte(value));
}
/// <summary>
/// The write color table.
/// </summary>
/// <param name="sourceGif">
/// The source gif.
/// </param>
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);
}
/// <summary>
/// The write graphic control block.
/// </summary>
/// <param name="sourceGif">
/// The source gif.
/// </param>
/// <param name="frameDelay">
/// The frame delay.
/// </param>
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
}
/// <summary>
/// The write image block.
/// </summary>
/// <param name="sourceGif">
/// The source gif.
/// </param>
/// <param name="includeColorTable">
/// The include color table.
/// </param>
/// <param name="x">
/// The x.
/// </param>
/// <param name="y">
/// The y.
/// </param>
/// <param name="h">
/// The h.
/// </param>
/// <param name="w">
/// The w.
/// </param>
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
}
/// <summary>
/// The write short.
/// </summary>
/// <param name="value">
/// The value.
/// </param>
private void WriteShort(int value)
{
this._stream.WriteByte(Convert.ToByte(value & 0xff));
this._stream.WriteByte(Convert.ToByte((value >> 8) & 0xff));
}
/// <summary>
/// The write string.
/// </summary>
/// <param name="value">
/// The value.
/// </param>
private void WriteString(string value)
{
this._stream.Write(value.ToArray().Select(c => (byte)c).ToArray(), 0, value.Length);
}
#endregion
}
}

29
src/ImageProcessor/Imaging/GifEncoder.cs

@ -225,9 +225,24 @@ namespace ImageProcessor.Imaging
this.isFirstImage = false;
}
/// <summary>
/// Returns the gif as an image.
/// </summary>
/// <returns>
/// The <see cref="Image"/> containing the animated gif.
/// </returns>
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);
}
/// <summary>
@ -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
}
}

6
src/ImageProcessorConsole/App.config

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
</startup>
</configuration>

66
src/ImageProcessorConsole/ImageProcessorConsole.csproj

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ImageProcessorConsole</RootNamespace>
<AssemblyName>ImageProcessorConsole</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ImageProcessor\ImageProcessor.csproj">
<Project>{3b5dd734-fb7a-487d-8ce6-55e7af9aea7e}</Project>
<Name>ImageProcessor</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

52
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));
}
}
}
}
}
}

36
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")]
Loading…
Cancel
Save