Code Monkey home page Code Monkey logo

gifdecoder's People

Contributors

cortinico avatar pauguillamon avatar redwarp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

gifdecoder's Issues

License

Hi,

As I'm trying to use this library in a commercial project, can you please clarify a few things regarding licenses?

Are these benchmark files actually included in the library?

benchmark/src/main/java/com/bumptech/glide/gifdecoder/GifDecoder.kt: * Copyright 2014 Google, Inc. All rights reserved.
benchmark/src/main/java/com/bumptech/glide/gifdecoder/GifFrame.kt: * Copyright 2014 Google, Inc. All rights reserved.
benchmark/src/main/java/com/bumptech/glide/gifdecoder/GifHeader.kt: * Copyright 2014 Google, Inc. All rights reserved.
benchmark/src/main/java/com/bumptech/glide/gifdecoder/GifHeaderParser.kt: * Copyright 2014 Google, Inc. All rights reserved.
benchmark/src/main/java/com/bumptech/glide/gifdecoder/StandardGifDecoder.java: * Copyright (c) 2013 Xcellent Creations, Inc.
benchmark/src/main/java/com/bumptech/glide/gifdecoder/StandardGifDecoder.java: * Copyright 2014 Google, Inc. All rights reserved.

Is this bitmap.h file from AOSP actually used in the library?

giflzwdecoder/ndkheaders/bitmap.h: * Copyright (C) 2009 The Android Open Source Project

Any other thing I should take into account regarding the license?

Could also be helpful to clarify this in the README.md file ;)

Thank you so much!

Disposal not correct sometimes?

HI there, found another little bug :)

I was testing with lots of different gifs and downloaded some from Giphy, I found some stickers are not rendered correctly. For example this one (and others): https://media0.giphy.com/media/kayGhRlOKbJHCqnj9m/giphy.gif ends up in including the first frame when rendering the second:

image

I debugged a bit, this gif has 2 frames with different disposal method, the first frame being RESTORE_TO_BACKGROUND and the second DO_NOT_DISPOSE. Not sure whether that's common or not, but other tools render it correctly.

I have created a branch on my fork so you can quickly test it https://github.com/PauGuillamon/gifdecoder/commits/PGJ/car_gunna_incorrect_disposal I'm not sure what would be the best fix here, since I don't know the specs of GIF.

Let me know if I can help in any way. Thank you!

GifWrapperDrawable set callback reference weak is unsafe

the Drawable#setCallback() saved the instance via WeakReference, that won't last much longer, after several GC, the instance probably drop, which cause the playback stop unexpectedly.

so I make it strong reference myself.

class GifDrawable {
    private fun nextFrame(unschedule: Boolean) {
        // invalidateSelf()
        // turn to :
        strongCallback?.invalidateDrawable(this)
        // and so on
    }

    private var strongCallback: Callback? = null

    fun setStrongCallback(strongCallback: Callback) {
        this.strongCallback = strongCallback
    }

    override fun getCallback(): Callback? {
        return strongCallback
    }
}

speed up the playback cause UI busy, suspend to response subsequence touch events

the adjustments I mentioned in other issue is to allow user pick the playback speed, for example 1X 2X 3X 4X, but your preload work scheduling by UI thread, can't satisfy my purpose when speed turn to fast, that's why I give up the BitmapCache and preload Executor.

after I implement this in a Thread, it work but no perfect, the highest speed will cause UI busy, suspending to response subsequence touch events, must kill the process to solve, it cannot accept for user, also for me.

so I turn to SurfaceView, also I noticed you offer a simple demo for drawing gif into Surface, get rid of the UI busy problem eventually.

but still can't satisfy the speed, because decode next frame sometime slow for those large resolution frame, most time wasting in the lzw data decode, so I plan to have a preloader which step forward only to pre decode next frame's lzw data, via Coroutines I think, I want to ask if you have some advices to achive this, thanks

Random access file: handle file deleted case

With 0.4.0 comes reading the gif from a random access file. Cool. But what happens if the file gets deleted?
It crashes.

It might be cool to create or reuse an exception for:

  • failing to parse a file that doesn't exists
  • a file that got properly parsed gets deleted before we ask to get a frame.

Parser.readImageData() infinite loop may never break for a broken gif file

in case of a broken gif

fun ReplayInputStream.readImageData(): ImageData {
        val position = getPosition()
        var length = 1
        skip(1)
        while (true) {
            val blockSize = readUByte().toInt()
            length++
            if (blockSize == 0) {
                // never reach
                break
            }
            length += blockSize
            skip(blockSize.toLong())
        }

        return ImageData(position, length)
    }

IndexOutOfBoundsException in the decoder

The decoder sometimes throws exception on multipl IndexOutOfBoundsExceptions:

java.lang.ArrayIndexOutOfBoundsException: 
  at net.redwarp.gif.decoder.lzw.LzwDecoder.decode (LzwDecoder.java:100)
  at net.redwarp.gif.decoder.Gif.getFrame (Gif.java:98)
  at net.redwarp.gif.decoder.Gif.getCurrentFrame (Gif.java:24)
java.lang.IndexOutOfBoundsException: 
  at java.util.ArrayList.get (ArrayList.java:437)
  at net.redwarp.gif.decoder.Gif.getFrame (Gif.java:17)
  at net.redwarp.gif.decoder.Gif.getCurrentFrame (Gif.java:24)
java.lang.ArrayIndexOutOfBoundsException: 
  at net.redwarp.gif.decoder.Gif.fillPixelsInterlaced (Gif.java:79)
  at net.redwarp.gif.decoder.Gif.fillPixels (Gif.java:6)
  at net.redwarp.gif.decoder.Gif.getFrame (Gif.java:114)
  at net.redwarp.gif.decoder.Gif.getCurrentFrame (Gif.java:24)
java.lang.ArrayIndexOutOfBoundsException: 
  at net.redwarp.gif.decoder.Gif.fillPixelsSimple (Gif.java:75)
  at net.redwarp.gif.decoder.Gif.fillPixels (Gif.java:10)
  at net.redwarp.gif.decoder.Gif.getFrame (Gif.java:114)
  at net.redwarp.gif.decoder.Gif.getCurrentFrame (Gif.java:24)

upgrade target sdk version cannot access file directly

hi, it's been a long time to come here, I upgrade my app's targetSdkVersion to 34, now I can't access the media resource by File api, only Uri, I can get the absolute path from it, but when I try to turn it as RandomAccessFile, I got a FileNotFoundException, so the problem is we can't have a RandomAccessFile easily any more, only take the return from ContentResolver#openFileDescriptor(android.net.Uri) which cannot turn to RandomAccessFile directly

Change group id to app.redwarp.gif

Turns out that for maven central, I need to own the domain name corresponding to the group.
Which is fine. But as some rando already bought redwarp.net, I have to change to a new group.
I could get the domain name redwarp.app, so I guess we will go for that.

Advancing multiple frames results in artifacts

When advancing multiple frames without calling getCurrentFrame(), the pixels contain artifacts. I have changed the sample app to call advance() twice before getting the frame, I got this:
gifdecoder_artifacts_1
gifdecoder_artifacts_2

The use case for this would be integrating Gif into a rendering engine where advancing frames is calculated on each frame update. If the frame rate of the engine is slower than the gif's, then advance() needs to be called multiple times in a frame resulting in this issue. Temporary workaround would be to explicitly call getCurrentFrame() after each advance() call, but I'm sure we can improve this :)

I am not sure if calling getCurrentFrame() internally when advance() is called would be the best solution, but it would fix the problem. I am not into the details of decoding, but it sounds like we need to decode frame by frame?

ArrayIndexOutOfBoundsException: length=4096; index=4096 at LzwDecoder.decode()

Hi, the decode step would cause ArrayIndexOutOfBoundsException sometime

private const val MAX_STACK_SIZE = 4096
private val prefix = ShortArray(MAX_STACK_SIZE)

fun decode(imageData: ByteArray, destination: ByteArray, pixelCount: Int) {
val lzwMinimumCodeSize = imageData[dataIndex]
val clear: Int = 1.shl(lzwMinimumCodeSize.toInt())

for (code in 0 until clear) {
    prefix[code] = 0
    suffix[code] = code.toByte()
}

once lzwMinimumCodeSize's value greater than 12, I can't make sure that gif file is corrupted or not due to it happened from my user's devices, but it is infrequent, the last report was two months ago, about 20 times totally, probably the files was broken.

just to ask if you have any idea.

A really small gifs with modified header to appear big will use up lots of memory for nothing

Similar to libjpeg-turbo/libjpeg-turbo#560

If we modify the header of the gif to declare a size much bigger than the gif actually is (so, corrupted gif), we will allocate the theoritical maximum for no reason.

We could try to find a heuristic to exit early:
A typical compression ratio of the gif seems to range between 4:1 to 10:1 (http://ist.uwaterloo.ca/~anderson/images/GIFvsJPEG/compression_rates.html)

So, if the size of the inputstream is available (might not be the case), we could exist early if we detect that the size declared of the gif is more than 15 time bigger than the data stream)

For exemple, if we read the header and the gif is 100x100pixel, meaning 10000 pixels, but the gif size is only 100 bytes, then it's really fishy.

Max size gifs can't be decoded as it wont fit in memory.

A theoritical max gif is 65535x65535, meaning 4_294_836_225 pixels. The code creates an array to store these pixels. But in java, the max size of an array is around Integer.MAX_VALUE (apparently depends on the VM, can be minus 2 or minus 8), so around 2_147_483_648.
It means that the library is actually unable to decode gifs that size ๐Ÿค”, and will throw an exception.

only one bitmap instance through the whole decode procedure

the BitmapCache is good for preload next frame, but it allocating two more bitmaps in memory, for me, I turn to single bitmap, that means I can't benefit from the prepareNextFrame work, but it doesn't matter as I have some other adjustments make me discard your preload job.

below are the key code, omit some unimportant lines

class GifDrawable {
    private val frameBitmap = Bitmap.createBitmap(gifWidth, gifHeight, Bitmap.Config.ARGB_8888)

    fun renderNextFrame(): Long {
        val nextIndex = (++gifState.frameIndex) % gif.frameCount
        val result = gif.getFrame(nextIndex, frameBitmap)
        if (result.isSuccess) {
            frameBitmap.prepareToDraw()
            invalidateSelf()
        }
    }
}

class Gif {
    fun getFrame(index: Int, frameBitmap: Bitmap): Result<Any?> {
        while (currentIndex != index) {
            advance().onFailure { return Result.failure(it) }
        }
        return getCurrentFrame(frameBitmap)
    }

    private fun getCurrentFrame(frameBitmap: Bitmap): Result<Any?> {
        val width = frameBitmap.width
        frameBitmap.setPixels(framePixels, 0, width, 0, 0, width, frameBitmap.height)
        return Result.success(null)
    }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.