@@ -4,6 +4,7 @@ import android.graphics.Bitmap
44import android.graphics.Canvas
55import android.graphics.Matrix
66import android.graphics.Rect
7+ import android.graphics.RectF
78import android.os.Build
89import androidx.annotation.Keep
910import androidx.core.graphics.createBitmap
@@ -14,6 +15,7 @@ import com.margelo.nitro.core.ArrayBuffer
1415import com.margelo.nitro.core.Promise
1516import com.margelo.nitro.image.extensions.compressInMemory
1617import com.margelo.nitro.image.extensions.isGPU
18+ import com.margelo.nitro.image.extensions.isRawPixelDataAccessible
1719import com.margelo.nitro.image.extensions.pixelFormat
1820import com.margelo.nitro.image.extensions.saveToFile
1921import com.margelo.nitro.image.extensions.toFilePath
@@ -22,6 +24,7 @@ import com.margelo.nitro.image.extensions.toCpuAccessible
2224import com.margelo.nitro.image.extensions.toMutable
2325import java.io.File
2426import java.nio.ByteBuffer
27+ import kotlin.math.ceil
2528
2629@Suppress(" ConvertSecondaryConstructorToPrimary" )
2730@Keep
@@ -54,13 +57,13 @@ class HybridImage: HybridImageSpec {
5457 } else {
5558 // Copy the data into a CPU buffer (ByteBuffer)
5659 var bitmap = bitmap
57- if (bitmap.isGPU ) {
58- // If this is a GPU-based bitmap (but we cannot use GPU), copy it to a CPU Bitmap first
60+ if (! bitmap.isRawPixelDataAccessible ) {
61+ // If this is a GPU-based or otherwise unsupported Bitmap config, normalize it first.
5962 bitmap = bitmap.copy(Bitmap .Config .ARGB_8888 , false )
6063 }
6164 val buffer = bitmap.toByteBuffer()
6265 val arrayBuffer = ArrayBuffer .wrap(buffer)
63- return RawPixelData (arrayBuffer, width, height, bitmap.pixelFormat)
66+ return RawPixelData (arrayBuffer, bitmap. width.toDouble(), bitmap. height.toDouble() , bitmap.pixelFormat)
6467 }
6568 }
6669 override fun toRawPixelDataAsync (allowGpu : Boolean? ): Promise <RawPixelData > {
@@ -86,8 +89,16 @@ class HybridImage: HybridImageSpec {
8689 // 2. Create a rotation Matrix
8790 val matrix = Matrix ()
8891 matrix.setRotate(degrees.toFloat(), source.width / 2f , source.height / 2f )
92+ // Rotating around the center can move the image into negative coordinates.
93+ // Map the original bounds through the rotation to measure the full output size,
94+ // then translate the matrix back so the rotated image starts at (0, 0).
95+ val bounds = RectF (0f , 0f , source.width.toFloat(), source.height.toFloat())
96+ matrix.mapRect(bounds)
97+ matrix.postTranslate(- bounds.left, - bounds.top)
8998 // 3. Create a new blank Bitmap as our output
90- val destination = createBitmap(bitmap.width, bitmap.height)
99+ val destinationWidth = ceil(bounds.width()).toInt().coerceAtLeast(1 )
100+ val destinationHeight = ceil(bounds.height()).toInt().coerceAtLeast(1 )
101+ val destination = createBitmap(destinationWidth, destinationHeight)
91102 // 4. Draw the Bitmap to our destination
92103 Canvas (destination).apply {
93104 drawBitmap(source, matrix, null )
0 commit comments