Commit 50d38372 authored by 林生雨's avatar 林生雨

commit

parent fc876556
package com.example.myimagepicker.repository
import android.content.Context
import android.graphics.BitmapFactory
import android.util.Log
import com.example.gengmei_flutter_plugin.utils.MyUtil.Companion.getFileFullName
import com.example.gengmei_flutter_plugin.utils.MyUtil.Companion.getFileName
import com.example.gengmei_flutter_plugin.utils.MyUtil.Companion.getImageCacheDir
import com.example.myimagepicker.bean.MediaFile
import com.example.myimagepicker.bean.MediaFolder
import com.example.myimagepicker.luban.Luban
import com.example.myimagepicker.repository.local.ImageScanner
import io.reactivex.Observable
import io.reactivex.ObservableOnSubscribe
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import java.io.File
import java.util.*
import java.util.concurrent.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
/**
* Created by lsy
* on 2019/3/27
*/
class ImageRespository {
private val globalThreadPool = ThreadPoolExecutor(0, 30
, 30, TimeUnit.SECONDS, LinkedBlockingDeque());
val recordImageListMap = ArrayList<HashMap<String, Any>>()
var finishOneTask = false
//: HashMap<String, ArrayList<HashMap<String, Any>>>
fun scanPhoneImage(context: Context): Observable<HashMap<String, ArrayList<HashMap<String, Any>>>> {
if (!recordImageListMap.isEmpty() && finishOneTask) {
return Observable.just(toMap(context, recordImageListMap))
.subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread())
}
return Observable.create(ObservableOnSubscribe<HashMap<String, ArrayList<HashMap<String, Any>>>> {
it.onNext(getFinalMap(context, ImageScanner(context).queryMedia()))
}).subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread())
}
fun savePreviewImg(context: Context, listener: savePreviewListener) {
val needSize = recordImageListMap.size;
var currentSize = 0;
var letSize = 30
var noPathSize = 0;
recordImageListMap.forEach {
val any = it["path"]
val realPath = it["realPath"] as String
if (any == null) {
globalThreadPool.execute {
val get = Luban.with(context).setTargetDir(getImageCacheDir(context, Luban.DEFAULT_DISK_CACHE_DIR)!!.absolutePath)
.setName(getFileName(realPath)!!)
.get(realPath);
it["path"] = get.absolutePath;
synchronized(this) {
currentSize++;
noPathSize++;
Log.e("lsy", "${noPathSize} ${currentSize} ${needSize}")
if (currentSize == needSize) {
//FINISH
listener.onSuccess(toMap(context, recordImageListMap))
} else {
if (noPathSize > letSize) {
letSize += 30
listener.onSuccess(toMap(context, recordImageListMap))
}
}
}
}
} else {
synchronized(this) {
currentSize++;
Log.e("lsy", "HAVE PATH ${noPathSize} ${currentSize} ${needSize}")
if (currentSize == needSize) {
//FINISH
listener.onSuccess(toMap(context, recordImageListMap))
}
// else if (currentSize > letSize) {
// letSize += 100
// listener.onSuccess(toMap(context, recordImageListMap))
// }
}
}
}
}
interface savePreviewListener {
fun onSuccess(data: HashMap<String, ArrayList<HashMap<String, Any>>>)
}
// val currentTimeMillis = System.currentTimeMillis();
// Thread {
// val queryMedia = ImageScanner(context).queryMedia()
// val needSize = queryMedia.size
// val newList = ArrayList<MediaFile>();
// val dir = getImageCacheDir(context, Luban.DEFAULT_DISK_CACHE_DIR)!!.absolutePath;
// queryMedia.forEach {
// val path = it.realPath!!
// val tempFilePngExists = File(dir + "/" + getFileName(path)!! + ".png").exists()
// val tempFileJpgExists = File(dir + "/" + getFileName(path)!! + ".jpg").exists();
// val tempFileJpegExists = File(dir + "/" + getFileName(path)!! + ".jpeg").exists()
//
// if (it.size > 1024 * 1024 && !tempFilePngExists
// && !tempFileJpgExists && !tempFileJpegExists) {
// globalThreadPool.execute {
// val get = Luban.with(context).setTargetDir(getImageCacheDir(context, Luban.DEFAULT_DISK_CACHE_DIR)!!.absolutePath)
// .setName(getFileName(path)!!)
// .get(path);
// // Log.e("lsy"," ${getFileFullName(path)!!}");
// it.path = get.absolutePath
// Log.e("lsy", " ${get.absolutePath} ")
// synchronized(this) {
// newList.add(it);
// Log.e("lsy", " ${newList.size} ${needSize}")
// if (newList.size == needSize) {
// //OKK
// Log.e("lsy", " TIME ${System.currentTimeMillis() - currentTimeMillis}")
// }
// }
// }
// } else {
// synchronized(this) {
// newList.add(it);
// Log.e("lsy", " ${newList.size} ${needSize}")
// if (newList.size == needSize) {
// //OKK
// Log.e("lsy", " TIME ${System.currentTimeMillis() - currentTimeMillis}")
// }
// }
// }
// }
// }.start()
fun getFinalMap(context: Context, imageList: ArrayList<MediaFile>): HashMap<String, ArrayList<HashMap<String, Any>>> {
val imageListMap = ArrayList<HashMap<String, Any>>();
imageList.forEach {
val itemMap = HashMap<String, Any>()
it.folderName?.run {
itemMap.put("folderName", this)
}
it.path?.run {
itemMap.put("path", this)
}
it.size?.run {
itemMap.put("size", this)
}
it.realPath?.run {
itemMap.put("realPath", this)
}
imageListMap.add(itemMap)
}
synchronized(this) {
recordImageListMap.clear()
recordImageListMap.addAll(imageListMap)
finishOneTask = true
}
// imageList.clear();
return toMap(context, imageListMap);
}
private fun toMap(context: Context, imageListMap: ArrayList<HashMap<String, Any>>): HashMap<String, ArrayList<HashMap<String, Any>>> {
val finalList = HashMap<String, ArrayList<HashMap<String, Any>>>()
imageListMap.forEach {
it["folderName"]?.run {
if (finalList[this] == null) {
finalList[this as String] = ArrayList<HashMap<String, Any>>()
if (it["path"] == null) {
val realPath = it["realPath"] as String
val get = Luban.with(context).setTargetDir(getImageCacheDir(context, Luban.DEFAULT_DISK_CACHE_DIR)!!.absolutePath)
.setName(getFileName(realPath)!!)
.get(realPath);
it["path"] = get.absolutePath
Log.e("lsy", "封面照片 ${get.absolutePath}");
}
finalList[this]!!.add(it);
} else {
finalList[this as String]!!.add(it);
}
}
}
finalList["IsGengmeiAlbumAllImages"] = imageListMap;
return finalList;
}
companion object {
private var instance: ImageRespository? = null
const val TAG: String = "Image_Picker"
fun getInstance(): ImageRespository {
if (instance == null) {
synchronized(ImageRespository::class.java) {
if (instance == null) {
instance = ImageRespository();
}
}
}
return instance!!
}
}
}
\ No newline at end of file
package com.example.myimagepicker.bean
/**
* Created by lsy
* on 2019/3/27
*/
data class MediaFile(
var path: String? = null,
var mime: String? = null,
var folderId: Int? = null,
var folderName: String? = null,
var duration: Long = 0,
var dateToken: Long = 0,
var size: Long = 0,
var isBigIm: Boolean = false,
var bigScare: Float = 0f,
var realPath: String? = null
)
package com.example.myimagepicker.bean
import java.util.ArrayList
/**
* Created by lsy
* on 2019/3/27
*/
class MediaFolder(folderI: Int, folderName: String, folderCover: String, mediaFileList: ArrayList<MediaFile>) {
var folderId: Int = 0
var folderName: String? = null
var folderCover: String? = null
var isCheck: Boolean = false
var mediaFileList: ArrayList<MediaFile>? = null
init {
this.folderId = folderI
this.folderName = folderName;
this.folderCover = folderCover;
this.isCheck = isCheck;
this.mediaFileList = mediaFileList;
}
}
\ No newline at end of file
package com.example.myimagepicker.config
import android.text.TextUtils
import com.example.gengmei_flutter_plugin.utils.ImageLoader
import java.util.ArrayList
/**
* Created by lsy
* on 2019/3/27
*/
class ConfigManager private constructor() {
var title: String? = null//标题
var selectColor: Int? = 0
var isShowCamera: Boolean = false//是否显示拍照Item,默认不显示
var isShowImage = true//是否显示图片,默认显示
var isShowVideo = true//是否显示视频,默认显示
var selectionMode = SELECT_MODE_SINGLE//选择模式,默认单选
var maxCount = 1
set(maxCount) {
if (maxCount > 1) {
selectionMode = SELECT_MODE_MULTI
}
field = maxCount
}//最大选择数量,默认为1
var imageLoader: ImageLoader? = null
@Throws(Exception::class)
get() {
if (field == null) {
throw Exception("imageLoader is null")
}
return field
}
companion object {
val SELECT_MODE_SINGLE = 0
val SELECT_MODE_MULTI = 1
@Volatile
private var mConfigManager: ConfigManager? = null
val instance: ConfigManager
get() {
if (mConfigManager == null) {
synchronized(ConfigManager::class.java) {
if (mConfigManager == null) {
mConfigManager = ConfigManager()
}
}
}
return mConfigManager!!
}
}
}
\ No newline at end of file
package com.example.myimagepicker.repository.local
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.provider.MediaStore
import android.util.Log
import java.io.File
import java.util.ArrayList
/**
* Created by lsy
* on 2019/3/27
*/
abstract class AbsMediaScanner<T>(private val mContext: Context) {
private val filter: Int = 5000
/**
* 查询URI
*
* @return
*/
protected abstract val scanUri: Uri
/**
* 查询列名
*
* @return
*/
protected abstract val projection: Array<String>
/**
* 查询条件
*
* @return
*/
protected abstract val selection: String
/**
* 查询条件值
*
* @return
*/
protected abstract val selectionArgs: Array<String>?
/**
* 查询排序
*
* @return
*/
protected abstract val order: String
/**
* 对外暴露游标,让开发者灵活构建对象
*
* @param cursor
* @return
*/
protected abstract fun parse(cursor: Cursor): T
/**
* 根据查询条件进行媒体库查询,隐藏查询细节,让开发者更专注业务
*
* @return
*/
fun queryMedia(): ArrayList<T> {
val list = ArrayList<T>()
val contentResolver = mContext.contentResolver
val cursor = contentResolver.query(scanUri, projection, selection, selectionArgs, order)
if (cursor != null && cursor.moveToFirst()) {
if (cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.SIZE)) >= filter) {
val path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA))
if(File(path).exists()){
val t = parse(cursor)
list.add(t)
}
}
while (cursor.moveToNext()) {
if (cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.SIZE)) >= filter) {
val path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA))
if(File(path).exists()){
val t = parse(cursor)
list.add(t)
}
}
}
cursor.close()
}
return list
}
}
\ No newline at end of file
package com.example.myimagepicker.repository.local
import android.content.Context
import android.database.Cursor
import android.graphics.BitmapFactory
import android.net.Uri
import android.provider.MediaStore
import android.util.Log
import com.example.gengmei_flutter_plugin.utils.MyUtil.Companion.getFileName
import com.example.gengmei_flutter_plugin.utils.MyUtil.Companion.getImageCacheDir
import com.example.myimagepicker.bean.MediaFile
import com.example.myimagepicker.luban.Luban
import java.io.File
/**
* Created by lsy
* on 2019/3/27
*/
class ImageScanner(var context: Context) : AbsMediaScanner<MediaFile>(context) {
override val scanUri: Uri
get() = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
override val projection: Array<String>
get() =
arrayOf(MediaStore.Images.Media.DATA, MediaStore.Images.Media.MIME_TYPE, MediaStore.Images.Media.BUCKET_ID, MediaStore.Images.Media.BUCKET_DISPLAY_NAME, MediaStore.Images.Media.DATE_TAKEN, MediaStore.Images.Media.SIZE)
override val selection: String
get() =
MediaStore.Images.Media.MIME_TYPE + "=? or " + MediaStore.Images.Media.MIME_TYPE + "=?" + " or " + MediaStore.Images.Media.MIME_TYPE + "=?"
override val selectionArgs: Array<String>
get() = arrayOf("image/jpeg", "image/png", "image/jpg"
// , "image/gif"
)
override val order: String
get() = MediaStore.Images.Media.DATE_TAKEN +
" DESC"
/**
* 构建媒体对象
*
* @param cursor
* @return
*/
override fun parse(cursor: Cursor): MediaFile {
val path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA))
val mime = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.MIME_TYPE))
val folderId = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_ID))
val folderName = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME))
val dateToken = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN))
val size = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.SIZE))
val mediaFile = MediaFile()
mediaFile.mime = mime
mediaFile.folderId = folderId
mediaFile.folderName = folderName
mediaFile.dateToken = dateToken
mediaFile.size = size
mediaFile.realPath = path
val dir = getImageCacheDir(context, Luban.DEFAULT_DISK_CACHE_DIR)!!.absolutePath;
val tempFilePngString = dir + "/" + getFileName(path)!! + ".png";
val tempFilePngExists = File(tempFilePngString).exists()
if (tempFilePngExists) {
mediaFile.path = tempFilePngString;
}
val tempFileJpgString = dir + "/" + getFileName(path)!! + ".jpg";
val tempFileJpgExists = File(tempFileJpgString).exists()
if (tempFileJpgExists) {
mediaFile.path = tempFileJpgString;
}
val tempFileJpegString = dir + "/" + getFileName(path)!! + ".jpeg"
val tempFileJpegExists = File(tempFileJpegString).exists()
if (tempFileJpegExists) {
mediaFile.path = tempFileJpegString;
}
if (size < 1024 * 512) {
mediaFile.path = path
}
//
// if (it.size > 1024 * 1024 && !tempFilePngExists
// && !tempFileJpgExists && !tempFileJpegExists) {
// globalThreadPool.execute {
// val get = Luban.with(context).setTargetDir(getImageCacheDir(context, Luban.DEFAULT_DISK_CACHE_DIR)!!.absolutePath)
// .setName(getFileName(path)!!)
// .get(path);
// val options = BitmapFactory.Options();
// options.inJustDecodeBounds = true;
// BitmapFactory.decodeFile(path, options);
// if (options.outHeight >= MAX_SIZE || options.outHeight / options.outWidth > MAX_SCALE) {
// mediaFile.isBigIm = true
//// mediaFile.bigScare = Utils.getImageScale(context, path)
// }
return mediaFile
}
companion object {
private const val MAX_SIZE = 4096 * 2
private const val MAX_SCALE = 8
}
}
package com.example.myimagepicker.repository.local
import android.content.Context
import com.example.myimagepicker.bean.MediaFile
import com.example.myimagepicker.bean.MediaFolder
import java.util.*
/**
* Created by lsy
* on 2019/3/27
*/
object MediaHandler {
val ALL_MEDIA_FOLDER = -1//全部媒体
val ALL_VIDEO_FOLDER = -2//全部视频
/**
* 对查询到的图片进行聚类(相册分类)
*
* @param context
* @param imageFileList
* @return
*/
fun getImageFolder(context: Context, imageFileList: ArrayList<MediaFile>): List<MediaFolder> {
return getMediaFolder(context, imageFileList, null)
}
/**
* 对查询到的视频进行聚类(相册分类)
*
* @param context
* @param imageFileList
* @return
*/
fun getVideoFolder(context: Context, imageFileList: ArrayList<MediaFile>): List<MediaFolder> {
return getMediaFolder(context, null, imageFileList)
}
/**
* 对查询到的图片和视频进行聚类(相册分类)
*
* @param context
* @param imageFileList
* @param videoFileList
* @return
*/
fun getMediaFolder(context: Context, imageFileList: ArrayList<MediaFile>?, videoFileList: ArrayList<MediaFile>?): List<MediaFolder> {
//根据媒体所在文件夹Id进行聚类(相册)
val mediaFolderMap = HashMap<Int, MediaFolder>()
//全部图片、视频文件
val mediaFileList = ArrayList<MediaFile>()
if (imageFileList != null) {
mediaFileList.addAll(imageFileList)
}
if (videoFileList != null) {
mediaFileList.addAll(videoFileList)
}
//对媒体数据进行排序
// mediaFileList.sortBy { it.dateToken }
//全部图片或视频
if (!mediaFileList.isEmpty()) {
val allMediaFolder = MediaFolder(ALL_MEDIA_FOLDER, "图片和视频", mediaFileList[0].path!!, mediaFileList)
mediaFolderMap[ALL_MEDIA_FOLDER] = allMediaFolder
}
//全部视频
if (videoFileList != null && !videoFileList.isEmpty()) {
val allVideoFolder = MediaFolder(ALL_VIDEO_FOLDER, "所有视频", videoFileList[0].path!!, videoFileList)
mediaFolderMap[ALL_VIDEO_FOLDER] = allVideoFolder
}
//对图片进行文件夹分类
if (imageFileList != null && !imageFileList.isEmpty()) {
val size = imageFileList.size
//添加其他的图片文件夹
for (i in 0 until size) {
val mediaFile = imageFileList[i]
val imageFolderId = mediaFile.folderId
var mediaFolder: MediaFolder? = mediaFolderMap[imageFolderId]
if (mediaFolder == null) {
mediaFolder = MediaFolder(imageFolderId!!, mediaFile.folderName!!, mediaFile.path!!, ArrayList<MediaFile>())
}
val imageList = mediaFolder.mediaFileList
imageList!!.add(mediaFile)
mediaFolder.mediaFileList = imageList
mediaFolderMap[imageFolderId!!] = mediaFolder
}
}
//整理聚类数据
val mediaFolderList = ArrayList<MediaFolder>()
for (folderId in mediaFolderMap.keys) {
if (folderId == ALL_MEDIA_FOLDER || folderId == ALL_VIDEO_FOLDER) {
mediaFolderList.add(0,mediaFolderMap[folderId]!!)
} else {
mediaFolderList.add(mediaFolderMap[folderId]!!)
}
}
return mediaFolderList
}
}
\ No newline at end of file
package com.example.myimagepicker.repository.local
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.provider.MediaStore
import com.example.myimagepicker.bean.MediaFile
/**
* Created by lsy
* on 2019/3/27
*/
class VideoScanner(private val mContext: Context) : AbsMediaScanner<MediaFile>(mContext) {
override val scanUri: Uri
get() = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
override val projection: Array<String>
get() =
arrayOf(MediaStore.Video.Media.DATA, MediaStore.Video.Media.MIME_TYPE, MediaStore.Video.Media.BUCKET_ID, MediaStore.Video.Media.BUCKET_DISPLAY_NAME, MediaStore.Video.Media.DURATION, MediaStore.Video.Media.DATE_TAKEN)
override val order: String
get() = MediaStore.Video.Media.DATE_TAKEN + " desc"
override val selectionArgs: Array<String>?
get() = null
override val selection: String
get() = ""
/**
* 构建媒体对象
*
* @param cursor
* @return
*/
protected override fun parse(cursor: Cursor): MediaFile {
val path = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA))
val mime = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.MIME_TYPE))
val folderId = cursor.getInt(cursor.getColumnIndex(MediaStore.Video.Media.BUCKET_ID))
val folderName = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.BUCKET_DISPLAY_NAME))
val duration = cursor.getLong(cursor.getColumnIndex(MediaStore.Video.Media.DURATION))
val dateToken = cursor.getLong(cursor.getColumnIndex(MediaStore.Video.Media.DATE_TAKEN))
val mediaFile = MediaFile()
mediaFile.path = path
mediaFile.mime = mime
mediaFile.folderId = folderId
mediaFile.folderName = folderName
mediaFile.duration = duration
mediaFile.dateToken = dateToken
return mediaFile
}
companion object {
val ALL_IMAGES_FOLDER = -1//全部图片
}
}
\ No newline at end of file
package com.example.gengmei_flutter_plugin.ImagePlugin.repository.luban;
import android.graphics.BitmapFactory;
import android.util.Log;
import com.example.myimagepicker.luban.InputStreamProvider;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
public enum Checker {
SINGLE;
private static final String TAG = "Luban";
private static final String JPG = ".jpg";
private final byte[] JPEG_SIGNATURE = new byte[]{(byte) 0xFF, (byte) 0xD8, (byte) 0xFF};
/**
* Determine if it is JPG.
*
* @param is image file input stream
*/
public boolean isJPG(InputStream is) {
return isJPG(toByteArray(is));
}
/**
* Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
*/
public int getOrientation(InputStream is) {
return getOrientation(toByteArray(is));
}
private boolean isJPG(byte[] data) {
if (data == null || data.length < 3) {
return false;
}
byte[] signatureB = new byte[]{data[0], data[1], data[2]};
return Arrays.equals(JPEG_SIGNATURE, signatureB);
}
private int getOrientation(byte[] jpeg) {
if (jpeg == null) {
return 0;
}
int offset = 0;
int length = 0;
// ISO/IEC 10918-1:1993(E)
while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) {
int marker = jpeg[offset] & 0xFF;
// Check if the marker is a padding.
if (marker == 0xFF) {
continue;
}
offset++;
// Check if the marker is SOI or TEM.
if (marker == 0xD8 || marker == 0x01) {
continue;
}
// Check if the marker is EOI or SOS.
if (marker == 0xD9 || marker == 0xDA) {
break;
}
// Get the length and check if it is reasonable.
length = pack(jpeg, offset, 2, false);
if (length < 2 || offset + length > jpeg.length) {
Log.e(TAG, "Invalid length");
return 0;
}
// Break if the marker is EXIF in APP1.
if (marker == 0xE1 && length >= 8
&& pack(jpeg, offset + 2, 4, false) == 0x45786966
&& pack(jpeg, offset + 6, 2, false) == 0) {
offset += 8;
length -= 8;
break;
}
// Skip other markers.
offset += length;
length = 0;
}
// JEITA CP-3451 Exif Version 2.2
if (length > 8) {
// Identify the byte order.
int tag = pack(jpeg, offset, 4, false);
if (tag != 0x49492A00 && tag != 0x4D4D002A) {
Log.e(TAG, "Invalid byte order");
return 0;
}
boolean littleEndian = (tag == 0x49492A00);
// Get the offset and check if it is reasonable.
int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
if (count < 10 || count > length) {
Log.e(TAG, "Invalid offset");
return 0;
}
offset += count;
length -= count;
// Get the count and go through all the elements.
count = pack(jpeg, offset - 2, 2, littleEndian);
while (count-- > 0 && length >= 12) {
// Get the tag and check if it is orientation.
tag = pack(jpeg, offset, 2, littleEndian);
if (tag == 0x0112) {
int orientation = pack(jpeg, offset + 8, 2, littleEndian);
switch (orientation) {
case 1:
return 0;
case 3:
return 180;
case 6:
return 90;
case 8:
return 270;
}
Log.e(TAG, "Unsupported orientation");
return 0;
}
offset += 12;
length -= 12;
}
}
Log.e(TAG, "Orientation not found");
return 0;
}
public String extSuffix(InputStreamProvider input) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(input.open(), null, options);
return options.outMimeType.replace("image/", ".");
} catch (Exception e) {
return JPG;
}
}
public boolean needCompress(int leastCompressSize, String path) {
if (leastCompressSize > 0) {
File source = new File(path);
return source.exists() && source.length() > (leastCompressSize << 10);
}
return true;
}
private int pack(byte[] bytes, int offset, int length, boolean littleEndian) {
int step = 1;
if (littleEndian) {
offset += length - 1;
step = -1;
}
int value = 0;
while (length-- > 0) {
value = (value << 8) | (bytes[offset] & 0xFF);
offset += step;
}
return value;
}
private byte[] toByteArray(InputStream is) {
if (is == null) {
return new byte[0];
}
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int read;
byte[] data = new byte[4096];
try {
while ((read = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, read);
}
} catch (Exception ignored) {
return new byte[0];
} finally {
try {
buffer.close();
} catch (IOException ignored) {
}
}
return buffer.toByteArray();
}
}
package com.example.myimagepicker.luban
/**
* Created by lsy
* on 2019/3/29
*/
interface CompressionPredicate {
/**
* Determine the given input path should be compressed and return a boolean.
* @param path input path
* @return the boolean result
*/
fun apply(path: String): Boolean
}
\ No newline at end of file
package com.example.myimagepicker.luban
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.util.Log
import com.example.gengmei_flutter_plugin.ImagePlugin.repository.luban.Checker
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
/**
* Created by lsy
* on 2019/3/29
*/
internal class Engine @Throws(IOException::class)
constructor(private val srcImg: InputStreamProvider, private val tagImgPath: String, private val focusAlpha: Boolean, val quality: Int) {
private var srcWidth: Int = 0
private var srcHeight: Int = 0
init {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
options.inSampleSize = 1
BitmapFactory.decodeStream(srcImg.open(), null, options)
this.srcWidth = options.outWidth
this.srcHeight = options.outHeight
}
private fun computeSize(): Int {
srcWidth = if (srcWidth % 2 == 1) srcWidth + 1 else srcWidth
srcHeight = if (srcHeight % 2 == 1) srcHeight + 1 else srcHeight
val longSide = Math.max(srcWidth, srcHeight)
val shortSide = Math.min(srcWidth, srcHeight)
val scale = shortSide.toFloat() / longSide
return if (scale <= 1 && scale > 0.5625) {
if (longSide < 1664) {
1
} else if (longSide < 4990) {
2
} else if (longSide > 4990 && longSide < 10240) {
4
} else {
if (longSide / 1280 == 0) 1 else longSide / 1280
}
} else if (scale <= 0.5625 && scale > 0.5) {
if (longSide / 1280 == 0) 1 else longSide / 1280
} else {
Math.ceil(longSide / (1280.0 / scale)).toInt()
}
}
private fun rotatingImage(bitmap: Bitmap?, angle: Int): Bitmap {
val matrix = Matrix()
matrix.postRotate(angle.toFloat())
return Bitmap.createBitmap(bitmap!!, 0, 0, bitmap.width, bitmap.height, matrix, true)
}
@Throws(IOException::class)
fun compress(): File {
val options = BitmapFactory.Options()
if (quality == 100) {
options.inSampleSize = computeSize()
} else {
options.inSampleSize = (srcWidth / 240).toInt();
}
// Log.e("lsy"," SAMPLE SIZE ${options.inSampleSize} ${srcWidth}")
var tagBitmap = BitmapFactory.decodeStream(srcImg.open(), null, options)
val stream = ByteArrayOutputStream()
if (Checker.SINGLE.isJPG(srcImg.open())) {
tagBitmap = rotatingImage(tagBitmap, Checker.SINGLE.getOrientation(srcImg.open()))
}
// val tagBitmap1 = imageScale(tagBitmap, 480);
tagBitmap!!.compress(if (focusAlpha) Bitmap.CompressFormat.PNG else Bitmap.CompressFormat.JPEG, if (quality != 0) quality else 70, stream)
// val width = tagBitmap.width
// val height = tagBitmap.height
tagBitmap.recycle()
// val split = tagImgPath.split(".")
// var before: String
// var after: String
// after = split[split.size - 1]
// before = tagImgPath.replace("." + after, "")
val file = File(tagImgPath)
val fos = FileOutputStream(file)
fos.write(stream.toByteArray())
fos.flush()
fos.close()
stream.close()
return file
}
private val matrix by lazy { Matrix() }
private fun imageScale(bitmap: Bitmap, targetSize: Int): Bitmap {
val scareSize = targetSize / bitmap.width.toFloat()
// Log.e("lsy"," ${targetSize} ${srcWidth} ${srcWidth}")
val width = bitmap.width * scareSize
val height = bitmap.height * scareSize;
matrix.reset();
matrix.postScale(width.toFloat(), height.toFloat());
val dstbmp = Bitmap.createBitmap(bitmap, 0, 0, width.toInt(), height.toInt(), matrix, true);
return dstbmp
}
}
\ No newline at end of file
package com.example.myimagepicker.luban
import java.io.IOException
import java.io.InputStream
/**
* Created by lsy
* on 2019/3/29
*/
abstract class InputStreamAdapter : InputStreamProvider {
private var inputStream: InputStream? = null
@Throws(IOException::class)
override fun open(): InputStream? {
close()
inputStream = openInternal()
return inputStream
}
@Throws(IOException::class)
abstract fun openInternal(): InputStream?
override fun close() {
if (inputStream != null) {
try {
inputStream!!.close()
} catch (ignore: IOException) {
} finally {
inputStream = null
}
}
}
}
\ No newline at end of file
package com.example.myimagepicker.luban
import java.io.IOException
import java.io.InputStream
/**
* Created by lsy
* on 2019/3/29
*/
interface InputStreamProvider {
val path: String?
@Throws(IOException::class)
fun open(): InputStream?
fun close()
}
package com.example.myimagepicker.luban
import java.io.File
/**
* Created by lsy
* on 2019/3/29
*/
interface OnCompressListener {
/**
* Fired when the compression is started, override to handle in your own code
*/
fun onStart()
/**
* Fired when a compression returns successfully, override to handle in your own code
*/
fun onSuccess(file: File)
/**
* Fired when a compression fails to complete, override to handle in your own code
*/
fun onError(e: Throwable)
}
package com.example.myimagepicker.luban
/**
* Created by lsy
* on 2019/3/29
*/
interface OnRenameListener {
/**
* 压缩前调用该方法用于修改压缩后文件名
*
*
* Call before compression begins.
*
* @param filePath 传入文件路径/ file path
* @return 返回重命名后的字符串/ file name
*/
fun rename(filePath: String): String
}
\ No newline at end of file
package com.example.gengmei_flutter_plugin.ex
/**
* @author lsy
* @date 2019-09-26
*/
class RxExpecition(message: String?) : Exception(message) {
}
\ No newline at end of file
package com.example.gengmei_flutter_plugin.result
import android.util.Log
import android.util.SparseArray
import io.flutter.plugin.common.MethodChannel
/**
* @author lsy
* @date 2019-09-25
*/
class ResultManager private constructor() {
val map = HashMap<Long, MethodChannel.Result>();
init {
}
fun addResult(key: Long, result: MethodChannel.Result) {
map.put(key, result)
}
fun resultSuccess(key: Long, value: Any) {
Log.e("lsy","KEYYY $key ")
map.get(key)?.run {
this.success(value);
}
map.remove(key)
Log.e("lsy"," ${map.size}")
}
fun resultError(key: Long, message: String, ob: Any) {
map.get(key)?.run {
this.error(message, message, ob)
}
map.remove(key)
Log.e("lsy"," ${map.size}")
}
companion object {
private val instance = ResultManager();
@JvmStatic
fun getInstance(): ResultManager {
return instance;
}
}
}
\ No newline at end of file
package com.example.gengmei_flutter_plugin.sharedPrefernces
import android.app.Application
import android.content.Context
import android.content.SharedPreferences
import com.example.gengmei_flutter_plugin.ex.RxExpecition
import io.reactivex.Observable
import io.reactivex.ObservableOnSubscribe
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
/**
* @author lsy
* @date 2019-09-25
*/
class SharedManager private constructor(app: Context) {
private val preferences: SharedPreferences
init {
preferences = app.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
}
companion object {
const val SHARED_PREFERENCES_NAME = "FlutterSharedPreferences"
@Volatile
private var instance: SharedManager?=null;
@JvmStatic
fun getInstance(app: Context): SharedManager {
if (instance == null) {
synchronized(this) {
if (instance == null) {
instance = SharedManager(app);
}
}
}
return instance!!
}
}
fun saveInt(key: String, value: Int): Observable<Boolean> {
return Observable.create(ObservableOnSubscribe<Boolean> {
it.onNext(preferences.edit().putInt(key, value).commit())
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
fun saveString(key: String, value: String): Observable<Boolean> {
return Observable.create(ObservableOnSubscribe<Boolean> {
it.onNext(preferences.edit().putString(key, value).commit())
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
fun saveBoolean(key: String, value: Boolean): Observable<Boolean> {
return Observable.create(ObservableOnSubscribe<Boolean> {
it.onNext(preferences.edit().putBoolean(key, value).commit())
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
fun saveFloat(key: String, value: Float): Observable<Boolean> {
return Observable.create(ObservableOnSubscribe<Boolean> {
it.onNext(preferences.edit().putFloat(key, value).commit())
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
fun saveStringList(key: String, value: Set<String>): Observable<Boolean> {
return Observable.create(ObservableOnSubscribe<Boolean> {
it.onNext(preferences.edit().putStringSet(key, value).commit())
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
fun getInt(key: String, value: Int): Observable<Int> {
return Observable.create(ObservableOnSubscribe<Int> {
it.onNext(preferences.getInt(key, value))
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
fun getString(key: String, value: String?): Observable<String?> {
return Observable.create(ObservableOnSubscribe<String> {
val string = preferences.getString(key, value)
if(string==null){
it.onNext("")
}else{
it.onNext(string)
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
fun getFloat(key: String, value: Float): Observable<Float> {
return Observable.create(ObservableOnSubscribe<Float> {
it.onNext(preferences.getFloat(key, value))
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
fun getBoolean(key: String, value: Boolean): Observable<Boolean> {
return Observable.create(ObservableOnSubscribe<Boolean> {
it.onNext(preferences.getBoolean(key, value))
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
fun getStringList(key: String, value: Set<String>?): Observable<ArrayList<String>> {
return Observable.create(ObservableOnSubscribe<ArrayList<String>> {
val stringSet = preferences.getStringSet(key, value)
if(stringSet==null){
throw RxExpecition("NULL!!")
}
val temp=ArrayList<String>()
temp.addAll(stringSet)
it.onNext(temp)
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
}
\ No newline at end of file
package com.example.gengmei_flutter_plugin.utils;
import android.util.Log;
import com.example.gengmei_flutter_plugin.BuildConfig;
public class DebugUtil {
private static final String TAG = "GENGMEI_FLUTTER_PLUGIN";
private static boolean DBG = BuildConfig.DEBUG;
public static void printStackTrace(Throwable throwable) {
if (DBG) {
throwable.printStackTrace();
}
Log.e(TAG,throwable.getMessage());
}
}
package com.example.gengmei_flutter_plugin.utils;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.DisplayMetrics;
import android.util.Size;
import android.util.TypedValue;
import android.view.WindowManager;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class DimensionUtils {
public static final int KB = 1024;
public static final int MB = 1024 * 1024;
public static final int RECORD_PHOTO_MAX_SIZE = 4 * MB;
public static int dp2Px(Context context,float dp) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dp * scale + 0.5f);
}
public static float cm2Feet(float cm) {
return Math.round((cm / 2.54F) * 100) / 100F;
}
public static float feetToCm(int feet, int second) {
int feet2Inch = feet * 12;
return (feet2Inch + second) * 2.54F;
}
public static float feetToCm(int[] feet) {
return feetToCm(feet[0], feet[1]);
}
public static boolean twoFloatEqual(float a, float b) {
return Math.abs(a - b) < 10e-6;
}
public static boolean twoDoubleEqual(double a, double b) {
return Math.abs(a - b) < 10e-6;
}
@SuppressLint("NewApi")
public static Size getOptimalCameraSize(Size[] sizes, boolean swappedDimension, int viewWidth) {
boolean found = false;
int index = 0;
int largestArea = Integer.MIN_VALUE;
// found the w/h is 3:4 size
for (int i = 0; i < sizes.length; i++) {
int realW = swappedDimension ? sizes[i].getHeight() : sizes[i].getWidth();
int realH = swappedDimension ? sizes[i].getWidth() : sizes[i].getHeight();
float ratio = (float) realW / realH;
int area = realH * realW;
if (realW >= viewWidth && twoFloatEqual(ratio, 0.75F)) {
found = true;
if (largestArea < area) {
index = i;
largestArea = area;
}
}
}
if (found) {
return sizes[index];
}
index = 0;
largestArea = Integer.MIN_VALUE;
// if not found, found the w/h close and bigger than 3:4
for (int i = 0; i < sizes.length; i++) {
int realW = swappedDimension ? sizes[i].getHeight() : sizes[i].getWidth();
int realH = swappedDimension ? sizes[i].getWidth() : sizes[i].getHeight();
float ratio = (float) realW / realH;
int area = realH * realW;
if (realW >= viewWidth && ratio > 0.75) {
if (largestArea < area) {
largestArea = area;
index = i;
}
}
}
return sizes[index];
}
public static List<Size> sortSizes(Size[] sizes) {
List list = Arrays.asList(sizes);
Collections.sort(list, new CompareSizesByArea());
return list;
}
/**
* Compares two {@code Size}s based on their areas.
*/
@SuppressLint("NewApi")
static class CompareSizesByArea implements Comparator<Size> {
@Override
public int compare(Size lhs, Size rhs) {
// We cast here to ensure the multiplications won't overflow
return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
(long) rhs.getWidth() * rhs.getHeight());
}
}
public static int getScreenWidth(Context context){
DisplayMetrics displayMetrics = new DisplayMetrics();
((WindowManager) (context.getSystemService(Context.WINDOW_SERVICE))).getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
public static int getScreenHeight(Context context){
DisplayMetrics displayMetrics = new DisplayMetrics();
((WindowManager) (context.getSystemService(Context.WINDOW_SERVICE))).getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.heightPixels;
}
}
package com.example.gengmei_flutter_plugin.utils;
import android.content.Context;
import android.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class FileUtil {
public static void copyFilesFromAssets(Context context, String oldPath, String newPath) {
try {
String[] fileNames = context.getAssets().list(oldPath);
if (fileNames.length > 0) {
// directory
File file = new File(newPath);
if (!file.mkdirs())
{
Log.d("mkdir","can't make folder");
}
for (String fileName : fileNames) {
copyFilesFromAssets(context, oldPath + "/" + fileName,
newPath + "/" + fileName);
}
} else {
// file
InputStream is = context.getAssets().open(oldPath);
FileOutputStream fos = new FileOutputStream(new File(newPath));
byte[] buffer = new byte[1024];
int byteCount;
while ((byteCount = is.read(buffer)) != -1) {
fos.write(buffer, 0, byteCount);
}
fos.flush();
is.close();
fos.close();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void copyAssetsFileToSD(Context context,String name, String predictorPath) {
// File file = new File(predictorPath);
// if (file.exists()) {
// return;
// }
InputStream myInput = null;
OutputStream myOutput = null;
try {
myOutput = new FileOutputStream(predictorPath);
myInput = context.getAssets().open(name);
byte[] buffer = new byte[1024];
int length = myInput.read(buffer);
while (length > 0) {
myOutput.write(buffer, 0, length);
length = myInput.read(buffer);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
myOutput.flush();
myInput.close();
myOutput.close();
} catch (IOException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
}
}
}
package com.example.gengmei_flutter_plugin.utils
import android.widget.ImageView
import java.io.Serializable
/**
* Created by lsy
* on 2019/3/27
*/
interface ImageLoader : Serializable {
/**
* 缩略图加载方案
*
* @param imageView
* @param imagePath
*/
fun loadImage(imageView: ImageView, imagePath: String)
/**
* 大图加载方案
*
* @param imageView
* @param imagePath
*/
fun loadPreImage(imageView: ImageView, imagePath: String)
/**
* 视频播放方案
*
* @param imageView
* @param path
*/
// void loadVideoPlay(ImageView imageView, String path);
/**
* 缓存管理
*/
fun clearMemoryCache()
}
\ No newline at end of file
package com.example.gengmei_flutter_plugin.utils
import android.graphics.Paint
import android.os.Handler
import android.text.TextUtils
import android.util.Log
import android.view.View
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import java.io.File
import java.text.SimpleDateFormat
/**
* Created by lsy
* on 2019/4/18
*/
fun Any?.isNull(): Boolean {
return this == null
}
fun String.splitU(s: String): List<String>? {
if (this.contains(s)) {
return this.split(s)
}
return null
}
fun Disposable?.addTo(disposable: CompositeDisposable?) {
if (disposable != null && this != null) {
disposable.add(this)
}
}
fun String?.empty(): Boolean {
return TextUtils.isEmpty(this)
}
package com.example.gengmei_flutter_plugin.utils
import android.content.Context
import android.util.Log
import com.example.myimagepicker.luban.Luban
import java.io.File
/**
* @author lsy
* @date 2019-09-10
*/
class MyUtil {
companion object{
fun getImageCacheDir(context: Context, cacheName: String): File? {
val cacheDir = context.externalCacheDir
if (cacheDir != null) {
val result = File(cacheDir, cacheName)
return if (!result.mkdirs() && (!result.exists() || !result.isDirectory)) {
// File wasn't able to create a directory, or the result exists but not a directory
null
} else result
}
if (Log.isLoggable(Luban.TAG, Log.ERROR)) {
Log.e(Luban.TAG, "default disk cache dir is null")
}
return null
}
fun getFileName(pathandname: String): String? {
val start = pathandname.lastIndexOf("/")
val end = pathandname.lastIndexOf(".")
return if (start != -1 && end != -1) {
pathandname.substring(start + 1, end)
} else {
null
}
}
fun getFileFullName(pathandname: String): String? {
val start = pathandname.lastIndexOf("/")
val end = pathandname.lastIndexOf(".")
return if (start != -1 && end != -1) {
pathandname.substring(start + 1, pathandname.length)
} else {
null
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment