More "thread-safe" Png Encoder
Now PngEncoder and his variables should be freed after using PngEncoder().encode(...), as wanted in issue #7
This commit is contained in:
parent
d32f5f3ebf
commit
9777569c4b
|
@ -21,6 +21,7 @@ import java.util.zip.CRC32
|
|||
// TODO CREATE A BETTER CLASS
|
||||
/**
|
||||
* Create an APNG file
|
||||
* If you want to create an APNG, use ApngEncoder instead
|
||||
*/
|
||||
@Suppress("unused")
|
||||
class Apng {
|
||||
|
@ -54,9 +55,9 @@ class Apng {
|
|||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
fun addFrames(bitmap : Bitmap, index : Int? = null, delay : Float = 1000f, xOffset : Int = 0, yOffset : Int = 0, disposeOp: Utils.Companion.DisposeOp = Utils.Companion.DisposeOp.APNG_DISPOSE_OP_NONE, blendOp: Utils.Companion.BlendOp = Utils.Companion.BlendOp.APNG_BLEND_OP_SOURCE) {
|
||||
if (index == null)
|
||||
frames.add(Frame(PngEncoder.encode(bitmap, true), delay, xOffset, yOffset, blendOp, disposeOp))
|
||||
frames.add(Frame(PngEncoder().encode(bitmap, true), delay, xOffset, yOffset, blendOp, disposeOp))
|
||||
else
|
||||
frames.add(index, Frame(PngEncoder.encode(bitmap, true), delay, xOffset, yOffset, blendOp, disposeOp))
|
||||
frames.add(index, Frame(PngEncoder().encode(bitmap, true), delay, xOffset, yOffset, blendOp, disposeOp))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,7 +155,7 @@ class Apng {
|
|||
// Add cover image : Not part of animation
|
||||
// region IDAT
|
||||
val idat = IDAT()
|
||||
idat.parse(PngEncoder.encode(cover!!, true, 1))
|
||||
idat.parse(PngEncoder().encode(cover!!, true, 1))
|
||||
idat.IDATBody.forEach {
|
||||
val idatByteArray = ArrayList<Byte>()
|
||||
framesByte.addAll(to4Bytes(it.size).asList())
|
||||
|
@ -422,11 +423,11 @@ class Apng {
|
|||
it.maxHeight = maxHeight
|
||||
}
|
||||
val drawedFrame = ApngAnimator(null).draw(frames)
|
||||
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "frame0.png").writeBytes(PngEncoder.encode(drawedFrame[0]))
|
||||
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "frame0.png").writeBytes(PngEncoder().encode(drawedFrame[0]))
|
||||
for (i in 1 until frames.size) {
|
||||
val diffCalculator = BitmapDiffCalculator(drawedFrame[i - 1], drawedFrame[i])
|
||||
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "frame$i.png").writeBytes(PngEncoder.encode(diffCalculator.res, true))
|
||||
frames[i].byteArray = PngEncoder.encode(diffCalculator.res, true)
|
||||
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "frame$i.png").writeBytes(PngEncoder().encode(diffCalculator.res, true))
|
||||
frames[i].byteArray = PngEncoder().encode(diffCalculator.res, true)
|
||||
frames[i].xOffsets = diffCalculator.xOffset
|
||||
frames[i].yOffsets = diffCalculator.yOffset
|
||||
frames[i].blendOp = Utils.Companion.BlendOp.APNG_BLEND_OP_OVER
|
||||
|
|
|
@ -62,7 +62,7 @@ class ApngEncoder(
|
|||
|
||||
val idat = IDAT().apply {
|
||||
val byteArray = if (usePngEncoder) {
|
||||
PngEncoder.encode(btm, true)
|
||||
PngEncoder().encode(btm, true)
|
||||
} else {
|
||||
val outputStream = ByteArrayOutputStream()
|
||||
btm.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
|
||||
|
@ -114,9 +114,9 @@ class ApngEncoder(
|
|||
}
|
||||
}
|
||||
frameIndex++
|
||||
if (usePngEncoder) {
|
||||
/**if (usePngEncoder) {
|
||||
PngEncoder.release()
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
fun writeEnd() {
|
||||
|
|
|
@ -65,7 +65,7 @@ class ExperimentalApngEncoder(
|
|||
|
||||
val idat = IDAT().apply {
|
||||
val byteArray = if (usePngEncoder) {
|
||||
PngEncoder.encode(btm, true)
|
||||
PngEncoder().encode(btm, true)
|
||||
} else {
|
||||
val outputStream = ByteArrayOutputStream()
|
||||
btm.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
|
||||
|
@ -117,9 +117,9 @@ class ExperimentalApngEncoder(
|
|||
}
|
||||
}
|
||||
frameIndex++
|
||||
if (usePngEncoder) {
|
||||
/**if (usePngEncoder) {
|
||||
PngEncoder.release()
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
fun writeEnd() {
|
||||
|
|
|
@ -10,15 +10,11 @@ import kotlin.math.max
|
|||
import kotlin.math.min
|
||||
|
||||
// TODO FIND A BETTER SOLUTION
|
||||
// TODO ABSOLUTELY NOT THREAD SAFE, FIX THAT
|
||||
/**
|
||||
* Taken from http://catcode.com/pngencoder/com/keypoint/PngEncoder.java
|
||||
*/
|
||||
class PngEncoder {
|
||||
companion object {
|
||||
/** Encode alpha ? */
|
||||
private var encodeAlpha = true
|
||||
|
||||
/** Constants for filter (NONE) */
|
||||
private const val FILTER_NONE = 0
|
||||
|
||||
|
@ -30,15 +26,18 @@ class PngEncoder {
|
|||
|
||||
/** Constants for filter (LAST) */
|
||||
private const val FILTER_LAST = 2
|
||||
}
|
||||
/** Encode alpha ? */
|
||||
private var encodeAlpha = true
|
||||
|
||||
/** IHDR tag. */
|
||||
private val IHDR = byteArrayOf(73, 72, 68, 82)
|
||||
private val ihdr = byteArrayOf(73, 72, 68, 82)
|
||||
|
||||
/** IDAT tag. */
|
||||
private val IDAT = byteArrayOf(73, 68, 65, 84)
|
||||
private val idat = byteArrayOf(73, 68, 65, 84)
|
||||
|
||||
/** IEND tag. */
|
||||
private val IEND = byteArrayOf(73, 69, 78, 68)
|
||||
private val iend = byteArrayOf(73, 69, 78, 68)
|
||||
|
||||
/** The image. */
|
||||
private var image: Bitmap? = null
|
||||
|
@ -234,7 +233,7 @@ class PngEncoder {
|
|||
private fun writeHeader() {
|
||||
bytePos = writeInt4(13, bytePos)
|
||||
val startPos: Int = bytePos
|
||||
bytePos = writeBytes(IHDR, bytePos)
|
||||
bytePos = writeBytes(ihdr, bytePos)
|
||||
width = image!!.width
|
||||
height = image!!.height
|
||||
bytePos = writeInt4(width, bytePos)
|
||||
|
@ -389,8 +388,8 @@ class PngEncoder {
|
|||
|
||||
crc.reset()
|
||||
bytePos = writeInt4(nCompressed, bytePos)
|
||||
bytePos = writeBytes(IDAT, bytePos)
|
||||
crc.update(IDAT)
|
||||
bytePos = writeBytes(idat, bytePos)
|
||||
crc.update(idat)
|
||||
bytePos = writeBytes(compressedLines, nCompressed, bytePos)
|
||||
crc.update(compressedLines, 0, nCompressed)
|
||||
|
||||
|
@ -410,11 +409,10 @@ class PngEncoder {
|
|||
*/
|
||||
private fun writeEnd() {
|
||||
bytePos = writeInt4(0, bytePos)
|
||||
bytePos = writeBytes(IEND, bytePos)
|
||||
bytePos = writeBytes(iend, bytePos)
|
||||
crc.reset()
|
||||
crc.update(IEND)
|
||||
crc.update(iend)
|
||||
crcValue = crc.value
|
||||
bytePos = writeInt4(crcValue.toInt(), bytePos)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ import android.content.Intent
|
|||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
|
@ -319,11 +318,7 @@ class CreatorActivity : AppCompatActivity() {
|
|||
if (BuildConfig.DEBUG)
|
||||
Log.i(TAG, "MaxWidth : $maxWidth; MaxHeight : $maxHeight")
|
||||
|
||||
val encoder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
ExperimentalApngEncoder(out, maxWidth, maxHeight, items.size, Bitmap.Config.RGBA_F16)
|
||||
} else {
|
||||
TODO("VERSION.SDK_INT < O")
|
||||
}
|
||||
val encoder = ExperimentalApngEncoder(out, maxWidth, maxHeight, items.size, Bitmap.Config.ARGB_8888)
|
||||
items.forEach { uri ->
|
||||
// println("delay : ${adapter?.delay?.get(i)?.toFloat() ?: 1000f}ms")
|
||||
val str =
|
||||
|
|
Loading…
Reference in New Issue