Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.fbreact.specs.NativeImageLoaderAndroidSpec
import com.facebook.imagepipeline.common.RotationOptions
import com.facebook.imagepipeline.core.ImagePipeline
import com.facebook.imagepipeline.image.CloseableImage
import com.facebook.imagepipeline.image.EncodedImage
import com.facebook.imagepipeline.request.ImageRequest
import com.facebook.imagepipeline.request.ImageRequestBuilder
Expand Down Expand Up @@ -97,9 +98,7 @@ internal class ImageLoaderModule : NativeImageLoaderAndroidSpec, LifecycleEventL
ImageRequestBuilder.newBuilderWithSource(source.uri)
.setRotationOptions(RotationOptions.disableRotation())
.build()
val dataSource: DataSource<CloseableReference<PooledByteBuffer>> =
this.imagePipeline.fetchEncodedImage(request, this.callerContext)
dataSource.subscribe(createSizeSubscriber(promise), CallerThreadExecutor.getInstance())
fetchImageSize(request, source.uri.scheme == "data", promise)
}

/**
Expand Down Expand Up @@ -127,11 +126,57 @@ internal class ImageLoaderModule : NativeImageLoaderAndroidSpec, LifecycleEventL
.setRotationOptions(RotationOptions.disableRotation())
val request: ImageRequest =
ReactNetworkImageRequest.fromBuilderWithHeaders(imageRequestBuilder, headers)
fetchImageSize(request, source.uri.scheme == "data", promise)
}

private fun fetchImageSize(request: ImageRequest, isDataUri: Boolean, promise: Promise) {
if (isDataUri) {
val dataSource: DataSource<CloseableReference<CloseableImage>> =
this.imagePipeline.fetchDecodedImage(request, this.callerContext)
dataSource.subscribe(
createDecodedImageSizeSubscriber(promise),
CallerThreadExecutor.getInstance(),
)
return
}

val dataSource: DataSource<CloseableReference<PooledByteBuffer>> =
this.imagePipeline.fetchEncodedImage(request, this.callerContext)
dataSource.subscribe(createSizeSubscriber(promise), CallerThreadExecutor.getInstance())
}

private fun createDecodedImageSizeSubscriber(
promise: Promise
): DataSubscriber<CloseableReference<CloseableImage>> =
object : BaseDataSubscriber<CloseableReference<CloseableImage>>() {
override fun onNewResultImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
if (!dataSource.isFinished) {
return
}
val ref = dataSource.result
if (ref != null) {
try {
val image: CloseableImage = ref.get()
val sizes = buildReadableMap {
put("width", image.width)
put("height", image.height)
}
promise.resolve(sizes)
} catch (e: Exception) {
promise.reject(ERROR_GET_SIZE_FAILURE, e)
} finally {
CloseableReference.closeSafely(ref)
}
} else {
promise.reject(ERROR_GET_SIZE_FAILURE, "Failed to get the size of the image")
}
}

override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
promise.reject(ERROR_GET_SIZE_FAILURE, dataSource.failureCause)
}
}

private fun createSizeSubscriber(
promise: Promise
): DataSubscriber<CloseableReference<PooledByteBuffer>> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,15 @@ package com.facebook.react.modules.image

import android.content.res.Resources
import android.graphics.drawable.Drawable
import com.facebook.common.references.CloseableReference
import com.facebook.datasource.DataSource
import com.facebook.imagepipeline.core.ImagePipeline
import com.facebook.imagepipeline.image.CloseableImage
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactTestHelper
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.bridge.WritableMap
import com.facebook.react.views.image.ReactCallerContextFactory
import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper
import com.facebook.testutils.shadows.ShadowArguments
import com.facebook.testutils.shadows.ShadowSoLoader
Expand All @@ -26,6 +31,8 @@ import org.mockito.Mockito.mockStatic
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
Expand Down Expand Up @@ -177,6 +184,46 @@ class ImageLoaderModuleTest {
assertThat(promise.errorMessage).contains("no intrinsic size")
}

@Test
fun testGetSizeWithDataUriUsesDecodedImagePipeline() {
val imagePipeline = mock<ImagePipeline>()
val dataSource = mock<DataSource<CloseableReference<CloseableImage>>>()
whenever(imagePipeline.fetchDecodedImage(any(), any())).thenReturn(dataSource)
val module =
ImageLoaderModule(
ReactTestHelper.createCatalystContextForTest(),
imagePipeline,
ReactCallerContextFactory { _, _ -> null },
)

module.getSize(DATA_URI, SimplePromise())

verify(imagePipeline).fetchDecodedImage(any(), any())
verify(imagePipeline, never()).fetchEncodedImage(any(), any())
}

@Test
fun testGetSizeWithHeadersWithDataUriUsesDecodedImagePipeline() {
val imagePipeline = mock<ImagePipeline>()
val dataSource = mock<DataSource<CloseableReference<CloseableImage>>>()
whenever(imagePipeline.fetchDecodedImage(any(), any())).thenReturn(dataSource)
val module =
ImageLoaderModule(
ReactTestHelper.createCatalystContextForTest(),
imagePipeline,
ReactCallerContextFactory { _, _ -> null },
)

module.getSizeWithHeaders(
DATA_URI,
null,
SimplePromise(),
)

verify(imagePipeline).fetchDecodedImage(any(), any())
verify(imagePipeline, never()).fetchEncodedImage(any(), any())
}

@Test
fun testGetSizeWithEmptyUri() {
val promise = SimplePromise()
Expand Down Expand Up @@ -271,4 +318,9 @@ class ImageLoaderModuleTest {
reject(null, message, null, null)
}
}

companion object {
private const val DATA_URI =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="
}
}
Loading