-
-
Notifications
You must be signed in to change notification settings - Fork 854
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API Image frames refactor #326
Conversation
moved some extensions into new namespace
TODO: I do not like this, far to flaky.
… and remove the one from Image<TPixel>.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
Quick question. Do you think we should seal our Image and ImageFrame classes? I'm thinking of people attempting to build things like integral images.
https://github.com/andrewkirillov/AForge.NET/blob/master/Sources/Imaging/IntegralImage.cs
They could inherit our image class and utilize the available API.
I think it would be almost impossible at the moment to make that work for the current version... we would have to make a heap more of the internals public. I feel we should leave it sealed for v1, we can always relax things as people hit the limits of our current implementation, I feel moving over to an interface based version of the API would end up being the better choice than just unsealing |
@tocsoft I can live with that for now. |
@JimBobSquarePants I think we should keep our stuff sealed. People should follow practices like composition over inheritance for these cases like integral images. |
Just noticed this issue, can we handle this better now? |
sort of we would still need and |
/// <summary> | ||
/// Gets the root frame. | ||
/// </summary> | ||
public ImageFrame<TPixel> RootFrame => this.frames.Count > 0 ? this.frames[0] : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it valid to have 0 frames? Shouldn't we throw in the constructor instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes you can have zero frames, it will have zero when the ImageFrameCollection as been disposed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q1: Shouldn't we throw ObjectDisposedException
instead of returning null then?
Q2: Looks like it's possible to dispose an ImageFrameCollection
without disposing the underlying image bringing Image<T>
into an invalid state. Shouldn't we drop IDisposable
from ImageFrameCollection<T>
API and dispose frames directly from Image<T>.Dispose()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
yes we should probably throw an
ObjectDisposedException
. -
I don;t think its really an issue that you can dispose of the ImageFrameCollection without disposing of the image. You can do the same for ImageFrame too. I suppose we could have the Image expose and interface of
IImageFrameCollection
that doesn't supportIDisposeable
then the users can't call dispose of the collection separately to the Image.
/// </summary> | ||
/// <param name="index"> The zero-based index at which item should be inserted..</param> | ||
/// <param name="frame">The <seealso cref="ImageFrame{TPixel}"/> to insert into the <seealso cref="Image{TPixel}"/>.</param> | ||
public void Insert(int index, ImageFrame<TPixel> frame) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it really a good idea to expose a mutable List API on ImageFrameCollection
? Feels like the API surface is to wide now.
I'd rather keep it as an immuatble collection. If someone wants to implement a gif frame manipulator tool with ImageSharp (looks like a very uncommon use case), he should probably construct new image instances after calculating the frames.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if its immutable then you can't create an animated gif.. also the public api doesn't allow users to specify frames so the only way for a user to go from zero to animated gif is to create a series of images, merge their frames together into a single image instance and then save that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably matter of API taste, but I would utilize builder pattern instead, having some kind of ImageBuilder
object to construct multi-frame images. This looks like a more convenient way to preserve valid object state. Constructing ImageFrame
instances of a certain size, and verifying it against the image dimensions when calling ImageFrameCollection.Add()
looks a bit clanky to me.
But looks like ImageSharp API follows mutable style on many other places (like ImageMetaData
) so maybe it's easier to conform to this style everywhere for 1.0.
How about encapsulating the consistance rules into ImageFrameCollection
by hiding ImageFrame<T>
constructors and define methods on ImageFrameCollection<T>
:
public ImageFrame<T> AppendNewFrame() { }
public ImageFrame<T> InsertNewFrame(int index) { }
?
@JimBobSquarePants thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had thought about adding those as APIs (well in concept not name, couldn't think of what to call them) but I like it.
This makes me think we should find a way to extend the Mutate()
apis to allow us to apply mutations to single frames... might need to extend expand IImageProcessors
, as we will need IFrameProcessor
s as well as IImageProcessor
s will also have to scope some of the APIs to allow targeting only images and not frames (resize, crop, rotate etc) unless we allow images to have frames with multiple dimensions and handle normalising frame sizes on a per encoder bases instead of during add frame (i.e. update gif to draw based on the first frame dimensions)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@antonfirsov I see where you're going there and it does seem safer. As far as I can see we don't actually new up a frame anywhere within our codebase.
@tocsoft I'd rather we treated images as a whole and avoid adding IFrameProcessor
's. Seems like we'd be creating a complexity level that would be difficult to follow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should leave it as is for now then... we can worry about that later if/when people hit issues with the API.
Everything LGTM except the mutable |
@SixLabors/core so we happy enough now with this to merge into beta? |
We are really short on time, so OK for now. |
ok merging this.. we can continue any final tweeks on the beta branch |
API Image frames refactor
Prerequisites
Description
This PR has a few API changed and a significate internal refactor of where pixel data is stored.
ImageFrame
s, every Image will always have at least one image frame (unless its been disposed).SixLabor.ImageSharp.Advanced
namespace as these APIs are "Use at your own risk".SavePixelData()
apis to pair with theLoadPixelData
apis to access the raw byte array holding the image pixels data.