Skip to content

Commit

Permalink
Use Fresco for downloading images
Browse files Browse the repository at this point in the history
Using Fresco will allow us to take advantage of caching and improve load times a lot. This also unblocks the UI thread by since Fresco performs image requests in a separate thread.
  • Loading branch information
satya164 committed Aug 11, 2017
1 parent 102e55b commit 86c72b9
Showing 1 changed file with 110 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
package io.callstack.react_native_material_palette

import android.support.v7.graphics.Palette
import com.facebook.react.bridge.*
import com.facebook.react.bridge.ReactApplicationContext
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.provider.MediaStore
import java.io.IOException
import android.graphics.BitmapFactory
import android.graphics.Bitmap
import android.support.v7.graphics.Palette
import android.support.v7.graphics.Target
import java.net.URL
import com.facebook.common.executors.CallerThreadExecutor
import com.facebook.common.internal.Closeables
import com.facebook.common.references.CloseableReference
import com.facebook.datasource.BaseDataSubscriber
import com.facebook.datasource.DataSource
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.imagepipeline.common.ImageDecodeOptions
import com.facebook.imagepipeline.memory.PooledByteBuffer
import com.facebook.imagepipeline.memory.PooledByteBufferInputStream
import com.facebook.imagepipeline.request.ImageRequest.RequestLevel
import com.facebook.imagepipeline.request.ImageRequestBuilder
import com.facebook.react.bridge.*
import java.io.IOException

class MaterialPaletteModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {

private val REACT_NAME = "MaterialPalette"
private val URI_ERROR = "URI_ERROR"
private val context = reactContext
private val ERR_INVALID_URI = "ERR_INVALID_URI"
private val ERR_DOWNLOAD = "ERR_DOWNLOAD"

override fun getName(): String {
return REACT_NAME
Expand Down Expand Up @@ -75,54 +84,109 @@ class MaterialPaletteModule(reactContext: ReactApplicationContext) : ReactContex
return getSwatchProperties(targetSwatch)
}

@ReactMethod
fun createMaterialPalette(source: ReadableMap, options: ReadableMap, promise: Promise) {
try {
val uri = source.getString("uri")
val region = options.getMap("region")
val top = region.getInt("top")
val right = region.getInt("right")
val bottom = region.getInt("bottom")
val left = region.getInt("left")
val maxColorCount = options.getInt("maximumColorCount")
val types = options.getArray("type")
val bitmap: Bitmap

if (uri.contains("http")) {
val url = URL(uri)
bitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream())
fun getPalettesFromImage(image: Bitmap, options: ReadableMap, callback: (result: WritableMap) -> Unit) {
val region = options.getMap("region")
val top = region.getInt("top")
val right = region.getInt("right")
val bottom = region.getInt("bottom")
val left = region.getInt("left")
val maxColorCount = options.getInt("maximumColorCount")
val types = options.getArray("type")

var builder: Palette.Builder = Palette.from(image).maximumColorCount(maxColorCount)

if (left != 0 || top != 0 || right != 0 || bottom != 0) {
builder = builder.setRegion(left, top, right, bottom)
}

for (t in Array(types.size(), { i -> targetMap(types.getString(i))})) {
if (t != null) {
builder = builder.addTarget(t)
} else {
bitmap = MediaStore.Images.Media.getBitmap(context.contentResolver, Uri.parse(uri))
throwExceptionWrongColor()
}
}

var builder: Palette.Builder = Palette.from(bitmap).maximumColorCount(maxColorCount)
builder.generate({ p: Palette ->
palette = p
val returnMap = Arguments.createMap()

if (left != 0 || top != 0 || right != 0 || bottom != 0) {
builder = builder.setRegion(left, top, right, bottom)
val targets: Array<String> = Array(types.size(), { i -> types.getString(i)})
for (t in targets) {
returnMap.putMap(t, getSwatch(t))
}

for (t in Array(types.size(), { i -> targetMap(types.getString(i))})) {
if (t != null) {
builder = builder.addTarget(t)
} else {
throwExceptionWrongColor()
}
}
callback(returnMap)
})
}

@ReactMethod
fun createMaterialPalette(source: ReadableMap, options: ReadableMap, promise: Promise) {
val uri: Uri

builder.generate({ p: Palette ->
palette = p
val returnMap = Arguments.createMap()
try {
uri = Uri.parse(source.getString("uri"));
} catch(error: IOException) {
promise.reject(ERR_INVALID_URI, "The URI provided is not valid")
return;
}

if (uri.scheme == "http" || uri.scheme == "https") {
val decodeOptions = ImageDecodeOptions.newBuilder()
.build()
val imageRequest = ImageRequestBuilder
.newBuilderWithSource(uri)
.setImageDecodeOptions(decodeOptions)
.setLowestPermittedRequestLevel(RequestLevel.FULL_FETCH)
.build()

val imagePipeline = Fresco.getImagePipeline();
val dataSource = imagePipeline.fetchEncodedImage(imageRequest, reactApplicationContext);

val dataSubscriber = object: BaseDataSubscriber<CloseableReference<PooledByteBuffer>>() {
override fun onNewResultImpl(dataSource: DataSource<CloseableReference<PooledByteBuffer>>) {
if (!dataSource.isFinished()) {
return;
}

val result = dataSource.getResult()

if (result == null) {
promise.reject(ERR_DOWNLOAD, "Failed to download image");
return;
}

val inputStream = PooledByteBufferInputStream(result.get());

try {
val bitmap = BitmapFactory.decodeStream(inputStream)
getPalettesFromImage(bitmap, options, {
result ->
promise.resolve(result)
})
} catch (e: Exception) {
promise.reject(e);
} finally {
Closeables.closeQuietly(inputStream);
}
}

val targets: Array<String> = Array(types.size(), { i -> types.getString(i)})
for (t in targets) {
returnMap.putMap(t, getSwatch(t))
override fun onFailureImpl(dataSource: DataSource<CloseableReference<PooledByteBuffer>>) {
promise.reject(dataSource.failureCause);
}
}

promise.resolve(returnMap)
})
dataSource.subscribe(dataSubscriber, CallerThreadExecutor.getInstance());
} else {
try {
val bitmap = MediaStore.Images.Media.getBitmap(reactApplicationContext.contentResolver, uri);

} catch(error: IOException) {
promise.reject(URI_ERROR, "The URI provided is not an image or the path is incorrect")
getPalettesFromImage(bitmap, options, {
result -> promise.resolve(result)
});
} catch (e: Exception) {
promise.reject(e);
}
}
}
}

0 comments on commit 86c72b9

Please sign in to comment.