parent
6d1f6af7c5
commit
ef95ec2e1f
Binary file not shown.
|
@ -2,6 +2,7 @@ package oupson.apng
|
|||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Environment
|
||||
import oupson.apng.ImageUtils.BitmapDiffCalculator
|
||||
import oupson.apng.ImageUtils.PngEncoder
|
||||
import oupson.apng.ImageUtils.PnnQuantizer
|
||||
|
@ -13,6 +14,7 @@ import oupson.apng.utils.Utils.Companion.getDispose_op
|
|||
import oupson.apng.utils.Utils.Companion.pngSignature
|
||||
import oupson.apng.utils.Utils.Companion.to2Bytes
|
||||
import oupson.apng.utils.Utils.Companion.to4Bytes
|
||||
import java.io.File
|
||||
import java.util.zip.CRC32
|
||||
|
||||
/**
|
||||
|
@ -517,6 +519,9 @@ class Apng {
|
|||
it.maxWidth = maxWidth
|
||||
it.maxHeight = maxHeight
|
||||
}
|
||||
for (i in 0 until frames.size){
|
||||
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "frameCreated$i.png").writeBytes(frames[i].byteArray)
|
||||
}
|
||||
val drawedFrame = ApngAnimator(null).draw(frames)
|
||||
for (i in 1 until frames.size) {
|
||||
val diffCalculator = BitmapDiffCalculator(drawedFrame[i - 1], drawedFrame[i])
|
||||
|
|
|
@ -79,7 +79,7 @@ class ApngAnimator(private val context: Context?) {
|
|||
* @throws NotApngException
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
fun load(file: File, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) {
|
||||
fun load(file: File, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) : ApngAnimator {
|
||||
doAsync {
|
||||
val bytes = file.readBytes()
|
||||
if (isApng(bytes)) {
|
||||
|
@ -103,6 +103,7 @@ class ApngAnimator(private val context: Context?) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
|
@ -113,7 +114,7 @@ class ApngAnimator(private val context: Context?) {
|
|||
* @param speed The speed
|
||||
* @throws NotApngException
|
||||
*/
|
||||
fun load(uri : Uri, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) {
|
||||
fun load(uri : Uri, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) : ApngAnimator {
|
||||
doAsync {
|
||||
context?.contentResolver?.openInputStream(uri)?.readBytes()?.let {
|
||||
if (isApng(it)) {
|
||||
|
@ -138,6 +139,7 @@ class ApngAnimator(private val context: Context?) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -147,7 +149,7 @@ class ApngAnimator(private val context: Context?) {
|
|||
* @throws NotApngException
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
fun loadUrl(url: URL, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) {
|
||||
fun loadUrl(url: URL, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) : ApngAnimator {
|
||||
doAsync(exceptionHandler = { e -> e.printStackTrace() }) {
|
||||
this@ApngAnimator.speed = speed
|
||||
// Download PNG
|
||||
|
@ -176,6 +178,7 @@ class ApngAnimator(private val context: Context?) {
|
|||
|
||||
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -185,7 +188,7 @@ class ApngAnimator(private val context: Context?) {
|
|||
* @throws NotApngException
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
fun load(byteArray: ByteArray, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) {
|
||||
fun load(byteArray: ByteArray, speed: Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) : ApngAnimator {
|
||||
doAsync {
|
||||
this@ApngAnimator.speed = speed
|
||||
if (isApng(byteArray)) {
|
||||
|
@ -209,6 +212,7 @@ class ApngAnimator(private val context: Context?) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -217,7 +221,7 @@ class ApngAnimator(private val context: Context?) {
|
|||
* @param speed The speed
|
||||
* @throws NotApngException
|
||||
*/
|
||||
fun load(string: String, speed : Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) {
|
||||
fun load(string: String, speed : Float? = null, apngAnimatorOptions: ApngAnimatorOptions? = null) : ApngAnimator {
|
||||
doAsync {
|
||||
this@ApngAnimator.speed = speed
|
||||
if (string.contains("http") || string.contains("https")) {
|
||||
|
@ -240,6 +244,7 @@ class ApngAnimator(private val context: Context?) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
package oupson.apng
|
||||
|
||||
import android.util.Log
|
||||
import oupson.apng.chunks.IDAT
|
||||
import oupson.apng.chunks.IHDR
|
||||
import oupson.apng.exceptions.NotPngException
|
||||
import oupson.apng.utils.Utils
|
||||
import oupson.apng.utils.Utils.Companion.IDAT
|
||||
import oupson.apng.utils.Utils.Companion.IHDR
|
||||
import oupson.apng.utils.Utils.Companion.isPng
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* A frame for an animated png
|
||||
|
@ -18,12 +22,12 @@ class Frame {
|
|||
|
||||
var byteArray : ByteArray
|
||||
|
||||
var width : Int
|
||||
var height : Int
|
||||
var width : Int = -1
|
||||
var height : Int = -1
|
||||
|
||||
var ihdr : IHDR
|
||||
lateinit var ihdr : IHDR
|
||||
|
||||
var idat : IDAT
|
||||
lateinit var idat : IDAT
|
||||
|
||||
val delay : Float
|
||||
|
||||
|
@ -39,21 +43,17 @@ class Frame {
|
|||
constructor(byteArray: ByteArray) {
|
||||
if (isPng(byteArray)) {
|
||||
this.byteArray = byteArray
|
||||
Log.e("tag", byteArray.size.toString())
|
||||
// Get width and height for image
|
||||
ihdr = IHDR()
|
||||
ihdr.parse(byteArray)
|
||||
|
||||
width = ihdr.pngWidth
|
||||
height = ihdr.pngHeight
|
||||
|
||||
// Get IDAT Bytes
|
||||
idat = IDAT()
|
||||
idat.parse(byteArray)
|
||||
|
||||
delay = 1000f
|
||||
|
||||
blend_op = Utils.Companion.blend_op.APNG_BLEND_OP_SOURCE
|
||||
dispose_op = Utils.Companion.dispose_op.APNG_DISPOSE_OP_NONE
|
||||
var cursor = 8
|
||||
while (cursor < byteArray.size) {
|
||||
val chunk = byteArray.copyOfRange(cursor, cursor + Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12)
|
||||
parseChunk(chunk)
|
||||
cursor += Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12
|
||||
}
|
||||
} else {
|
||||
throw NotPngException()
|
||||
}
|
||||
|
@ -62,15 +62,12 @@ class Frame {
|
|||
if (isPng(byteArray)) {
|
||||
this.byteArray = byteArray
|
||||
// Get width and height for image
|
||||
ihdr = IHDR()
|
||||
ihdr.parse(byteArray)
|
||||
|
||||
width = ihdr.pngWidth
|
||||
height = ihdr.pngHeight
|
||||
|
||||
// Get IDAT Bytes
|
||||
idat = IDAT()
|
||||
idat.parse(byteArray)
|
||||
var cursor = 8
|
||||
while (cursor < byteArray.size) {
|
||||
val chunk = byteArray.copyOfRange(cursor, cursor + Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12)
|
||||
parseChunk(chunk)
|
||||
cursor += Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12
|
||||
}
|
||||
|
||||
this.delay = delay
|
||||
blend_op = Utils.Companion.blend_op.APNG_BLEND_OP_SOURCE
|
||||
|
@ -84,15 +81,12 @@ class Frame {
|
|||
if (isPng(byteArray)) {
|
||||
this.byteArray = byteArray
|
||||
// Get width and height for image
|
||||
ihdr = IHDR()
|
||||
ihdr.parse(byteArray)
|
||||
|
||||
width = ihdr.pngWidth
|
||||
height = ihdr.pngHeight
|
||||
|
||||
// Get IDAT Bytes
|
||||
idat = IDAT()
|
||||
idat.parse(byteArray)
|
||||
var cursor = 8
|
||||
while (cursor < byteArray.size) {
|
||||
val chunk = byteArray.copyOfRange(cursor, cursor + Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12)
|
||||
parseChunk(chunk)
|
||||
cursor += Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12
|
||||
}
|
||||
|
||||
this.delay = delay
|
||||
|
||||
|
@ -110,15 +104,12 @@ class Frame {
|
|||
if (isPng(byteArray)) {
|
||||
this.byteArray = byteArray
|
||||
// Get width and height for image
|
||||
ihdr = IHDR()
|
||||
ihdr.parse(byteArray)
|
||||
|
||||
width = ihdr.pngWidth
|
||||
height = ihdr.pngHeight
|
||||
|
||||
// Get IDAT Bytes
|
||||
idat = IDAT()
|
||||
idat.parse(byteArray)
|
||||
var cursor = 8
|
||||
while (cursor < byteArray.size) {
|
||||
val chunk = byteArray.copyOfRange(cursor, cursor + Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12)
|
||||
parseChunk(chunk)
|
||||
cursor += Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12
|
||||
}
|
||||
|
||||
this.delay = delay
|
||||
|
||||
|
@ -138,15 +129,12 @@ class Frame {
|
|||
if (isPng(byteArray)) {
|
||||
this.byteArray = byteArray
|
||||
// Get width and height for image
|
||||
ihdr = IHDR()
|
||||
ihdr.parse(byteArray)
|
||||
|
||||
width = ihdr.pngWidth
|
||||
height = ihdr.pngHeight
|
||||
|
||||
// Get IDAT Bytes
|
||||
idat = IDAT()
|
||||
idat.parse(byteArray)
|
||||
var cursor = 8
|
||||
while (cursor < byteArray.size) {
|
||||
val chunk = byteArray.copyOfRange(cursor, cursor + Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12)
|
||||
parseChunk(chunk)
|
||||
cursor += Utils.parseLength(byteArray.copyOfRange(cursor, cursor + 4)) + 12
|
||||
}
|
||||
|
||||
this.delay = delay
|
||||
|
||||
|
@ -161,4 +149,20 @@ class Frame {
|
|||
throw NotPngException()
|
||||
}
|
||||
}
|
||||
|
||||
fun parseChunk(byteArray: ByteArray) {
|
||||
when(Arrays.toString(byteArray.copyOfRange(4, 8))) {
|
||||
IHDR -> {
|
||||
ihdr = IHDR()
|
||||
ihdr.parse(byteArray)
|
||||
width = ihdr.pngWidth
|
||||
height = ihdr.pngHeight
|
||||
}
|
||||
IDAT -> {
|
||||
// Get IDAT Bytes
|
||||
idat = IDAT()
|
||||
idat.parse(byteArray)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -80,22 +80,22 @@ class PngEncoder {
|
|||
* @param compressionLevel ! Don't use it : It's buggy
|
||||
*/
|
||||
fun encode(image: Bitmap, encodeAlpha: Boolean = false, filter: Int = 0, compressionLevel: Int = 0): ByteArray {
|
||||
Companion.filter = FILTER_NONE
|
||||
this.filter = FILTER_NONE
|
||||
if (filter <= FILTER_LAST) {
|
||||
Companion.filter = filter
|
||||
this.filter = filter
|
||||
}
|
||||
|
||||
if (compressionLevel in 0..9) {
|
||||
Companion.compressionLevel = compressionLevel
|
||||
this.compressionLevel = compressionLevel
|
||||
}
|
||||
|
||||
Companion.encodeAlpha = encodeAlpha
|
||||
this.encodeAlpha = encodeAlpha
|
||||
|
||||
|
||||
val pngIdBytes = byteArrayOf(-119, 80, 78, 71, 13, 10, 26, 10)
|
||||
width = image.width
|
||||
height = image.height
|
||||
Companion.image = image
|
||||
this.image = image
|
||||
/*
|
||||
* start with an array that is big enough to hold all the pixels
|
||||
* (plus filter bytes), and an extra 200 bytes for header info
|
||||
|
@ -221,9 +221,8 @@ class PngEncoder {
|
|||
* Write a PNG "IHDR" chunk into the pngBytes array.
|
||||
*/
|
||||
private fun writeHeader() {
|
||||
val startPos: Int = bytePos
|
||||
|
||||
bytePos = writeInt4(13, bytePos)
|
||||
val startPos: Int = bytePos
|
||||
bytePos = writeBytes(IHDR, bytePos)
|
||||
width = image!!.width
|
||||
height = image!!.height
|
||||
|
|
|
@ -4,11 +4,9 @@ import android.app.Activity
|
|||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Canvas
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.util.Log
|
||||
import kotlinx.android.synthetic.main.activity_creator.*
|
||||
import org.jetbrains.anko.alert
|
||||
import org.jetbrains.anko.customView
|
||||
|
@ -17,7 +15,6 @@ import org.jetbrains.anko.sdk27.coroutines.onClick
|
|||
import oupson.apng.APNGDisassembler
|
||||
import oupson.apng.Apng
|
||||
import oupson.apng.ApngAnimator
|
||||
import oupson.apng.ImageUtils.PngEncoder
|
||||
import oupson.apngcreator.adapter.frameListViewAdapter
|
||||
import java.io.File
|
||||
|
||||
|
@ -45,33 +42,30 @@ class CreatorActivity : AppCompatActivity() {
|
|||
fab_create.onClick {
|
||||
var apngCreated = Apng()
|
||||
|
||||
items.forEach {
|
||||
apngCreated.addFrames(it)
|
||||
items.forEach { bitmap ->
|
||||
apngCreated.addFrames(bitmap)
|
||||
}
|
||||
|
||||
|
||||
Log.e("tag", apngCreated.frames.size.toString())
|
||||
apngCreated = APNGDisassembler.disassemble(apngCreated.toByteArray())
|
||||
apngCreated.optimiseFrame()
|
||||
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "vtm").writeBytes(apngCreated.toByteArray())
|
||||
apngCreated = APNGDisassembler.disassemble(apngCreated.toByteArray()).apply {
|
||||
optimiseFrame()
|
||||
}
|
||||
val a = ApngAnimator(applicationContext)
|
||||
|
||||
|
||||
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "apn.png").writeBytes(apngCreated.toByteArray())
|
||||
a.load(apngCreated.toByteArray())
|
||||
a.onLoaded {
|
||||
alert {
|
||||
a.onLoaded { anim ->
|
||||
alert {
|
||||
customView {
|
||||
imageView {
|
||||
Log.e("tag", "${it.anim?.numberOfFrames.toString()} : ${items.size}")
|
||||
it.anim?.let {
|
||||
for (i in 0 until it.numberOfFrames) {
|
||||
val vt = Bitmap.createBitmap(it.getFrame(i).intrinsicWidth, it.getFrame(i).intrinsicHeight, Bitmap.Config.ARGB_8888)
|
||||
/**anim.anim?.let {cu ->
|
||||
for (i in 0 until cu.numberOfFrames) {
|
||||
val vt = Bitmap.createBitmap(cu.getFrame(i).intrinsicWidth, cu.getFrame(i).intrinsicHeight, Bitmap.Config.ARGB_8888)
|
||||
val canvas = Canvas(vt)
|
||||
it.getFrame(i).draw(canvas)
|
||||
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "frame$i.png").writeBytes(PngEncoder.encode(vt))
|
||||
cu.getFrame(i).draw(canvas)
|
||||
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "frameCreated$i.png").writeBytes(PngEncoder.encode(vt))
|
||||
}
|
||||
}
|
||||
this.setImageDrawable(it.anim)
|
||||
this.setImageDrawable(anim.anim)
|
||||
*/
|
||||
}
|
||||
}
|
||||
}.show()
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
android:clickable="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:srcCompat="@drawable/ic_play_arrow_white_24dp" />
|
||||
app:srcCompat="@drawable/ic_add_white_24dp" />
|
||||
|
||||
<ListView
|
||||
android:id="@+id/dragView"
|
||||
|
|
Loading…
Reference in New Issue