add "mimeType" parameter in "getFile" API to allow specifying image format when get full image on both platforms
This commit is contained in:
parent
f40f83204f
commit
270432154d
@ -15,9 +15,11 @@ import android.provider.MediaStore
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.database.Cursor.FIELD_TYPE_INTEGER
|
import android.database.Cursor.FIELD_TYPE_INTEGER
|
||||||
|
import android.graphics.ImageDecoder
|
||||||
import android.os.AsyncTask
|
import android.os.AsyncTask
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.Size
|
import android.util.Size
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
|
||||||
/** PhotoGalleryPlugin */
|
/** PhotoGalleryPlugin */
|
||||||
class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
|
class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
|
||||||
@ -138,8 +140,9 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
|
|||||||
"getFile" -> {
|
"getFile" -> {
|
||||||
val mediumId = call.argument<String>("mediumId")
|
val mediumId = call.argument<String>("mediumId")
|
||||||
val mediumType = call.argument<String>("mediumType")
|
val mediumType = call.argument<String>("mediumType")
|
||||||
|
val mimeType = call.argument<String>("mimeType")
|
||||||
BackgroundAsyncTask({
|
BackgroundAsyncTask({
|
||||||
getFile(mediumId!!, mediumType)
|
getFile(mediumId!!, mediumType, mimeType)
|
||||||
}, { v ->
|
}, { v ->
|
||||||
result.success(v)
|
result.success(v)
|
||||||
})
|
})
|
||||||
@ -666,24 +669,31 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFile(mediumId: String, mediumType: String?): String? {
|
private fun getFile(mediumId: String, mediumType: String?, mimeType: String?): String? {
|
||||||
return when (mediumType) {
|
return when (mediumType) {
|
||||||
imageType -> {
|
imageType -> {
|
||||||
getImageFile(mediumId)
|
getImageFile(mediumId, mimeType = mimeType)
|
||||||
}
|
}
|
||||||
videoType -> {
|
videoType -> {
|
||||||
getVideoFile(mediumId)
|
getVideoFile(mediumId)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
getImageFile(mediumId) ?: getVideoFile(mediumId)
|
getImageFile(mediumId, mimeType = mimeType) ?: getVideoFile(mediumId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getImageFile(mediumId: String): String? {
|
private fun getImageFile(mediumId: String, mimeType: String? = null): String? {
|
||||||
var path: String? = null
|
|
||||||
|
|
||||||
this.context?.run {
|
this.context?.run {
|
||||||
|
mimeType?.let {
|
||||||
|
val type = this.contentResolver.getType(
|
||||||
|
ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mediumId.toLong())
|
||||||
|
)
|
||||||
|
if (it != type) {
|
||||||
|
return cacheImage(mediumId, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val imageCursor = this.contentResolver.query(
|
val imageCursor = this.contentResolver.query(
|
||||||
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||||
arrayOf(MediaStore.Images.Media.DATA),
|
arrayOf(MediaStore.Images.Media.DATA),
|
||||||
@ -695,12 +705,12 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
|
|||||||
imageCursor?.use { cursor ->
|
imageCursor?.use { cursor ->
|
||||||
if (cursor.moveToNext()) {
|
if (cursor.moveToNext()) {
|
||||||
val dataColumn = cursor.getColumnIndex(MediaStore.Images.Media.DATA)
|
val dataColumn = cursor.getColumnIndex(MediaStore.Images.Media.DATA)
|
||||||
path = cursor.getString(dataColumn)
|
return cursor.getString(dataColumn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return path
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getVideoFile(mediumId: String): String? {
|
private fun getVideoFile(mediumId: String): String? {
|
||||||
@ -725,6 +735,51 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
|
|||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun cacheImage(mediumId: String, mimeType: String): String? {
|
||||||
|
val bitmap: Bitmap? = this.context?.run {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
try {
|
||||||
|
ImageDecoder.decodeBitmap(ImageDecoder.createSource(
|
||||||
|
this.contentResolver,
|
||||||
|
ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mediumId.toLong())
|
||||||
|
))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MediaStore.Images.Media.getBitmap(
|
||||||
|
this.contentResolver,
|
||||||
|
ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mediumId.toLong())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmap?.let {
|
||||||
|
val compressFormat: Bitmap.CompressFormat
|
||||||
|
if (mimeType == "image/jpeg") {
|
||||||
|
val path = File(getCachePath(), "$mediumId.jpeg")
|
||||||
|
val out = FileOutputStream(path)
|
||||||
|
compressFormat = Bitmap.CompressFormat.JPEG
|
||||||
|
it.compress(compressFormat, 100, out)
|
||||||
|
return path.absolutePath
|
||||||
|
} else if (mimeType == "image/png") {
|
||||||
|
val path = File(getCachePath(), "$mediumId.png")
|
||||||
|
val out = FileOutputStream(path)
|
||||||
|
compressFormat = Bitmap.CompressFormat.PNG
|
||||||
|
it.compress(compressFormat, 100, out)
|
||||||
|
return path.absolutePath
|
||||||
|
} else if (mimeType == "image/webp") {
|
||||||
|
val path = File(getCachePath(), "$mediumId.webp")
|
||||||
|
val out = FileOutputStream(path)
|
||||||
|
compressFormat = Bitmap.CompressFormat.WEBP
|
||||||
|
it.compress(compressFormat, 100, out)
|
||||||
|
return path.absolutePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
private fun getImageMetadata(cursor: Cursor): Map<String, Any?> {
|
private fun getImageMetadata(cursor: Cursor): Map<String, Any?> {
|
||||||
val idColumn = cursor.getColumnIndex(MediaStore.Images.Media._ID)
|
val idColumn = cursor.getColumnIndex(MediaStore.Images.Media._ID)
|
||||||
val widthColumn = cursor.getColumnIndex(MediaStore.Images.Media.WIDTH)
|
val widthColumn = cursor.getColumnIndex(MediaStore.Images.Media.WIDTH)
|
||||||
|
@ -70,8 +70,10 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
|
|||||||
else if(call.method == "getFile") {
|
else if(call.method == "getFile") {
|
||||||
let arguments = call.arguments as! Dictionary<String, AnyObject>
|
let arguments = call.arguments as! Dictionary<String, AnyObject>
|
||||||
let mediumId = arguments["mediumId"] as! String
|
let mediumId = arguments["mediumId"] as! String
|
||||||
|
let mimeType = arguments["mimeType"] as? String
|
||||||
getFile(
|
getFile(
|
||||||
mediumId: mediumId,
|
mediumId: mediumId,
|
||||||
|
mimeType: mimeType,
|
||||||
completion: { (filepath: String?, error: Error?) -> Void in
|
completion: { (filepath: String?, error: Error?) -> Void in
|
||||||
result(filepath?.replacingOccurrences(of: "file://", with: ""))
|
result(filepath?.replacingOccurrences(of: "file://", with: ""))
|
||||||
})
|
})
|
||||||
@ -319,7 +321,7 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
|
|||||||
completion(nil , NSError(domain: "photo_gallery", code: 404, userInfo: nil))
|
completion(nil , NSError(domain: "photo_gallery", code: 404, userInfo: nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getFile(mediumId: String, completion: @escaping (String?, Error?) -> Void) {
|
private func getFile(mediumId: String, mimeType: String?, completion: @escaping (String?, Error?) -> Void) {
|
||||||
let manager = PHImageManager.default()
|
let manager = PHImageManager.default()
|
||||||
|
|
||||||
let fetchOptions = PHFetchOptions()
|
let fetchOptions = PHFetchOptions()
|
||||||
@ -350,6 +352,14 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
|
|||||||
completion(nil, NSError(domain: "photo_gallery", code: 404, userInfo: nil))
|
completion(nil, NSError(domain: "photo_gallery", code: 404, userInfo: nil))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if mimeType != nil {
|
||||||
|
let type = self.extractMimeTypeFromUTI(uti: assetUTI)
|
||||||
|
if type != mimeType {
|
||||||
|
let path = self.cacheImage(asset: asset, data: imageData, mimeType: mimeType!)
|
||||||
|
completion(path, NSError(domain: "photo_gallery", code: 404, userInfo: nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
let fileExt = self.extractFileExtensionFromUTI(uti: assetUTI)
|
let fileExt = self.extractFileExtensionFromUTI(uti: assetUTI)
|
||||||
let filepath = self.exportPathForAsset(asset: asset, ext: fileExt)
|
let filepath = self.exportPathForAsset(asset: asset, ext: fileExt)
|
||||||
try! imageData.write(to: filepath, options: .atomic)
|
try! imageData.write(to: filepath, options: .atomic)
|
||||||
@ -383,6 +393,22 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func cacheImage(asset: PHAsset, data: Data, mimeType: String) -> String? {
|
||||||
|
if mimeType == "image/jpeg" {
|
||||||
|
let filepath = self.exportPathForAsset(asset: asset, ext: ".jpeg")
|
||||||
|
let uiImage = UIImage(data: data)
|
||||||
|
try! uiImage?.jpegData(compressionQuality: 100)?.write(to: filepath, options: .atomic)
|
||||||
|
return filepath.absoluteString
|
||||||
|
} else if mimeType == "image/png" {
|
||||||
|
let filepath = self.exportPathForAsset(asset: asset, ext: ".png")
|
||||||
|
let uiImage = UIImage(data: data)
|
||||||
|
try! uiImage?.pngData()?.write(to: filepath, options: .atomic)
|
||||||
|
return filepath.absoluteString
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func getMediumFromAsset(asset: PHAsset) -> [String: Any?] {
|
private func getMediumFromAsset(asset: PHAsset) -> [String: Any?] {
|
||||||
let mimeType = self.extractMimeTypeFromAsset(asset: asset)
|
let mimeType = self.extractMimeTypeFromAsset(asset: asset)
|
||||||
return [
|
return [
|
||||||
|
@ -103,11 +103,14 @@ class PhotoGallery {
|
|||||||
static Future<File> getFile({
|
static Future<File> getFile({
|
||||||
required String mediumId,
|
required String mediumId,
|
||||||
MediumType? mediumType,
|
MediumType? mediumType,
|
||||||
|
String? mimeType,
|
||||||
}) async {
|
}) async {
|
||||||
final path = await _channel.invokeMethod('getFile', {
|
final path = await _channel.invokeMethod('getFile', {
|
||||||
'mediumId': mediumId,
|
'mediumId': mediumId,
|
||||||
'mediumType': mediumTypeToJson(mediumType),
|
'mediumType': mediumTypeToJson(mediumType),
|
||||||
}) as String;
|
'mimeType': mimeType,
|
||||||
|
}) as String?;
|
||||||
|
if (path == null) throw "Cannot get file $mediumId with type $mimeType";
|
||||||
return File(path);
|
return File(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,9 +4,11 @@ part of photogallery;
|
|||||||
class PhotoProvider extends ImageProvider<PhotoProvider> {
|
class PhotoProvider extends ImageProvider<PhotoProvider> {
|
||||||
PhotoProvider({
|
PhotoProvider({
|
||||||
required this.mediumId,
|
required this.mediumId,
|
||||||
|
this.mimeType,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String mediumId;
|
final String mediumId;
|
||||||
|
final String? mimeType;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ImageStreamCompleter load(key, decode) {
|
ImageStreamCompleter load(key, decode) {
|
||||||
@ -22,7 +24,7 @@ class PhotoProvider extends ImageProvider<PhotoProvider> {
|
|||||||
Future<ui.Codec> _loadAsync(PhotoProvider key, DecoderCallback decode) async {
|
Future<ui.Codec> _loadAsync(PhotoProvider key, DecoderCallback decode) async {
|
||||||
assert(key == this);
|
assert(key == this);
|
||||||
final file = await PhotoGallery.getFile(
|
final file = await PhotoGallery.getFile(
|
||||||
mediumId: mediumId, mediumType: MediumType.image);
|
mediumId: mediumId, mediumType: MediumType.image, mimeType: mimeType);
|
||||||
|
|
||||||
final bytes = await file.readAsBytes();
|
final bytes = await file.readAsBytes();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user