dragon66 / icafe

Java library for reading, writing, converting and manipulating images and metadata
Eclipse Public License 1.0
204 stars 58 forks source link

Help resizing animated gif #61

Closed kfredy closed 6 years ago

kfredy commented 6 years ago

Hi, I'm trying to resize a big 4M animated gif (I'm using GifDecoder but i'm getting out of Memory Exception so trying iCafe :-)). Note that i do not have access to disk so i need to resize frame by frame. (You have a note on that on the wiki but i could not figure out the process...) i assume the first step will be splitting the image: byte [] source=....; ImageWriter writer = com.icafe4j.image.ImageIO.getWriter(ImageType.GIF); ByteArrayInputStream bis = new ByteArrayInputStream(source); GIFTweaker.splitAnimatedGIF(bis, writer, "split"); bis.close(); What/how should i do next?

Thanks, Fredy

dragon66 commented 6 years ago

@kfredy Not sure if I understand you right but you already have a large animated GIF and you want to create a small animated GIF and you also don't have access to disk, right?

kfredy commented 6 years ago

Yes exactly

dragon66 commented 6 years ago

@kfredy This is how you can do it with ICAFE:

  1. Create a FrameReader which is a subclass of GIFReader used to read animated GIF frame by frame and return them as GIFFrame instances.
FrameReader reader = new FrameReader();
GIFFrame frame = null;
// Here fin is the input stream for the animated GIF
while ((frame = reader.getGIFFrameEx(fin)) != null) {
// do something with the frame
} 
  1. Initialize GIFTweaker to write animated GIF frame by frame like this:
    // Start writing animated GIF frame by frame to save memory
    GIFWriter animatedGIFWriter = new GIFWriter();
    // Apply dithering
    animatedGIFWriter.setImageParam(ImageParam.getBuilder().applyDither(true).build());
    // Set logical screen width and height to zero to use first frame width and height
    // Here fout is the output stream to hold the final animated GIF
    // The last two parameters are the logical screen width and height of the animated GIF
    // If we give it 0, 0, ICAFE will use the dimension of the first frame to write. In your case,
    // you can give it the actual dimension of the resized frame
    GIFTweaker.prepareForWrite(animatedGIFWriter, fout, 0, 0);
    // Here images is an array of GIFFrame. You can do it a different way in your case:
    // write a Frame as you read it with FrameReader
    for(int i = 0; i < images.length; i++) 
    GIFTweaker.writeFrame(animatedGIFWriter, fout, images[i]);
    // wrap it up
    GIFTweaker.finishWrite(fout);
  2. One thing I haven't mentioned is the actual resizing process you want. ICAFE comes with a limited resizing function but it works. You can use any other resizing library or write your own. Something that is not so good here is GIFFrame is ready only. That means if you want to manipulate it, you have to grab all it's fields by calling the public methods and recreate a new GIFFrame with all the changes you make to all of the fields. The scale function I mentioned called IMGUtils.getScaledInstance() which you can take a look at along with the IMGUtils.createThumbnail() function call.
kfredy commented 6 years ago

Thanks for the information. I'll take a look later on. BTW i think it will be a great addition to the package since i saw a couple of complains on other existing solutions and a need for a "working one".... Thanks again

dragon66 commented 6 years ago

@kfredy All the ingredients are there I just put them together for your specific case. If I see a relatively reasonable number of demands for this function, I can definitely add it to the package. Let's see how it works for your case.