Skip to content

Commit 0928881

Browse files
committed
feature: Use cache for images from network
1 parent 9813b2c commit 0928881

File tree

3 files changed

+109
-13
lines changed

3 files changed

+109
-13
lines changed

android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorModuleImpl.kt

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,18 @@ import android.provider.MediaStore
2121
import android.text.TextUtils
2222
import android.util.Base64
2323
import androidx.exifinterface.media.ExifInterface
24+
import com.facebook.common.executors.CallerThreadExecutor
2425
import com.facebook.common.logging.FLog
26+
import com.facebook.common.memory.PooledByteBuffer
27+
import com.facebook.common.memory.PooledByteBufferInputStream
28+
import com.facebook.common.references.CloseableReference
29+
import com.facebook.datasource.BaseDataSubscriber
30+
import com.facebook.datasource.DataSource
31+
import com.facebook.datasource.DataSubscriber
32+
import com.facebook.drawee.backends.pipeline.Fresco
33+
import com.facebook.imagepipeline.core.ImagePipeline
34+
import com.facebook.imagepipeline.request.ImageRequest
35+
import com.facebook.imagepipeline.request.ImageRequestBuilder
2536
import com.facebook.infer.annotation.Assertions
2637
import com.facebook.react.bridge.Arguments
2738
import com.facebook.react.bridge.JSApplicationIllegalArgumentException
@@ -31,6 +42,8 @@ import com.facebook.react.bridge.ReadableMap
3142
import com.facebook.react.bridge.ReadableType
3243
import com.facebook.react.bridge.WritableMap
3344
import com.facebook.react.common.ReactConstants
45+
import com.facebook.react.modules.fresco.ReactNetworkImageRequest
46+
import com.facebook.react.views.image.ReactCallerContextFactory
3447
import java.io.ByteArrayInputStream
3548
import java.io.File
3649
import java.io.FileInputStream
@@ -51,7 +64,13 @@ object MimeType {
5164
const val WEBP = "image/webp"
5265
}
5366

54-
class ImageEditorModuleImpl(private val reactContext: ReactApplicationContext) {
67+
class ImageEditorModuleImpl(
68+
private val reactContext: ReactApplicationContext,
69+
private val callerContext: Any?,
70+
private val callerContextFactory: ReactCallerContextFactory?,
71+
private val imagePipeline: ImagePipeline?
72+
) {
73+
5574
private val moduleCoroutineScope = CoroutineScope(Dispatchers.Default)
5675

5776
init {
@@ -65,6 +84,58 @@ class ImageEditorModuleImpl(private val reactContext: ReactApplicationContext) {
6584
cleanTask()
6685
}
6786

87+
private fun getCallerContext(): Any? {
88+
return callerContextFactory?.getOrCreateCallerContext("", "") ?: callerContext
89+
}
90+
91+
private fun getImagePipeline(): ImagePipeline {
92+
return imagePipeline ?: Fresco.getImagePipeline()
93+
}
94+
95+
private fun fetchAndCacheImage(
96+
uri: String,
97+
headers: ReadableMap?,
98+
callback: (InputStream?) -> Unit
99+
) {
100+
val uri = Uri.parse(uri)
101+
102+
val imageRequest: ImageRequest =
103+
if (headers != null) {
104+
val imageRequestBuilder = ImageRequestBuilder.newBuilderWithSource(uri)
105+
ReactNetworkImageRequest.fromBuilderWithHeaders(imageRequestBuilder, headers)
106+
} else ImageRequestBuilder.newBuilderWithSource(uri).build()
107+
108+
val dataSource: DataSource<CloseableReference<PooledByteBuffer>> =
109+
getImagePipeline().fetchEncodedImage(imageRequest, getCallerContext())
110+
val dataSubscriber: DataSubscriber<CloseableReference<PooledByteBuffer>> =
111+
object : BaseDataSubscriber<CloseableReference<PooledByteBuffer>>() {
112+
override fun onNewResultImpl(
113+
dataSource: DataSource<CloseableReference<PooledByteBuffer>>
114+
) {
115+
if (!dataSource.isFinished()) {
116+
return
117+
}
118+
val ref = dataSource.getResult()
119+
val result = ref?.get()
120+
if (result != null) {
121+
val stream: InputStream = PooledByteBufferInputStream(result)
122+
callback(stream)
123+
} else {
124+
dataSource.close()
125+
callback(null)
126+
}
127+
}
128+
129+
override fun onFailureImpl(
130+
dataSource: DataSource<CloseableReference<PooledByteBuffer>>
131+
) {
132+
dataSource.close()
133+
callback(null)
134+
}
135+
}
136+
dataSource.subscribe(dataSubscriber, CallerThreadExecutor.getInstance())
137+
}
138+
68139
/**
69140
* Asynchronous task that cleans up cache dirs (internal and, if available, external) of cropped
70141
* image files. This is run when the module is invalidated (i.e. app is shutting down) and when
@@ -148,7 +219,7 @@ class ImageEditorModuleImpl(private val reactContext: ReactApplicationContext) {
148219
// memory
149220
val hasTargetSize = targetWidth > 0 && targetHeight > 0
150221
val cropped: Bitmap? =
151-
if (hasTargetSize) {
222+
if (hasTargetSize)
152223
cropAndResizeTask(
153224
outOptions,
154225
uri,
@@ -160,9 +231,8 @@ class ImageEditorModuleImpl(private val reactContext: ReactApplicationContext) {
160231
targetHeight,
161232
headers
162233
)
163-
} else {
164-
cropTask(outOptions, uri, x, y, width, height, headers)
165-
}
234+
else cropTask(outOptions, uri, x, y, width, height, headers)
235+
166236
if (cropped == null) {
167237
throw IOException("Cannot decode bitmap: $uri")
168238
}

android/src/newarch/com/reactnativecommunity/imageeditor/ImageEditorModule.kt

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
11
package com.reactnativecommunity.imageeditor
22

3+
import com.facebook.imagepipeline.core.ImagePipeline
34
import com.facebook.react.bridge.Promise
45
import com.facebook.react.bridge.ReactApplicationContext
56
import com.facebook.react.bridge.ReadableMap
67
import com.facebook.react.module.annotations.ReactModule
8+
import com.facebook.react.views.image.ReactCallerContextFactory
79

810
@ReactModule(name = ImageEditorModule.NAME)
9-
class ImageEditorModule(reactContext: ReactApplicationContext) :
10-
NativeRNCImageEditorSpec(reactContext) {
11+
class ImageEditorModule : NativeRNCImageEditorSpec {
1112
private val moduleImpl: ImageEditorModuleImpl
1213

13-
init {
14-
moduleImpl = ImageEditorModuleImpl(reactContext)
14+
constructor(reactContext: ReactApplicationContext) : super(reactContext) {
15+
moduleImpl = ImageEditorModuleImpl(reactContext, this, null, null)
16+
}
17+
18+
constructor(reactContext: ReactApplicationContext, callerContext: Any?) : super(reactContext) {
19+
moduleImpl = ImageEditorModuleImpl(reactContext, callerContext, null, null)
20+
}
21+
22+
constructor(
23+
reactContext: ReactApplicationContext,
24+
imagePipeline: ImagePipeline?,
25+
callerContextFactory: ReactCallerContextFactory?
26+
) : super(reactContext) {
27+
moduleImpl = ImageEditorModuleImpl(reactContext, null, callerContextFactory, imagePipeline)
1528
}
1629

1730
override fun getName(): String {

android/src/oldarch/com/reactnativecommunity/imageeditor/ImageEditorModule.kt

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,32 @@
11
package com.reactnativecommunity.imageeditor
22

3+
import com.facebook.imagepipeline.core.ImagePipeline
34
import com.facebook.react.bridge.Promise
45
import com.facebook.react.bridge.ReactApplicationContext
56
import com.facebook.react.bridge.ReactContextBaseJavaModule
67
import com.facebook.react.bridge.ReactMethod
78
import com.facebook.react.bridge.ReadableMap
89
import com.facebook.react.module.annotations.ReactModule
10+
import com.facebook.react.views.image.ReactCallerContextFactory
911

1012
@ReactModule(name = ImageEditorModule.NAME)
11-
class ImageEditorModule(reactContext: ReactApplicationContext) :
12-
ReactContextBaseJavaModule(reactContext) {
13+
class ImageEditorModule : ReactContextBaseJavaModule {
1314
private val moduleImpl: ImageEditorModuleImpl
1415

15-
init {
16-
moduleImpl = ImageEditorModuleImpl(reactContext)
16+
constructor(reactContext: ReactApplicationContext) : super(reactContext) {
17+
moduleImpl = ImageEditorModuleImpl(reactContext, this, null, null)
18+
}
19+
20+
constructor(reactContext: ReactApplicationContext, callerContext: Any?) : super(reactContext) {
21+
moduleImpl = ImageEditorModuleImpl(reactContext, callerContext, null, null)
22+
}
23+
24+
constructor(
25+
reactContext: ReactApplicationContext,
26+
imagePipeline: ImagePipeline?,
27+
callerContextFactory: ReactCallerContextFactory?
28+
) : super(reactContext) {
29+
moduleImpl = ImageEditorModuleImpl(reactContext, null, callerContextFactory, imagePipeline)
1730
}
1831

1932
override fun getName(): String {

0 commit comments

Comments
 (0)