@@ -21,7 +21,18 @@ import android.provider.MediaStore
21
21
import android.text.TextUtils
22
22
import android.util.Base64
23
23
import androidx.exifinterface.media.ExifInterface
24
+ import com.facebook.common.executors.CallerThreadExecutor
24
25
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
25
36
import com.facebook.infer.annotation.Assertions
26
37
import com.facebook.react.bridge.Arguments
27
38
import com.facebook.react.bridge.JSApplicationIllegalArgumentException
@@ -31,6 +42,8 @@ import com.facebook.react.bridge.ReadableMap
31
42
import com.facebook.react.bridge.ReadableType
32
43
import com.facebook.react.bridge.WritableMap
33
44
import com.facebook.react.common.ReactConstants
45
+ import com.facebook.react.modules.fresco.ReactNetworkImageRequest
46
+ import com.facebook.react.views.image.ReactCallerContextFactory
34
47
import java.io.ByteArrayInputStream
35
48
import java.io.File
36
49
import java.io.FileInputStream
@@ -51,7 +64,13 @@ object MimeType {
51
64
const val WEBP = " image/webp"
52
65
}
53
66
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
+
55
74
private val moduleCoroutineScope = CoroutineScope (Dispatchers .Default )
56
75
57
76
init {
@@ -65,6 +84,58 @@ class ImageEditorModuleImpl(private val reactContext: ReactApplicationContext) {
65
84
cleanTask()
66
85
}
67
86
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
+
68
139
/* *
69
140
* Asynchronous task that cleans up cache dirs (internal and, if available, external) of cropped
70
141
* 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) {
148
219
// memory
149
220
val hasTargetSize = targetWidth > 0 && targetHeight > 0
150
221
val cropped: Bitmap ? =
151
- if (hasTargetSize) {
222
+ if (hasTargetSize)
152
223
cropAndResizeTask(
153
224
outOptions,
154
225
uri,
@@ -160,9 +231,8 @@ class ImageEditorModuleImpl(private val reactContext: ReactApplicationContext) {
160
231
targetHeight,
161
232
headers
162
233
)
163
- } else {
164
- cropTask(outOptions, uri, x, y, width, height, headers)
165
- }
234
+ else cropTask(outOptions, uri, x, y, width, height, headers)
235
+
166
236
if (cropped == null ) {
167
237
throw IOException (" Cannot decode bitmap: $uri " )
168
238
}
0 commit comments