├── .gitignore ├── .idea ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── light │ │ └── example │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── light │ │ │ └── example │ │ │ ├── MainActivity.java │ │ │ └── NetActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── d1.jpg │ │ ├── ic_launcher_background.xml │ │ ├── pic.jpg │ │ ├── test_1920_1200.jpg │ │ └── test_4608_3456.jpg │ │ ├── layout │ │ ├── activity_main.xml │ │ └── activity_net.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── light │ └── example │ └── ExampleUnitTest.java ├── build.gradle ├── demo.jpg ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── light ├── .gitignore ├── build.gradle ├── jniLibs │ ├── arm64-v8a │ │ ├── libjpegbither.so │ │ └── liblight.so │ ├── armeabi-v7a │ │ ├── libjpegbither.so │ │ └── liblight.so │ └── armeabi │ │ ├── libjpegbither.so │ │ └── liblight.so ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── light │ │ └── core │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── light │ │ │ ├── body │ │ │ ├── ArgumentsAdapter.java │ │ │ ├── CompressArgs.java │ │ │ ├── Light.java │ │ │ ├── LightBuilder.java │ │ │ ├── LightCache.java │ │ │ ├── LightConfig.java │ │ │ └── RxLight.java │ │ │ ├── compress │ │ │ ├── LightCompressCore.java │ │ │ └── NativeCompressCore.java │ │ │ ├── core │ │ │ ├── AsyncCompressExecutor.java │ │ │ ├── LightCompressEngine.java │ │ │ ├── Utils │ │ │ │ ├── ContextUtil.java │ │ │ │ ├── DegreeHelper.java │ │ │ │ ├── DisplayUtil.java │ │ │ │ ├── FileUtils.java │ │ │ │ ├── L.java │ │ │ │ ├── MatrixUtil.java │ │ │ │ ├── MemoryComputeUtil.java │ │ │ │ ├── SimpleSizeCompute.java │ │ │ │ ├── UriParser.java │ │ │ │ └── http │ │ │ │ │ └── HttpDownLoader.java │ │ │ ├── cache │ │ │ │ ├── CacheKey.java │ │ │ │ ├── DiskLruCache.java │ │ │ │ ├── StrictLineReader.java │ │ │ │ └── Util.java │ │ │ └── listener │ │ │ │ ├── ICompressEngine.java │ │ │ │ ├── ICompressProxy.java │ │ │ │ ├── OnAsyncCompressFinishListener.java │ │ │ │ └── OnCompressFinishListener.java │ │ │ └── proxy │ │ │ ├── BitmapCompressProxy.java │ │ │ ├── BytesCompressProxy.java │ │ │ ├── CompressFactory.java │ │ │ ├── FileCompressProxy.java │ │ │ ├── ResourcesCompressProxy.java │ │ │ └── UriCompressProxy.java │ ├── jni │ │ ├── Android.mk │ │ ├── Application.mk │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bitherlibjni.c │ │ ├── libjpeg-turbo │ │ │ ├── android │ │ │ │ ├── config.h │ │ │ │ └── jconfig.h │ │ │ ├── cderror.h │ │ │ ├── cdjpeg.h │ │ │ ├── jconfig.h │ │ │ ├── jerror.h │ │ │ ├── jinclude.h │ │ │ ├── jmorecfg.h │ │ │ ├── jpeglib.h │ │ │ └── jversion.h │ │ └── libjpegbither.so │ ├── libs │ │ ├── armeabi-v7a │ │ │ ├── libjpegbither.so │ │ │ └── liblight.so │ │ └── armeabi │ │ │ ├── libjpegbither.so │ │ │ └── liblight.so │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── light │ └── core │ └── ExampleUnitTest.java ├── pic1.jpg ├── pic2.jpg ├── pic3.jpg └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 30 | 45 | 46 | 47 | 48 | 49 | 50 | 52 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Light 2 | 3 | [![license](https://img.shields.io/badge/license-Apache2.0-brightgreen.svg?style=flat)](https://github.com/JavaNoober/Light) 4 | [![JCenter](https://img.shields.io/badge/JCenter-Light-green.svg?style=flat)](https://bintray.com/noober/maven/Light) 5 | 6 | a lightweight image compress framework for Android based on libJpeg. 7 | 一个基于libJpeg的压缩图片框架, 支持配合rxjava使用。 8 | 9 | ### 说明 10 | 这个库主要是用于压缩图片体积,当然也可以压缩bitamp减少内存。但是在显示需要高清晰度的图片的时候,比如icon,背景图,建议还是使用glide picasso等成熟的框架,而需要保存图片文件的时候使用本框架。 11 | 如果需要对icon 背景图等图片压缩可以通过这个网址: [https://tinypng.com/](https://tinypng.com/) 12 | 13 | ### demo效果 14 | 15 | 先展示一下压缩前后的效果对比,以及文件大小和占用内存的大小 16 | demo比较简单,运行的时候请打开sd卡权限和相册拍照权限。 17 | 18 | ![](https://raw.githubusercontent.com/JavaNoober/Light/master/demo.jpg) 19 | 20 | ### 基本功能: 21 | 支持的压缩类型: 22 | File,String,Uri,Bytes,Bitmap,DrawableResourceID,Drawable 23 | 24 | * 1:图片的旋转、缩放、平移操作 25 | * 2:异步和同步压缩处理 26 | * 3:同步压缩 27 | * 4:可以配合RxJava2使用 28 | 29 | ### 版本记录: 30 | 31 | 1.0.0 完成大致功能 32 | 1.1.0 修复从uri获取路径错误的bug; 33 | 增加ignoreSize的设置,以便用于压缩图片保持原尺寸; 34 | 支持配合rxjava2使用; 35 | 1.1.1 优化异常提示; 36 | 1.1.2 增加Light.getInstance().compressFromHttp方法,从网络获取图片; 37 | 1.1.3 RxLight去除线程切换控制,让开发者自己去指定线程; 38 | 去掉无用类; 39 | 1.1.4 增加autoRotation的设置(只有压缩从本地读取图片有用,其他情况无效),可以将图片自动旋转为0度, 便于解决三星手机拍照会自动将图片选择的问题; 40 | 1.1.5 优化部分代码,解决bug; 41 | 增加autoRecycle的设置(只有压缩bitmap和压缩byte类型的图片有用,其他类型图片无效),开启该设置代表自动会将传入的bitmap或者bytes进行内存回收; 42 | 1.1.6 增加compressFileSize的压缩设置,可以设置当大于一定kb大小的图片,才会进行压缩,只对压缩保存到本地的方法有效,对压缩保存到bitmap的方法无效; 43 | 1.1.7 默认对gif不支持压缩 44 | 1.1.9 修复bug 45 | 1.2.0 增加Bitmap.Config的设置,默认是RGB_565,可以在CompressArgs设置,也可以在LightConfig统一配置 46 | 1.2.1 网络图片下载增加磁盘缓存 47 | 1.2.2 增加arm64-v8a的支持 48 | 49 | ### 使用方法: 50 | 51 | android { 52 | ... 53 | ndk { 54 | abiFilters 'armeabi-v7a', 'armeabi' 55 | //abiFilters 'armeabi-v7a', 'armeabi', 'arm64-v8a' 根据需要选择指令集架构 56 | } 57 | } 58 | 59 | //引入 60 | implementation 'com.noober.light:core:1.2.2' 61 | 62 | //如果要配合rxjava2,加入rxjava2的依赖 63 | implementation 'io.reactivex.rxjava2:rxandroid:2.0.1' 64 | implementation 'io.reactivex.rxjava2:rxjava:2.1.7' 65 | 66 | 67 | #### 设置压缩参数: 68 | CompressArgs这个类用于设置每次所要压缩到的指定的宽高以及压缩质量。使用如下: 69 | 70 | CompressArgs args = new CompressArgs.Builder().width(width).height(height).quality(70).ignoreSize(false).build(); 71 | 72 | ##### 参数说明: 73 | 1.width: 要压缩到的图片的宽度,单位px 74 | 2.height: 要压缩到的图片的高度,单位px 75 | 3.quality: 压缩质量, 可选范围是0-100。 76 | 4.ignoreSize: 是否要忽略压缩后图片宽高的限制, 如果设为true,压缩的时候会根据原图本身大小进行压缩,设置的width和height就会失效,默认false。 77 | 5.autoRotation: 是否要将图片自动摆正,只有压缩从本地读取图片有用,其他情况无效(例如三星手机拍照后图片会自动旋转,设为true则会自动将图片旋转正确的方向)。 78 | 6.autoRecycle: 是否需要自动将传入的bitmap或者bytes进行内存回收,只有压缩bitmap和压缩byte类型的图片有用,其他类型图片无效 79 | 7.compressFileSize: 对压缩图片到本地的时候增加文件大小的设置,如果大于此kb大小的图片,则不进行压缩。 80 | 8.bitmapConfig: 设置bitmap的色彩模式,默认是RGB_565 81 | 因为从网络下载图片保存到本地,中间默认会自动压缩图片,如果不想对图片进行压缩,并保持宽高的话,设置如下参数即可: 82 | 83 | CompressArgs args = new CompressArgs.Builder().quality(100).ignoreSize(true).autoRotation(true) 84 | .autoRecycle(true).bitmapConfig(Bitmap.Config.ARGB_8888).build(); 85 | 86 | 87 | ##### 默认参数: 88 | 调用compress方法的时候也可以不初始化这个参数,框架会自动初始化一个默认的压缩设置。 89 | 90 | **默认规则**如下: 91 | 压缩图片的最大默认高度是屏幕高度; 92 | 图片的最大宽度是屏幕宽度; 93 | 默认压缩质量是85; 94 | ignoreSize 为false。 95 | 96 | ##### 设置全局的压缩参数,以便不需要每次都去设置: 97 | 建议在Application的onCreate中进行初始化,使用如下: 98 | 99 | LightConfig lightConfig = new LightConfig(); 100 | lightConfig.setDefaultQuality(xx); 101 | lightConfig.setMaxWidth(xx); 102 | lightConfig.setMaxHeight(xx); 103 | lightConfig.setMaxHeight(xx); 104 | lightConfig.setNeedIgnoreSize(xx); 105 | ... 106 | Light.getInstance().setConfig(lightConfig); 107 | 108 | 109 | #### 压缩图片,获取Bitmap:images -> Bitmap 110 | 111 | 支持**File,String,Uri,Bytes,Bitmap,DrawableResourceID,Drawable**这5种类型压缩为Bitmap。 112 | 113 | 114 | //String,Uri,Bytes,Bitmap,File -->bitmap 115 | Bitmap bitmap = Light.getInstance().compress(path); 116 | //args为CompressArgs压缩参数,不传入,即用默认参数 117 | Bitmap bitmap = Light.getInstance().compress(path, args); 118 | ..... 119 | 120 | #### 压缩图片并且保存到本地:images -> boolean 121 | 支持**File,String,Uri,Bytes,Bitmap**这5种类型保存为文件。 122 | 想对于压缩成Bitmap的方法只是多了一个输出路径。 123 | 124 | //images --> boolean //保存图片,返回值代表保存是否成功 125 | //img为要压缩的图片,args是压缩参数,不传即默认, outPath为输出路径 126 | Light.getInstance().compress(img, args, outPath); 127 | Light.getInstance().compress(img, outPath); 128 | //支持类型Bitmap, Bytes, String, Resource, Uri, Drawable 129 | 130 | #### 从网络获取图片 131 | 132 | 注意,onCompressFinishListener必须实现,否则会不进行下载,onCompressFinishListener必须实现接口返回值是byte,可以用来保存到file, openDiskCache若为true则开启图片缓存 133 | 134 | Light.getInstance().compressFromHttp(uri, openDiskCache, new OnCompressFinishListener() { 135 | @Override 136 | public void onFinish(byte[] bytes) { 137 | Bitmap bitmap = Light.getInstance().compress(bytes); 138 | ... 139 | } 140 | }); 141 | 142 | #### 配合RxJava2使用 143 | 关于配合RxJava2使用的类都在RxLight这个类中。 144 | 通过与rxJava的配合,一行代码就能实现从网络下载->压缩->显示,这个过程,非常的方便。 145 | 146 | 使用方法如下: 147 | 148 | RxLight会自动对图片进行下载 -> 压缩 -> 显示或保存到本地 149 | ###### 从网络获取资源 -> Bitmap: 150 | 151 | RxLight.compressForUriHttp()中参数openDiskCache控制是否增加磁盘缓存 152 | 153 | //uri类型的网络资源 154 | Flowable.just(uri).compose(RxLight.compressForUriHttp()).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(bitmap -> ivCompress.setImageBitmap(bitmap)); 155 | List urlList = new ArrayList<>(); 156 | .... 157 | Flowable.fromIterable(urlList).compose(RxLight.compressForUriHttp()).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(bitmap -> ivCompress.setImageBitmap(bitmap)); 158 | //url类型的网络资源 159 | Flowable.just(url).compose(RxLight.compressForStringHttp()).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(bitmap -> ivCompress.setImageBitmap(bitmap)); 160 | List urlList = new ArrayList<>(); 161 | .... 162 | Flowable.fromIterable(urlList).compose(RxLight.compressForStringHttp()).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(bitmap -> ivCompress.setImageBitmap(bitmap)); 163 | //或者传入自定义的压缩参数只需要在compressForUriHttp() 和 compressForStringHttp()传入CompressArgs即可 164 | CompressArgs args = new CompressArgs(); 165 | .... 166 | Flowable.just(uri).compose(RxLight.compressForUriHttp(args)).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(bitmap -> ivCompress.setImageBitmap(bitmap)); 167 | 168 | ###### 从网络获取资源 -> boolean(保存到本地): 169 | 与上述方法类似,只需要compressForUri() 和 compressForString()传入要保存到的路径即可。同样支持uri和string的网络地址类型。 170 | 171 | 172 | RxLight.compressForUriHttp(中参数openDiskCache控制是否增加磁盘缓存, path)中参数openDiskCache控制是否增加磁盘缓存 173 | String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/pic.jpg"; 174 | Flowable.just(uri).compose(RxLight.compressForUriHttp(path)).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(result -> {}); 175 | //自定义压缩参数 176 | CompressArgs args = new CompressArgs(); 177 | .... 178 | Flowable.just(uri).compose(RxLight.compressForUriHttp(path, args)).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(result -> {}); 179 | 180 | ##### 通过本地资源异步压缩 181 | 同样都支持 File,String,Uri,Bytes,Bitmap,DrawableResourceID,Drawable这几种类型 182 | ###### 图片资源 -> Bitmap 183 | 通过RxLight.compress()方法即可: 184 | 185 | Flowable.just(image).compose(RxLight.compress()).subscribe(bitmap -> ivCompress.setImageBitmap(bitmap)); 186 | 187 | ###### 图片资源 -> Boolean(保存到本地): 188 | 通过RxLight.compress(outPath)方法即可: 189 | 190 | Flowable.just(image).compose(RxLight.compress(outPath)).subscribe(bitmap -> ivCompress.setImageBitmap(bitmap)); 191 | 192 | #### 其他 193 | * 1:MemoryComputeUtil工具类,获取bitmap占用内存的大小,返回值单位是kb。 194 | 195 | 196 | MemoryComputeUtil.getMemorySize(compressBitmap) 197 | 198 | * 2:关于so文件的编译,可以移步[https://github.com/JavaNoober/LibJpegCompress](https://github.com/JavaNoober/LibJpegCompress)。 199 | 如何去编译,我在很久之前的写过一个博客介绍过:[http://blog.csdn.net/qq_25412055/article/details/53878655](http://blog.csdn.net/qq_25412055/article/details/53878655) 200 | 201 | * 3:MatrixUtil工具类 202 | 可以很方便的对Bitmap进行放大缩小、旋转、缩放、平移等处理,使用也很方便,支持Matrix的大部分方法。 203 | 204 | 205 | Bitmap result = new MatrixUtil.Build().scale(scaleSize, scaleSize).rotate(90f).bitmap(bitmap).build(); 206 | 207 | ### 总结 208 | 209 | 版本还在逐步更新中,欢迎各位大佬star,以及提出建议。 210 | 211 | GitHub demo下载地址:[https://github.com/JavaNoober/Light](https://github.com/JavaNoober/Light) 212 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | defaultConfig { 6 | applicationId "com.light.example" 7 | minSdkVersion 14 8 | targetSdkVersion 26 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | ndk { 13 | abiFilters 'armeabi-v7a', 'armeabi', 'arm64-v8a' 14 | } 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | sourceSets { 23 | main { 24 | jniLibs.srcDirs = ['libs'] 25 | } 26 | } 27 | // splits { 28 | // abi { 29 | // enable true 30 | // reset() 31 | // include 'armeabi-v7a', 'armeabi' 32 | // universalApk true 33 | // } 34 | // } 35 | compileOptions { 36 | sourceCompatibility JavaVersion.VERSION_1_8 37 | targetCompatibility JavaVersion.VERSION_1_8 38 | } 39 | } 40 | 41 | dependencies { 42 | implementation fileTree(include: ['*.jar'], dir: 'libs') 43 | implementation 'com.android.support:appcompat-v7:26.1.0' 44 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 45 | testImplementation 'junit:junit:4.12' 46 | androidTestImplementation 'com.android.support.test:runner:1.0.1' 47 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 48 | // implementation 'com.noober.light:core:1.2.0' 49 | implementation project(':light') 50 | implementation 'io.reactivex.rxjava2:rxandroid:2.0.1' 51 | implementation 'io.reactivex.rxjava2:rxjava:2.1.7' 52 | } 53 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/light/example/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.light.example; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.light.example", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/light/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.light.example; 2 | 3 | import android.content.ContentValues; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.net.Uri; 8 | import android.os.Bundle; 9 | import android.os.Environment; 10 | import android.provider.MediaStore; 11 | import android.support.v7.app.AppCompatActivity; 12 | import android.util.Log; 13 | import android.view.Menu; 14 | import android.view.MenuItem; 15 | import android.view.View; 16 | import android.widget.ImageView; 17 | import android.widget.TextView; 18 | 19 | import com.light.body.CompressArgs; 20 | import com.light.body.Light; 21 | import com.light.body.LightConfig; 22 | import com.light.body.RxLight; 23 | import com.light.core.Utils.MemoryComputeUtil; 24 | import com.light.core.Utils.UriParser; 25 | import com.light.core.listener.OnCompressFinishListener; 26 | 27 | import java.io.File; 28 | import java.util.List; 29 | import java.util.Locale; 30 | 31 | import io.reactivex.Flowable; 32 | 33 | 34 | public class MainActivity extends AppCompatActivity { 35 | ImageView ivCompress; 36 | ImageView ivImage; 37 | TextView tvInfo; 38 | TextView tvInfo1; 39 | TextView tvInfo2; 40 | Uri imageUri; 41 | String path1 = Environment.getExternalStorageDirectory().getAbsolutePath() + "/ttjpeg.jpg"; 42 | final static String info1 = "压缩后:\n高度:%d,宽度:%d,占用内存:%dKB,文件大小:%dKB"; 43 | final static String info2 = "原图片:\n高度:%d,宽度:%d,占用内存:%dKB,文件大小:%dKB"; 44 | 45 | @Override 46 | protected void onCreate(Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | setContentView(R.layout.activity_main); 49 | LightConfig config = new LightConfig(); 50 | config.setAutoRotation(true); 51 | config.setAutoRecycle(true); 52 | Light.getInstance().setConfig(config); 53 | ivCompress = findViewById(R.id.image_compress); 54 | ivImage = findViewById(R.id.image); 55 | tvInfo = findViewById(R.id.tv_info); 56 | tvInfo1 = findViewById(R.id.tv_info1); 57 | tvInfo2 = findViewById(R.id.tv_info2); 58 | 59 | String url = "https://upload.jdcf88.com/test/2018/5/25/15272095511667.jpg"; 60 | new Thread(() -> { 61 | Light.getInstance().compressFromHttp(url, new OnCompressFinishListener() { 62 | @Override 63 | public void onFinish(byte[] bytes) { 64 | runOnUiThread(() -> { 65 | if(bytes == null){ 66 | // photoView.setImageResource(R.drawable.bg_preview_error); 67 | }else { 68 | // Bitmap bitmap = Light.getInstance().compress(bytes); 69 | // cache.put(urls.get(position), bitmap); 70 | // photoView.setImageBitmap(bitmap); 71 | } 72 | }); 73 | } 74 | 75 | @Override 76 | public void onError(Throwable throwable) { 77 | throwable.printStackTrace(); 78 | // photoView.setImageResource(R.drawable.bg_preview_error); 79 | } 80 | }); 81 | }).start(); 82 | 83 | // //Light1.2新增写法: 84 | // Bitmap bitmap1 = Light.getInstance().source(imageUri).width(500).height(500).autoRotation(true).compress(); 85 | // boolean result1 = Light.getInstance().source(imageUri).width(500).height(500).autoRotation(true).compress(path); 86 | // CompressArgs args = new CompressArgs.Builder().width(500).height(500).autoRecycle(true).build(); 87 | // Bitmap bitmap2 = Light.getInstance().source(imageUri).compressArgs(args).compress(); 88 | // boolean result2 = Light.getInstance().source(imageUri).compressArgs(args).compress(path); 89 | 90 | } 91 | 92 | @Override 93 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 94 | super.onActivityResult(requestCode, resultCode, data); 95 | if (requestCode == 1 && imageUri != null) { 96 | //效果同下 97 | // Light.setImage(ivCompress, imageUri); 98 | Bitmap compressBitmap = Light.getInstance().compress(imageUri); 99 | ivCompress.setImageBitmap(compressBitmap); 100 | Light.getInstance().compress(imageUri, path1); 101 | // Flowable.just(imageUri).compose(RxLight.compress()).subscribe(bitmap -> ivCompress.setImageBitmap(bitmap)); 102 | //系统获取图片的方法 103 | String path = UriParser.getPathFromContentUri(imageUri); 104 | BitmapFactory.Options options = new BitmapFactory.Options(); 105 | options.inJustDecodeBounds = true; 106 | BitmapFactory.decodeFile(path, options); 107 | Bitmap bitmap2 = BitmapFactory.decodeFile(path); 108 | ivImage.setImageBitmap(bitmap2); 109 | tvInfo1.setVisibility(View.VISIBLE); 110 | tvInfo2.setVisibility(View.VISIBLE); 111 | tvInfo1.setText(String.format(Locale.CHINA, info1, compressBitmap.getHeight(), 112 | compressBitmap.getWidth(), MemoryComputeUtil.getMemorySize(compressBitmap), new File(path1).length() / 1024)); 113 | tvInfo2.setText(String.format(Locale.CHINA, info2, options.outHeight, 114 | options.outWidth, MemoryComputeUtil.getMemorySize(bitmap2), new File(path).length() / 1024)); 115 | } else if (requestCode == 2 && data != null) { 116 | Uri imageUri = data.getData(); 117 | String path = UriParser.getPathFromContentUri(imageUri); 118 | BitmapFactory.Options options = new BitmapFactory.Options(); 119 | options.inJustDecodeBounds = true; 120 | BitmapFactory.decodeFile(path, options); 121 | // Bitmap compressBitmap = Light.getInstance().compress(imageUri); 122 | CompressArgs args = new CompressArgs.Builder().width(1600) 123 | .bitmapConfig(Bitmap.Config.ARGB_8888) 124 | .height(1600).autoRotation(true).compressFileSize(200) 125 | .build(); 126 | Light.getInstance().compress(imageUri, args, path1); 127 | Bitmap compressBitmap = Light.getInstance().compress(path1); 128 | ivCompress.setImageBitmap(compressBitmap); 129 | Bitmap bitmap2 = BitmapFactory.decodeFile(path); 130 | ivImage.setImageBitmap(bitmap2); 131 | // tvInfo1.setVisibility(View.VISIBLE); 132 | // tvInfo2.setVisibility(View.VISIBLE); 133 | // tvInfo1.setText(String.format(Locale.CHINA, info1, compressBitmap.getHeight(), 134 | // compressBitmap.getWidth(), MemoryComputeUtil.getMemorySize(compressBitmap), new File(path1).length() / 1024)); 135 | // tvInfo2.setText(String.format(Locale.CHINA, info2, options.outHeight, 136 | // options.outWidth, MemoryComputeUtil.getMemorySize(bitmap2), new File(path).length() / 1024)); 137 | } 138 | 139 | } 140 | 141 | @Override 142 | public boolean onCreateOptionsMenu(Menu menu) { 143 | menu.add("相册"); 144 | menu.add("拍照"); 145 | menu.add("从网络加载"); 146 | return super.onCreateOptionsMenu(menu); 147 | } 148 | 149 | @Override 150 | public boolean onOptionsItemSelected(MenuItem item) { 151 | if ("相册".equals(item.getTitle())) { 152 | Intent intent = new Intent(); 153 | intent.setAction(Intent.ACTION_PICK); 154 | intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI); 155 | startActivityForResult(intent, 2); 156 | } else if ("拍照".equals(item.getTitle())) { 157 | imageUri = getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 158 | new ContentValues()); 159 | Intent takePhotoIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); 160 | takePhotoIntent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageUri); 161 | startActivityForResult(takePhotoIntent, 1); 162 | } else if ("从网络加载".equals(item.getTitle())) { 163 | startActivity(new Intent(MainActivity.this, NetActivity.class)); 164 | } 165 | return true; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /app/src/main/java/com/light/example/NetActivity.java: -------------------------------------------------------------------------------- 1 | package com.light.example; 2 | 3 | import android.app.ProgressDialog; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.net.Uri; 7 | import android.os.Environment; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.os.Bundle; 10 | import android.view.View; 11 | import android.widget.Button; 12 | import android.widget.ImageView; 13 | import android.widget.TextView; 14 | 15 | import com.light.body.Light; 16 | import com.light.body.RxLight; 17 | import com.light.core.Utils.MatrixUtil; 18 | import com.light.core.Utils.MemoryComputeUtil; 19 | import com.light.core.Utils.http.HttpDownLoader; 20 | import com.light.core.listener.OnCompressFinishListener; 21 | 22 | import java.io.BufferedOutputStream; 23 | import java.io.File; 24 | import java.io.FileNotFoundException; 25 | import java.io.FileOutputStream; 26 | import java.io.IOException; 27 | import java.io.OutputStream; 28 | import java.util.Locale; 29 | 30 | import io.reactivex.Flowable; 31 | import io.reactivex.Scheduler; 32 | import io.reactivex.android.schedulers.AndroidSchedulers; 33 | import io.reactivex.schedulers.Schedulers; 34 | 35 | public class NetActivity extends AppCompatActivity { 36 | ImageView ivCompress; 37 | ImageView ivImage; 38 | TextView tvInfo; 39 | TextView tvInfo1; 40 | TextView tvInfo2; 41 | TextView tvSize; 42 | Button button1; 43 | Button button2; 44 | Button button3; 45 | String path1 = Environment.getExternalStorageDirectory().getAbsolutePath() + "/1.jpg";//压缩后 46 | String path2 = Environment.getExternalStorageDirectory().getAbsolutePath() + "/2.jpg";//原图片 47 | final static String info1 = "压缩后:\n高度:%d,宽度:%d,占用内存:%dKB"; 48 | final static String info2 = "原图片:\n高度:%d,宽度:%d,占用内存:%dKB"; 49 | ProgressDialog progressDialog; 50 | 51 | @Override 52 | protected void onCreate(Bundle savedInstanceState) { 53 | super.onCreate(savedInstanceState); 54 | setContentView(R.layout.activity_net); 55 | ivCompress = findViewById(R.id.image_compress); 56 | ivImage = findViewById(R.id.image); 57 | tvInfo = findViewById(R.id.tv_info); 58 | tvInfo1 = findViewById(R.id.tv_info1); 59 | tvInfo2 = findViewById(R.id.tv_info2); 60 | button1 = findViewById(R.id.btn1); 61 | button2 = findViewById(R.id.btn2); 62 | button3 = findViewById(R.id.btn3); 63 | tvSize = findViewById(R.id.tv_size); 64 | tvInfo1.setVisibility(View.VISIBLE); 65 | tvInfo2.setVisibility(View.VISIBLE); 66 | progressDialog = new ProgressDialog(this); 67 | progressDialog.setTitle("图片加载中"); 68 | progressDialog.setMessage("Loading..."); 69 | progressDialog.setCancelable(false); 70 | button1.setOnClickListener(new View.OnClickListener() { 71 | @Override 72 | public void onClick(View v) { 73 | progressDialog.show(); 74 | Uri uri = Uri.parse("http://img52.fooww.com:9999/group5/M01/00/99/ZyjCGlrtH9uEPlSIAAAAAN9Juaw140.jpg"); 75 | showImg(uri); 76 | } 77 | }); 78 | 79 | button2.setOnClickListener(new View.OnClickListener() { 80 | @Override 81 | public void onClick(View v) { 82 | progressDialog.show(); 83 | Uri uri = Uri.parse("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png"); 84 | showImg(uri); 85 | } 86 | }); 87 | 88 | button3.setOnClickListener(new View.OnClickListener() { 89 | @Override 90 | public void onClick(View v) { 91 | progressDialog.show(); 92 | Uri uri = Uri.parse("http://pic31.nipic.com/20130705/9527735_231540074000_2.jpg"); 93 | showImg(uri); 94 | } 95 | }); 96 | } 97 | 98 | private void showImg(Uri uri) { 99 | 100 | new Thread(new Runnable() { 101 | @Override 102 | public void run() { 103 | byte[] bytes = HttpDownLoader.downloadImage(uri); 104 | BitmapFactory.Options options = new BitmapFactory.Options(); 105 | Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); 106 | File file = new File(path2); 107 | OutputStream output = null; 108 | try { 109 | output = new FileOutputStream(file); 110 | BufferedOutputStream bufferedOutput = new BufferedOutputStream(output); 111 | bufferedOutput.write(bytes); 112 | } catch (FileNotFoundException e) { 113 | e.printStackTrace(); 114 | } catch (IOException e) { 115 | e.printStackTrace(); 116 | } 117 | if(!new File(path1).exists()){ 118 | return; 119 | } 120 | runOnUiThread(new Runnable() { 121 | @Override 122 | public void run() { 123 | progressDialog.dismiss(); 124 | float scaleX = MatrixUtil.getScale(1920, 1080, options.outWidth, options.outHeight); 125 | ivImage.setImageBitmap(new MatrixUtil.Build().scale(scaleX, scaleX).bitmap(bitmap).build()); 126 | Light.getInstance().compress(path2, path1); 127 | tvInfo2.setText(String.format(Locale.CHINA, info2, options.outHeight, 128 | options.outWidth, MemoryComputeUtil.getMemorySize(bitmap))); 129 | tvSize.setText("原图片文件大小:" + file.length() / 1024 + "KB;压缩后图片文件大小:" + 130 | new File(path1).length() / 1024 + "KB"); 131 | } 132 | }); 133 | } 134 | }).start(); 135 | Flowable.just(uri).compose(RxLight.compressForUriHttp()) 136 | .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) 137 | .subscribe(bitmap -> { 138 | progressDialog.dismiss(); 139 | ivCompress.setImageBitmap(bitmap); 140 | tvInfo1.setText(String.format(Locale.CHINA, info1, bitmap.getHeight(), 141 | bitmap.getWidth(), MemoryComputeUtil.getMemorySize(bitmap))); 142 | }); 143 | 144 | //缓存测试 145 | // new Thread(() -> Light.getInstance().compressFromHttp(uri, true, new OnCompressFinishListener() { 146 | // @Override 147 | // public void onFinish(byte[] bytes) { 148 | // Bitmap bitmap = Light.getInstance().compress(bytes); 149 | // runOnUiThread(() -> { 150 | // progressDialog.dismiss(); 151 | // ivCompress.setImageBitmap(bitmap); 152 | // tvInfo1.setText(String.format(Locale.CHINA, info1, bitmap.getHeight(), 153 | // bitmap.getWidth(), MemoryComputeUtil.getMemorySize(bitmap))); 154 | // }); 155 | // } 156 | // 157 | // @Override 158 | // public void onError(Throwable throwable) { 159 | // 160 | // } 161 | // })).start(); 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/d1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JavaNoober/Light/542685d74227d325241eacbaeac99a7759e0ff3e/app/src/main/res/drawable/d1.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 16 | 21 | 26 | 31 | 36 | 41 | 46 | 51 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 116 | 121 | 126 | 131 | 136 | 141 | 146 | 151 | 156 | 161 | 166 | 171 | 172 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/pic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JavaNoober/Light/542685d74227d325241eacbaeac99a7759e0ff3e/app/src/main/res/drawable/pic.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/test_1920_1200.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JavaNoober/Light/542685d74227d325241eacbaeac99a7759e0ff3e/app/src/main/res/drawable/test_1920_1200.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/test_4608_3456.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JavaNoober/Light/542685d74227d325241eacbaeac99a7759e0ff3e/app/src/main/res/drawable/test_4608_3456.jpg -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 19 | 20 | 25 | 26 | 33 | 34 | 40 | 41 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_net.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 18 | 19 |