add "mimeType" parameter in "getFile" API to allow specifying image format when get full image on both platforms

This commit is contained in:
Wenqi Li 2021-04-13 22:02:35 +08:00
parent f40f83204f
commit 270432154d
4 changed files with 98 additions and 12 deletions

View File

@ -15,9 +15,11 @@ import android.provider.MediaStore
import android.content.Context
import android.database.Cursor
import android.database.Cursor.FIELD_TYPE_INTEGER
import android.graphics.ImageDecoder
import android.os.AsyncTask
import android.os.Build
import android.util.Size
import java.io.FileOutputStream
/** PhotoGalleryPlugin */
class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
@ -138,8 +140,9 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
"getFile" -> {
val mediumId = call.argument<String>("mediumId")
val mediumType = call.argument<String>("mediumType")
val mimeType = call.argument<String>("mimeType")
BackgroundAsyncTask({
getFile(mediumId!!, mediumType)
getFile(mediumId!!, mediumType, mimeType)
}, { 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) {
imageType -> {
getImageFile(mediumId)
getImageFile(mediumId, mimeType = mimeType)
}
videoType -> {
getVideoFile(mediumId)
}
else -> {
getImageFile(mediumId) ?: getVideoFile(mediumId)
getImageFile(mediumId, mimeType = mimeType) ?: getVideoFile(mediumId)
}
}
}
private fun getImageFile(mediumId: String): String? {
var path: String? = null
private fun getImageFile(mediumId: String, mimeType: String? = null): String? {
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(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
arrayOf(MediaStore.Images.Media.DATA),
@ -695,12 +705,12 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
imageCursor?.use { cursor ->
if (cursor.moveToNext()) {
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? {
@ -725,6 +735,51 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
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?> {
val idColumn = cursor.getColumnIndex(MediaStore.Images.Media._ID)
val widthColumn = cursor.getColumnIndex(MediaStore.Images.Media.WIDTH)

View File

@ -70,8 +70,10 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
else if(call.method == "getFile") {
let arguments = call.arguments as! Dictionary<String, AnyObject>
let mediumId = arguments["mediumId"] as! String
let mimeType = arguments["mimeType"] as? String
getFile(
mediumId: mediumId,
mimeType: mimeType,
completion: { (filepath: String?, error: Error?) -> Void in
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))
}
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 fetchOptions = PHFetchOptions()
@ -350,6 +352,14 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
completion(nil, NSError(domain: "photo_gallery", code: 404, userInfo: nil))
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 filepath = self.exportPathForAsset(asset: asset, ext: fileExt)
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?] {
let mimeType = self.extractMimeTypeFromAsset(asset: asset)
return [

View File

@ -103,11 +103,14 @@ class PhotoGallery {
static Future<File> getFile({
required String mediumId,
MediumType? mediumType,
String? mimeType,
}) async {
final path = await _channel.invokeMethod('getFile', {
'mediumId': mediumId,
'mediumType': mediumTypeToJson(mediumType),
}) as String;
'mimeType': mimeType,
}) as String?;
if (path == null) throw "Cannot get file $mediumId with type $mimeType";
return File(path);
}

View File

@ -4,9 +4,11 @@ part of photogallery;
class PhotoProvider extends ImageProvider<PhotoProvider> {
PhotoProvider({
required this.mediumId,
this.mimeType,
});
final String mediumId;
final String? mimeType;
@override
ImageStreamCompleter load(key, decode) {
@ -22,7 +24,7 @@ class PhotoProvider extends ImageProvider<PhotoProvider> {
Future<ui.Codec> _loadAsync(PhotoProvider key, DecoderCallback decode) async {
assert(key == this);
final file = await PhotoGallery.getFile(
mediumId: mediumId, mediumType: MediumType.image);
mediumId: mediumId, mediumType: MediumType.image, mimeType: mimeType);
final bytes = await file.readAsBytes();