mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-22 05:48:37 +00:00
Gif image support added.
This commit is contained in:
parent
cf6f10943c
commit
87c837658d
9 changed files with 817 additions and 3 deletions
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><ItemProperties xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><Properties><Property><Name>svn:mime-type</Name><Value>application/octet-stream</Value></Property></Properties></ItemProperties>
|
||||
|
|
@ -12,6 +12,7 @@ namespace ImageManipulatorTester
|
|||
public partial class Form1 : System.Windows.Forms.Form
|
||||
{
|
||||
private StreamWriter st;
|
||||
|
||||
public Form1()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
|
@ -363,10 +364,51 @@ namespace ImageManipulatorTester
|
|||
|
||||
System.GC.Collect();
|
||||
|
||||
#region Load Gif
|
||||
{
|
||||
FileStream s = new FileStream(Path.GetFullPath("Test.gif"), FileMode.Open);
|
||||
|
||||
t.Start();
|
||||
anim = Orvid.Graphics.ImageFormats.GifSupport.Load(s);
|
||||
t.Stop();
|
||||
WriteToLog("Loading a Gif took '" + t.ElapsedMilliseconds.ToString() + " ms'");
|
||||
t.Reset();
|
||||
|
||||
s.Close();
|
||||
s.Dispose();
|
||||
|
||||
Bitmap b = (Bitmap)anim[0];
|
||||
GifPictureBox = new PictureBox();
|
||||
GifPictureBox.BorderStyle = BorderStyle.FixedSingle;
|
||||
GifPictureBox.Parent = flowLayoutPanel2;
|
||||
GifPictureBox.Height = b.Height;
|
||||
GifPictureBox.Width = b.Width;
|
||||
GifPictureBox.Image = b;
|
||||
animpar = new Orvid.Graphics.Shapes.ShapedImage(anim.Width, anim.Height);
|
||||
anim.Parent = animpar;
|
||||
animpar.Shapes.Add(anim);
|
||||
|
||||
//time.Interval = anim.TimePerFrame * 4;
|
||||
//time.Tick += new EventHandler(time_Tick);
|
||||
//time.Start();
|
||||
}
|
||||
#endregion
|
||||
|
||||
st.Flush();
|
||||
st.Close();
|
||||
st.Dispose();
|
||||
|
||||
}
|
||||
|
||||
private PictureBox GifPictureBox;
|
||||
private Orvid.Graphics.AnimatedImage anim;
|
||||
private Orvid.Graphics.Shapes.ShapedImage animpar;
|
||||
private Timer time = new Timer();
|
||||
private void time_Tick(object sender, EventArgs e)
|
||||
{
|
||||
animpar.Modified = true;
|
||||
GifPictureBox.Image = (Bitmap)animpar.Render();
|
||||
GifPictureBox.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
BIN
source2/Users/Orvid/ImageManipulatorTester/Test.gif
Normal file
BIN
source2/Users/Orvid/ImageManipulatorTester/Test.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
122
source2/Users/Orvid/Orvid.Graphics/AnimatedImage.cs
Normal file
122
source2/Users/Orvid/Orvid.Graphics/AnimatedImage.cs
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Orvid.Graphics
|
||||
{
|
||||
public class AnimatedImage : Shapes.Shape, IDisposable
|
||||
{
|
||||
public Image[] Frames;
|
||||
private UInt32 curFrameIndex;
|
||||
private bool loop = false;
|
||||
public int Height { get { return Frames[0].Height; } }
|
||||
public int Width { get { return Frames[0].Width; } }
|
||||
|
||||
/// <summary>
|
||||
/// This is in Milli-Seconds
|
||||
/// </summary>
|
||||
public int TimePerFrame { get; set; }
|
||||
|
||||
public bool Loop
|
||||
{
|
||||
get
|
||||
{
|
||||
return loop;
|
||||
}
|
||||
set
|
||||
{
|
||||
loop = value;
|
||||
}
|
||||
}
|
||||
|
||||
public UInt32 CurFrameIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return curFrameIndex;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetCurrrentFrameIndex(value);
|
||||
}
|
||||
}
|
||||
|
||||
public Image this[UInt32 val]
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetFrame(val);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetFrame(val, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFrame(UInt32 indx, Image i)
|
||||
{
|
||||
if (indx < Frames.Length)
|
||||
Frames[indx] = i;
|
||||
throw new Exception("Specified Frame Doesn't Exist!");
|
||||
}
|
||||
|
||||
public AnimatedImage()
|
||||
{
|
||||
Frames = new Image[0];
|
||||
}
|
||||
|
||||
public AnimatedImage(Image[] images)
|
||||
{
|
||||
Frames = new Image[images.Length];
|
||||
Array.Copy(images, Frames, images.Length);
|
||||
curFrameIndex = 0;
|
||||
}
|
||||
|
||||
public Image GetFrame(UInt32 indx)
|
||||
{
|
||||
if (indx < Frames.Length)
|
||||
return Frames[indx];
|
||||
throw new Exception("Specified Frame Doesn't Exist!");
|
||||
}
|
||||
|
||||
public void AddFrame(Image i)
|
||||
{
|
||||
Image[] tmp = new Image[Frames.Length + 1];
|
||||
Array.Copy(Frames, tmp, Frames.Length);
|
||||
tmp[tmp.Length - 1] = i;
|
||||
Frames = tmp;
|
||||
curFrameIndex = 1;
|
||||
}
|
||||
|
||||
public void SetCurrrentFrameIndex(uint v)
|
||||
{
|
||||
if (v < Frames.Length - 1)
|
||||
curFrameIndex = v;
|
||||
else
|
||||
throw new Exception("Specified Frame Non-Existant!");
|
||||
}
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
Parent.Clear(new Pixel(true));
|
||||
Parent.DrawImage(new Vec2(this.X, this.Y), Frames[curFrameIndex]);
|
||||
|
||||
if (curFrameIndex + 2 <= Frames.Length - 1)
|
||||
{
|
||||
curFrameIndex++;
|
||||
curFrameIndex++;
|
||||
}
|
||||
else// if (loop)
|
||||
{
|
||||
curFrameIndex = 0;
|
||||
}
|
||||
|
||||
this.Modified = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Frames = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ namespace Orvid.Graphics.ImageFormats
|
|||
Formats.Add(new VbpImage());
|
||||
Formats.Add(new JpegImage());
|
||||
Formats.Add(new TiffImage());
|
||||
Formats.Add(new TgaImage());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
646
source2/Users/Orvid/Orvid.Graphics/ImageFormats/GifSupport.cs
Normal file
646
source2/Users/Orvid/Orvid.Graphics/ImageFormats/GifSupport.cs
Normal file
|
|
@ -0,0 +1,646 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace Orvid.Graphics.ImageFormats
|
||||
{
|
||||
public static class GifSupport
|
||||
{
|
||||
public static AnimatedImage Load(Stream s)
|
||||
{
|
||||
GifDecoder g = new GifDecoder();
|
||||
return g.DecodeImage(s);
|
||||
}
|
||||
|
||||
|
||||
// Please note, everything below this
|
||||
// point was originally from the ImageTools
|
||||
// Library, available here:
|
||||
// http://imagetools.codeplex.com/
|
||||
//
|
||||
// This disclaimer was last
|
||||
// modified on August 7, 2011.
|
||||
|
||||
|
||||
|
||||
#region Internals
|
||||
|
||||
#region DisposalMethod
|
||||
/// <summary>
|
||||
/// Specifies, what to do with the last image
|
||||
/// in an animation sequence.
|
||||
/// </summary>
|
||||
private enum DisposalMethod : int
|
||||
{
|
||||
/// <summary>
|
||||
/// No disposal specified. The decoder is not
|
||||
/// required to take any action.
|
||||
/// </summary>
|
||||
Unspecified = 0,
|
||||
/// <summary>
|
||||
/// Do not dispose. The graphic is to be left in place.
|
||||
/// </summary>
|
||||
NotDispose = 1,
|
||||
/// <summary>
|
||||
/// Restore to background color.
|
||||
/// The area used by the graphic must be restored to
|
||||
/// the background color.
|
||||
/// </summary>
|
||||
RestoreToBackground = 2,
|
||||
/// <summary>
|
||||
/// Restore to previous. The decoder is required to
|
||||
/// restore the area overwritten by the
|
||||
/// graphic with what was there prior to rendering the graphic.
|
||||
/// </summary>
|
||||
RestoreToPrevious = 3
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GifDecoder
|
||||
private class GifDecoder
|
||||
{
|
||||
private const byte ExtensionIntroducer = 0x21;
|
||||
private const byte Terminator = 0;
|
||||
private const byte ImageLabel = 0x2C;
|
||||
private const byte EndIntroducer = 0x3B;
|
||||
private const byte ApplicationExtensionLabel = 0xFF;
|
||||
private const byte CommentLabel = 0xFE;
|
||||
private const byte ImageDescriptorLabel = 0x2C;
|
||||
private const byte PlainTextLabel = 0x01;
|
||||
private const byte GraphicControlLabel = 0xF9;
|
||||
private AnimatedImage _image;
|
||||
private Stream _stream;
|
||||
private GifLogicalScreenDescriptor _logicalScreenDescriptor;
|
||||
private byte[] _globalColorTable;
|
||||
private byte[] _currentFrame;
|
||||
private GifGraphicsControlExtension _graphicsControl;
|
||||
|
||||
|
||||
public AnimatedImage DecodeImage(Stream stream)
|
||||
{
|
||||
_image = new AnimatedImage();
|
||||
|
||||
_stream = stream;
|
||||
_stream.Seek(6, SeekOrigin.Current);
|
||||
|
||||
ReadLogicalScreenDescriptor();
|
||||
|
||||
if (_logicalScreenDescriptor.GlobalColorTableFlag == true)
|
||||
{
|
||||
_globalColorTable = new byte[_logicalScreenDescriptor.GlobalColorTableSize * 3];
|
||||
|
||||
// Read the global color table from the stream
|
||||
stream.Read(_globalColorTable, 0, _globalColorTable.Length);
|
||||
}
|
||||
|
||||
int nextFlag = stream.ReadByte();
|
||||
while (nextFlag != 0)
|
||||
{
|
||||
if (nextFlag == ImageLabel)
|
||||
{
|
||||
ReadFrame();
|
||||
}
|
||||
else if (nextFlag == ExtensionIntroducer)
|
||||
{
|
||||
int gcl = stream.ReadByte();
|
||||
switch (gcl)
|
||||
{
|
||||
case GraphicControlLabel:
|
||||
ReadGraphicalControlExtension();
|
||||
break;
|
||||
case CommentLabel:
|
||||
ReadComments();
|
||||
break;
|
||||
case ApplicationExtensionLabel:
|
||||
Skip(12);
|
||||
break;
|
||||
case PlainTextLabel:
|
||||
Skip(13);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (nextFlag == EndIntroducer)
|
||||
{
|
||||
break;
|
||||
}
|
||||
nextFlag = stream.ReadByte();
|
||||
}
|
||||
return _image;
|
||||
}
|
||||
|
||||
private void ReadGraphicalControlExtension()
|
||||
{
|
||||
byte[] buffer = new byte[6];
|
||||
|
||||
_stream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
byte packed = buffer[1];
|
||||
|
||||
_graphicsControl = new GifGraphicsControlExtension();
|
||||
_graphicsControl.DelayTime = BitConverter.ToInt16(buffer, 2);
|
||||
_graphicsControl.TransparencyIndex = buffer[4];
|
||||
_graphicsControl.TransparencyFlag = (packed & 0x01) == 1;
|
||||
_graphicsControl.DisposalMethod = (DisposalMethod)((packed & 0x1C) >> 2);
|
||||
}
|
||||
|
||||
private GifImageDescriptor ReadImageDescriptor()
|
||||
{
|
||||
byte[] buffer = new byte[9];
|
||||
|
||||
_stream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
byte packed = buffer[8];
|
||||
|
||||
GifImageDescriptor imageDescriptor = new GifImageDescriptor();
|
||||
imageDescriptor.Left = BitConverter.ToInt16(buffer, 0);
|
||||
imageDescriptor.Top = BitConverter.ToInt16(buffer, 2);
|
||||
imageDescriptor.Width = BitConverter.ToInt16(buffer, 4);
|
||||
imageDescriptor.Height = BitConverter.ToInt16(buffer, 6);
|
||||
imageDescriptor.LocalColorTableFlag = ((packed & 0x80) >> 7) == 1;
|
||||
imageDescriptor.LocalColorTableSize = 2 << (packed & 0x07);
|
||||
imageDescriptor.InterlaceFlag = ((packed & 0x40) >> 6) == 1;
|
||||
|
||||
return imageDescriptor;
|
||||
}
|
||||
|
||||
private void ReadLogicalScreenDescriptor()
|
||||
{
|
||||
byte[] buffer = new byte[7];
|
||||
|
||||
_stream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
byte packed = buffer[4];
|
||||
|
||||
_logicalScreenDescriptor = new GifLogicalScreenDescriptor();
|
||||
_logicalScreenDescriptor.Width = BitConverter.ToInt16(buffer, 0);
|
||||
_logicalScreenDescriptor.Height = BitConverter.ToInt16(buffer, 2);
|
||||
_logicalScreenDescriptor.Background = buffer[5];
|
||||
_logicalScreenDescriptor.GlobalColorTableFlag = ((packed & 0x80) >> 7) == 1;
|
||||
_logicalScreenDescriptor.GlobalColorTableSize = 2 << (packed & 0x07);
|
||||
}
|
||||
|
||||
private void Skip(int length)
|
||||
{
|
||||
_stream.Seek(length, SeekOrigin.Current);
|
||||
|
||||
int flag = 0;
|
||||
|
||||
while ((flag = _stream.ReadByte()) != 0)
|
||||
{
|
||||
_stream.Seek(flag, SeekOrigin.Current);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadComments()
|
||||
{
|
||||
int flag = 0;
|
||||
|
||||
while ((flag = _stream.ReadByte()) != 0)
|
||||
{
|
||||
byte[] buffer = new byte[flag];
|
||||
_stream.Read(buffer, 0, flag);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadFrame()
|
||||
{
|
||||
GifImageDescriptor imageDescriptor = ReadImageDescriptor();
|
||||
|
||||
byte[] localColorTable = ReadFrameLocalColorTable(imageDescriptor);
|
||||
|
||||
byte[] indices = ReadFrameIndices(imageDescriptor);
|
||||
|
||||
// Determine the color table for this frame. If there is a local one, use it
|
||||
// otherwise use the global color table.
|
||||
byte[] colorTable = localColorTable != null ? localColorTable : _globalColorTable;
|
||||
|
||||
ReadFrameColors(indices, colorTable, imageDescriptor);
|
||||
|
||||
int blockSize = _stream.ReadByte();
|
||||
if (blockSize > 0)
|
||||
{
|
||||
_stream.Seek(blockSize, SeekOrigin.Current);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] ReadFrameIndices(GifImageDescriptor imageDescriptor)
|
||||
{
|
||||
int dataSize = _stream.ReadByte();
|
||||
|
||||
LZWDecoder lzwDecoder = new LZWDecoder(_stream);
|
||||
|
||||
byte[] indices = lzwDecoder.DecodePixels(imageDescriptor.Width, imageDescriptor.Height, dataSize);
|
||||
return indices;
|
||||
}
|
||||
|
||||
private byte[] ReadFrameLocalColorTable(GifImageDescriptor imageDescriptor)
|
||||
{
|
||||
byte[] localColorTable = null;
|
||||
|
||||
if (imageDescriptor.LocalColorTableFlag == true)
|
||||
{
|
||||
localColorTable = new byte[imageDescriptor.LocalColorTableSize * 3];
|
||||
|
||||
_stream.Read(localColorTable, 0, localColorTable.Length);
|
||||
}
|
||||
|
||||
return localColorTable;
|
||||
}
|
||||
|
||||
private void ReadFrameColors(byte[] indices, byte[] colorTable, GifImageDescriptor descriptor)
|
||||
{
|
||||
int imageWidth = _logicalScreenDescriptor.Width;
|
||||
int imageHeight = _logicalScreenDescriptor.Height;
|
||||
|
||||
if (_currentFrame == null)
|
||||
{
|
||||
_currentFrame = new byte[imageWidth * imageHeight * 4];
|
||||
}
|
||||
|
||||
byte[] lastFrame = null;
|
||||
|
||||
if (_graphicsControl != null &&
|
||||
_graphicsControl.DisposalMethod == DisposalMethod.RestoreToPrevious)
|
||||
{
|
||||
lastFrame = new byte[imageWidth * imageHeight * 4];
|
||||
|
||||
Array.Copy(_currentFrame, lastFrame, lastFrame.Length);
|
||||
}
|
||||
|
||||
int offset = 0, i = 0, index = -1;
|
||||
|
||||
int iPass = 0; // the interlace pass
|
||||
int iInc = 8; // the interlacing line increment
|
||||
int iY = 0; // the current interlaced line
|
||||
int writeY = 0; // the target y offset to write to
|
||||
|
||||
for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++)
|
||||
{
|
||||
// Check if this image is interlaced.
|
||||
if (descriptor.InterlaceFlag)
|
||||
{
|
||||
// If so then we read lines at predetermined offsets.
|
||||
// When an entire image height worth of offset lines has been read we consider this a pass.
|
||||
// With each pass the number of offset lines changes and the starting line changes.
|
||||
if (iY >= descriptor.Height)
|
||||
{
|
||||
iPass++;
|
||||
switch (iPass)
|
||||
{
|
||||
case 1:
|
||||
iY = 4;
|
||||
break;
|
||||
case 2:
|
||||
iY = 2;
|
||||
iInc = 4;
|
||||
break;
|
||||
case 3:
|
||||
iY = 1;
|
||||
iInc = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writeY = iY + descriptor.Top;
|
||||
|
||||
iY += iInc;
|
||||
}
|
||||
else
|
||||
{
|
||||
writeY = y;
|
||||
}
|
||||
|
||||
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++)
|
||||
{
|
||||
offset = writeY * imageWidth + x;
|
||||
|
||||
index = indices[i];
|
||||
|
||||
if (_graphicsControl == null ||
|
||||
_graphicsControl.TransparencyFlag == false ||
|
||||
_graphicsControl.TransparencyIndex != index)
|
||||
{
|
||||
_currentFrame[offset * 4 + 0] = colorTable[index * 3 + 0];
|
||||
_currentFrame[offset * 4 + 1] = colorTable[index * 3 + 1];
|
||||
_currentFrame[offset * 4 + 2] = colorTable[index * 3 + 2];
|
||||
_currentFrame[offset * 4 + 3] = (byte)255;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] pixels = new byte[imageWidth * imageHeight * 4];
|
||||
|
||||
Array.Copy(_currentFrame, pixels, pixels.Length);
|
||||
_currentFrame = new byte[imageWidth * imageHeight * 4];
|
||||
Image frame = new Image(imageWidth, imageHeight);
|
||||
|
||||
int indx = 0;
|
||||
byte r, g, b, a;
|
||||
for (uint y = 0; y < frame.Height; y++)
|
||||
{
|
||||
for (uint x = 0; x < frame.Width; x++)
|
||||
{
|
||||
r = pixels[indx];
|
||||
indx++;
|
||||
g = pixels[indx];
|
||||
indx++;
|
||||
b = pixels[indx];
|
||||
indx++;
|
||||
a = pixels[indx];
|
||||
indx++;
|
||||
frame.SetPixel(x, y, new Pixel(r, g, b, a));
|
||||
}
|
||||
}
|
||||
pixels = null;
|
||||
System.GC.Collect();
|
||||
_image.AddFrame(frame);
|
||||
|
||||
|
||||
if (_graphicsControl != null)
|
||||
{
|
||||
if (_graphicsControl.DelayTime > 0)
|
||||
{
|
||||
_image.TimePerFrame = _graphicsControl.DelayTime;
|
||||
}
|
||||
|
||||
if (_graphicsControl.DisposalMethod == DisposalMethod.RestoreToBackground)
|
||||
{
|
||||
Image im = new Image(imageWidth, imageHeight);
|
||||
im.Clear(new Pixel(true));
|
||||
_image.AddFrame(im);
|
||||
_image.Loop = false;
|
||||
|
||||
}
|
||||
else if (_graphicsControl.DisposalMethod == DisposalMethod.RestoreToPrevious)
|
||||
{
|
||||
_image.Loop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GifImageDescriptor
|
||||
private sealed class GifImageDescriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Column number, in pixels, of the left edge of the image,
|
||||
/// with respect to the left edge of the Logical Screen.
|
||||
/// Leftmost column of the Logical Screen is 0.
|
||||
/// </summary>
|
||||
public short Left;
|
||||
/// <summary>
|
||||
/// Row number, in pixels, of the top edge of the image with
|
||||
/// respect to the top edge of the Logical Screen.
|
||||
/// Top row of the Logical Screen is 0.
|
||||
/// </summary>
|
||||
public short Top;
|
||||
/// <summary>
|
||||
/// Width of the image in pixels.
|
||||
/// </summary>
|
||||
public short Width;
|
||||
/// <summary>
|
||||
/// Height of the image in pixels.
|
||||
/// </summary>
|
||||
public short Height;
|
||||
/// <summary>
|
||||
/// Indicates the presence of a Local Color Table immediately
|
||||
/// following this Image Descriptor.
|
||||
/// </summary>
|
||||
public bool LocalColorTableFlag;
|
||||
/// <summary>
|
||||
/// If the Local Color Table Flag is set to 1, the value in this field
|
||||
/// is used to calculate the number of bytes contained in the Local Color Table.
|
||||
/// </summary>
|
||||
public int LocalColorTableSize;
|
||||
/// <summary>
|
||||
/// Indicates if the image is interlaced. An image is interlaced
|
||||
/// in a four-pass interlace pattern.
|
||||
/// </summary>
|
||||
public bool InterlaceFlag;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GifLogicalScreenDescriptor
|
||||
private sealed class GifLogicalScreenDescriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Width, in pixels, of the Logical Screen where the images will
|
||||
/// be rendered in the displaying device.
|
||||
/// </summary>
|
||||
public short Width;
|
||||
/// <summary>
|
||||
/// Height, in pixels, of the Logical Screen where the images will be
|
||||
/// rendered in the displaying device.
|
||||
/// </summary>
|
||||
public short Height;
|
||||
/// <summary>
|
||||
/// Index into the Global Color Table for the Background Color.
|
||||
/// The Background Color is the color used for those
|
||||
/// pixels on the screen that are not covered by an image.
|
||||
/// </summary>
|
||||
public byte Background;
|
||||
/// <summary>
|
||||
/// Flag indicating the presence of a Global Color Table;
|
||||
/// if the flag is set, the Global Color Table will immediately
|
||||
/// follow the Logical Screen Descriptor.
|
||||
/// </summary>
|
||||
public bool GlobalColorTableFlag;
|
||||
/// <summary>
|
||||
/// If the Global Color Table Flag is set to 1,
|
||||
/// the value in this field is used to calculate the number of
|
||||
/// bytes contained in the Global Color Table.
|
||||
/// </summary>
|
||||
public int GlobalColorTableSize;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GifGraphicsControlExtension
|
||||
private sealed class GifGraphicsControlExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the way in which the graphic is to be treated after being displayed.
|
||||
/// </summary>
|
||||
public DisposalMethod DisposalMethod;
|
||||
/// <summary>
|
||||
/// Indicates whether a transparency index is given in the Transparent Index field.
|
||||
/// (This field is the least significant bit of the byte.)
|
||||
/// </summary>
|
||||
public bool TransparencyFlag;
|
||||
/// <summary>
|
||||
/// The Transparency Index is such that when encountered, the corresponding pixel
|
||||
/// of the display device is not modified and processing goes on to the next pixel.
|
||||
/// </summary>
|
||||
public int TransparencyIndex;
|
||||
/// <summary>
|
||||
/// If not 0, this field specifies the number of hundredths (1/100) of a second to
|
||||
/// wait before continuing with the processing of the Data Stream.
|
||||
/// The clock starts ticking immediately after the graphic is rendered.
|
||||
/// This field may be used in conjunction with the User Input Flag field.
|
||||
/// </summary>
|
||||
public int DelayTime;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region LZWDecoder
|
||||
private sealed class LZWDecoder
|
||||
{
|
||||
private const int StackSize = 4096;
|
||||
private const int NullCode = -1;
|
||||
|
||||
private Stream _stream;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LZWDecoder"/> class
|
||||
/// and sets the stream, where the compressed data should be read from.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream. where to read from.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="stream"/> is null
|
||||
/// (Nothing in Visual Basic).</exception>
|
||||
public LZWDecoder(Stream stream)
|
||||
{
|
||||
_stream = stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes and uncompresses all pixel indices from the stream.
|
||||
/// </summary>
|
||||
/// <param name="width">The width of the pixel index array.</param>
|
||||
/// <param name="height">The height of the pixel index array.</param>
|
||||
/// <param name="dataSize">Size of the data.</param>
|
||||
/// <returns>The decoded and uncompressed array.</returns>
|
||||
public byte[] DecodePixels(int width, int height, int dataSize)
|
||||
{
|
||||
byte[] pixels = new byte[width * height];
|
||||
int clearCode = 1 << dataSize;
|
||||
if (dataSize == Int32.MaxValue)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("dataSize", "Must be less than Int32.MaxValue");
|
||||
}
|
||||
int codeSize = dataSize + 1;
|
||||
int endCode = clearCode + 1;
|
||||
int availableCode = clearCode + 2;
|
||||
#region Jillzhangs Code (Not From Me) see: http://giflib.codeplex.com/
|
||||
int code = NullCode;
|
||||
int old_code = NullCode;
|
||||
int code_mask = (1 << codeSize) - 1;
|
||||
int bits = 0;
|
||||
int[] prefix = new int[StackSize];
|
||||
int[] suffix = new int[StackSize];
|
||||
int[] pixelStatck = new int[StackSize + 1];
|
||||
int top = 0;
|
||||
int count = 0;
|
||||
int bi = 0;
|
||||
int xyz = 0;
|
||||
int data = 0;
|
||||
int first = 0;
|
||||
int inCode = NullCode;
|
||||
for (code = 0; code < clearCode; code++)
|
||||
{
|
||||
prefix[code] = 0;
|
||||
suffix[code] = (byte)code;
|
||||
}
|
||||
|
||||
byte[] buffer = null;
|
||||
while (xyz < pixels.Length)
|
||||
{
|
||||
if (top == 0)
|
||||
{
|
||||
if (bits < codeSize)
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
buffer = ReadBlock();
|
||||
count = buffer.Length;
|
||||
if (count == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
bi = 0;
|
||||
}
|
||||
data += buffer[bi] << bits;
|
||||
bits += 8;
|
||||
bi++;
|
||||
count--;
|
||||
continue;
|
||||
}
|
||||
code = data & code_mask;
|
||||
data >>= codeSize;
|
||||
bits -= codeSize;
|
||||
if (code > availableCode || code == endCode)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (code == clearCode)
|
||||
{
|
||||
codeSize = dataSize + 1;
|
||||
code_mask = (1 << codeSize) - 1;
|
||||
availableCode = clearCode + 2;
|
||||
old_code = NullCode;
|
||||
continue;
|
||||
}
|
||||
if (old_code == NullCode)
|
||||
{
|
||||
pixelStatck[top++] = suffix[code];
|
||||
old_code = code;
|
||||
first = code;
|
||||
continue;
|
||||
}
|
||||
inCode = code;
|
||||
if (code == availableCode)
|
||||
{
|
||||
pixelStatck[top++] = (byte)first;
|
||||
code = old_code;
|
||||
}
|
||||
while (code > clearCode)
|
||||
{
|
||||
pixelStatck[top++] = suffix[code];
|
||||
code = prefix[code];
|
||||
}
|
||||
first = suffix[code];
|
||||
if (availableCode > StackSize)
|
||||
{
|
||||
break;
|
||||
}
|
||||
pixelStatck[top++] = suffix[code];
|
||||
prefix[availableCode] = old_code;
|
||||
suffix[availableCode] = first;
|
||||
availableCode++;
|
||||
if (availableCode == code_mask + 1 && availableCode < StackSize)
|
||||
{
|
||||
codeSize++;
|
||||
code_mask = (1 << codeSize) - 1;
|
||||
}
|
||||
old_code = inCode;
|
||||
}
|
||||
top--;
|
||||
pixels[xyz++] = (byte)pixelStatck[top];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private byte[] ReadBlock()
|
||||
{
|
||||
int blockSize = _stream.ReadByte();
|
||||
return ReadBytes(blockSize);
|
||||
}
|
||||
|
||||
private byte[] ReadBytes(int length)
|
||||
{
|
||||
byte[] buffer = new byte[length];
|
||||
_stream.Read(buffer, 0, length);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -42,6 +42,7 @@
|
|||
<Reference Include="System.Drawing" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AnimatedImage.cs" />
|
||||
<Compile Include="BoundingBox.cs" />
|
||||
<Compile Include="Drivers\VGADriver.cs" />
|
||||
<Compile Include="FontSupport\Font.cs" />
|
||||
|
|
@ -56,6 +57,7 @@
|
|||
<Compile Include="Image.cs" />
|
||||
<Compile Include="ImageFormats\BmpSupport.cs" />
|
||||
<Compile Include="ImageFormats\FormatManager.cs" />
|
||||
<Compile Include="ImageFormats\GifSupport.cs" />
|
||||
<Compile Include="ImageFormats\ImageFormat.cs" />
|
||||
<Compile Include="ImageFormats\JpegSupport.cs" />
|
||||
<Compile Include="ImageFormats\OifSupport.cs" />
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ namespace Orvid.Graphics.Shapes
|
|||
}
|
||||
}
|
||||
}
|
||||
public ShapedImage Parent { get; protected set; }
|
||||
public ShapedImage Parent { get; set; }
|
||||
public abstract void Draw();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ namespace Orvid.Graphics.Shapes
|
|||
{
|
||||
public class ShapedImage : Image
|
||||
{
|
||||
public bool Modified { get; internal set; }
|
||||
internal List<Shape> Shapes = new List<Shape>();
|
||||
public bool Modified { get; set; }
|
||||
public List<Shape> Shapes = new List<Shape>();
|
||||
|
||||
public ShapedImage(int width, int height) : base(width, height)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue