Skip to content

Commit

Permalink
Closes #7
Browse files Browse the repository at this point in the history
  • Loading branch information
Roman Shapiro committed Jul 3, 2021
1 parent 55e833e commit 2572cb2
Show file tree
Hide file tree
Showing 10 changed files with 278 additions and 96 deletions.
2 changes: 1 addition & 1 deletion src/AnimatedFrameResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#endif
class AnimatedFrameResult : ImageResult
{
public int Delay
public int DelayInMs
{
get; set;
}
Expand Down
121 changes: 121 additions & 0 deletions src/AnimatedGifEnumerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;

namespace StbImageSharp
{
internal class AnimatedGifEnumerator: IEnumerator<AnimatedFrameResult>
{
private readonly StbImage.stbi__context _context;
private StbImage.stbi__gif _gif;
private AnimatedFrameResult _current;

public ColorComponents ColorComponents { get; private set; }

public AnimatedFrameResult Current => _current;

object IEnumerator.Current => _current;

public AnimatedGifEnumerator(Stream input, ColorComponents colorComponents)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}

_context = new StbImage.stbi__context(input);

if (StbImage.stbi__gif_test(_context) == 0)
{
throw new Exception("Input stream is not GIF file.");
}

_gif = new StbImage.stbi__gif();
ColorComponents = colorComponents;
}

~AnimatedGifEnumerator()
{
Dispose(false);
}

protected unsafe virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_gif != null)
{
_gif.Dispose();
_gif = null;
}
}
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

public unsafe bool MoveNext()
{
// Read next frame
int ccomp;
byte two_back;
var result = StbImage.stbi__gif_load_next(_context, _gif, &ccomp, (int)ColorComponents, &two_back);
if (result == null)
{
return false;
}

if (_current == null)
{
_current = new AnimatedFrameResult
{
Width = _gif.w,
Height = _gif.h,
SourceComp = (ColorComponents)ccomp,
Comp = ColorComponents == ColorComponents.Default ? (ColorComponents)ccomp : ColorComponents
};

_current.Data = new byte[_current.Width * _current.Height * (int)_current.Comp];
}

_current.DelayInMs = _gif.delay;

Marshal.Copy(new IntPtr(result), _current.Data, 0, _current.Data.Length);

return true;
}

public void Reset()
{
throw new NotImplementedException();
}
}

internal class AnimatedGifEnumerable : IEnumerable<AnimatedFrameResult>
{
private readonly Stream _input;

public ColorComponents ColorComponents { get; private set; }

public AnimatedGifEnumerable(Stream input, ColorComponents colorComponents)
{
_input = input;
ColorComponents = colorComponents;
}

public IEnumerator<AnimatedFrameResult> GetEnumerator()
{
return new AnimatedGifEnumerator(_input, ColorComponents);
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
7 changes: 7 additions & 0 deletions src/ImageResult.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;

Expand Down Expand Up @@ -82,5 +83,11 @@ public static ImageResult FromMemory(byte[] data, ColorComponents requiredCompon
return FromStream(stream, requiredComponents);
}
}

public static IEnumerable<AnimatedFrameResult> AnimatedGifFramesFromStream(Stream stream,
ColorComponents requiredComponents = ColorComponents.Default)
{
return new AnimatedGifEnumerable(stream, requiredComponents);
}
}
}
77 changes: 12 additions & 65 deletions src/StbImage.Generated.Gif.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,20 @@ public static int stbi__gif_header(stbi__context s, stbi__gif g, int* comp, int

public static int stbi__gif_info_raw(stbi__context s, int* x, int* y, int* comp)
{
var g = new stbi__gif();
if (stbi__gif_header(s, g, comp, 1) == 0)
{
stbi__rewind(s);
return 0;
using (var g = new stbi__gif())
{
if (stbi__gif_header(s, g, comp, 1) == 0)
{
stbi__rewind(s);
return 0;
}

if (x != null)
*x = g.w;
if (y != null)
*y = g.h;
}

if (x != null)
*x = g.w;
if (y != null)
*y = g.h;

return 1;
}

Expand Down Expand Up @@ -362,61 +364,6 @@ public static void stbi__out_gif_code(stbi__gif g, ushort code)
}
}

public static void* stbi__load_gif_main(stbi__context s, int** delays, int* x, int* y, int* z, int* comp,
int req_comp)
{
if (stbi__gif_test(s) != 0)
{
var layers = 0;
byte* u = null;
byte* _out_ = null;
byte* two_back = null;
var g = new stbi__gif();
var stride = 0;
if (delays != null)
*delays = null;
do
{
u = stbi__gif_load_next(s, g, comp, req_comp, two_back);
if (u != null)
{
*x = g.w;
*y = g.h;
++layers;
stride = g.w * g.h * 4;
if (_out_ != null)
{
_out_ = (byte*)CRuntime.realloc(_out_, (ulong)(layers * stride));
if (delays != null)
*delays = (int*)CRuntime.realloc(*delays, (ulong)(sizeof(int) * layers));
}
else
{
_out_ = (byte*)stbi__malloc((ulong)(layers * stride));
if (delays != null)
*delays = (int*)stbi__malloc((ulong)(layers * sizeof(int)));
}

CRuntime.memcpy(_out_ + (layers - 1) * stride, u, (ulong)stride);
if (layers >= 2)
two_back = _out_ - 2 * stride;
if (delays != null)
(*delays)[layers - 1U] = g.delay;
}
} while (u != null);

CRuntime.free(g._out_);
CRuntime.free(g.history);
CRuntime.free(g.background);
if (req_comp != 0 && req_comp != 4)
_out_ = stbi__convert_format(_out_, 4, req_comp, (uint)(layers * g.w), (uint)g.h);
*z = layers;
return _out_;
}

return (byte*)(ulong)(stbi__err("not GIF") != 0 ? (byte*)null : null);
}

public static void* stbi__gif_load(stbi__context s, int* x, int* y, int* comp, int req_comp,
stbi__result_info* ri)
{
Expand Down
34 changes: 23 additions & 11 deletions src/StbImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ public struct stbi__gif_lzw

public class stbi__gif : IDisposable
{
public byte* _out_;
public byte* background;
public byte* _out_ = null;
public byte* background = null;
public int bgindex;
public stbi__gif_lzw* codes = (stbi__gif_lzw*)stbi__malloc(8192 * sizeof(stbi__gif_lzw));
public byte* color_table;
Expand All @@ -165,13 +165,13 @@ public class stbi__gif : IDisposable
public int eflags;
public int flags;
public int h;
public byte* history;
public byte* history = null;
public int lflags;
public int line_size;
public byte* lpal;
public byte* lpal = (byte*)stbi__malloc(256 * 4 * sizeof(byte));
public int max_x;
public int max_y;
public byte* pal;
public byte* pal = (byte*)stbi__malloc(256 * 4 * sizeof(byte));
public int parse;
public int ratio;
public int start_x;
Expand All @@ -180,12 +180,6 @@ public class stbi__gif : IDisposable
public int transparent;
public int w;

public stbi__gif()
{
pal = (byte*)stbi__malloc(256 * 4 * sizeof(byte));
lpal = (byte*)stbi__malloc(256 * 4 * sizeof(byte));
}

public void Dispose()
{
if (pal != null)
Expand All @@ -205,6 +199,24 @@ public void Dispose()
CRuntime.free(codes);
codes = null;
}

if (_out_ != null)
{
CRuntime.free(_out_);
_out_ = null;
}

if (background != null)
{
CRuntime.free(background);
background = null;
}

if (history != null)
{
CRuntime.free(history);
history = null;
}
}

~stbi__gif()
Expand Down
2 changes: 1 addition & 1 deletion src/StbImageSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<Description>C# port of the stb_image.h</Description>
<PackageLicenseUrl>Public Domain</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/StbSharp/StbImageSharp</PackageProjectUrl>
<Version>2.22.5</Version>
<Version>2.22.6</Version>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions tests/StbImageSharp.Tests/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,30 @@ public void Info(string filename, int headerSize, int width, int height, ColorCo
Assert.AreEqual(info.ColorComponents, colorComponents);
Assert.AreEqual(info.BitsPerChannel, is16bit ? 16 : 8);
}

[TestCase("somersault.gif", 384, 480, ColorComponents.RedGreenBlueAlpha, 43)]
public void AnimatedGifFrames(string fileName, int width, int height, ColorComponents colorComponents, int originalFrameCount)
{
using (var stream = _assembly.OpenResourceStream(fileName))
{
var frameCount = 0;
foreach(var frame in ImageResult.AnimatedGifFramesFromStream(stream))
{
Assert.AreEqual(frame.Width, width);
Assert.AreEqual(frame.Height, height);
Assert.AreEqual(frame.Comp, colorComponents);
Assert.IsNotNull(frame.Data);
Assert.AreEqual(frame.Data.Length, frame.Width * frame.Height * (int)frame.Comp);

++frameCount;
}

Assert.AreEqual(frameCount, originalFrameCount);

stream.Seek(0, SeekOrigin.Begin);
}

Assert.AreEqual(MemoryStats.Allocations, 0);
}
}
}
10 changes: 8 additions & 2 deletions tests/StbImageSharp.Viewer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,19 @@ static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("Usage: StbImageSharp.Viewer <path_to_image_file>");
Console.WriteLine("Usage: StbImageSharp.Viewer <path_to_image_file> [-animated-gif]");
return;
}

try
{
using (var game = new ViewerGame(args[0]))
var isAnimatedGif = false;
if (args.Length > 1 && args[1] == "-animated-gif")
{
isAnimatedGif = true;
}

using (var game = new ViewerGame(args[0], isAnimatedGif))
game.Run();
}
catch(Exception ex)
Expand Down
Loading

0 comments on commit 2572cb2

Please sign in to comment.