├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── dictionaries │ └── shaohui.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── LICENSE ├── README.md ├── README_ZH.md ├── build.gradle ├── example ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── me │ │ └── shaohui │ │ └── advancedlubanexample │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── me │ │ │ └── shaohui │ │ │ └── advancedlubanexample │ │ │ └── MainActivity.java │ └── res │ │ ├── layout │ │ ├── activity_main.xml │ │ └── activity_weixin.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── me │ └── shaohui │ └── advancedlubanexample │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── image └── sketch_map.png ├── library ├── .gitignore ├── bintrayUpload.gradle ├── build.gradle ├── proguard-rules.pro ├── project.properties └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── me │ │ └── shaohui │ │ └── advancedluban │ │ ├── Luban.java │ │ ├── LubanBuilder.java │ │ ├── LubanCompresser.java │ │ ├── OnCompressListener.java │ │ ├── OnMultiCompressListener.java │ │ └── Preconditions.java │ └── res │ └── values │ └── strings.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/libraries 2 | .DS_Store 3 | /captures 4 | .externalNativeBuild 5 | 6 | # Built application files 7 | *.apk 8 | *.ap_ 9 | 10 | # Files for the ART/Dalvik VM 11 | *.dex 12 | 13 | # Java class files 14 | *.class 15 | 16 | # Generated files 17 | bin/ 18 | gen/ 19 | out/ 20 | 21 | # Gradle files 22 | .gradle/ 23 | build/ 24 | 25 | # Local configuration file (sdk path, etc) 26 | local.properties 27 | 28 | # Proguard folder generated by Eclipse 29 | proguard/ 30 | 31 | # Log Files 32 | *.log 33 | 34 | # Android Studio Navigation editor temp files 35 | .navigation/ 36 | 37 | # Android Studio captures folder 38 | captures/ 39 | 40 | # Intellij 41 | *.iml 42 | .idea/workspace.xml 43 | 44 | # Keystore files 45 | *.jks 46 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/dictionaries/shaohui.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | luban 5 | 6 | 7 | -------------------------------------------------------------------------------- /.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 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AdvancedLuban 2 | [![build](https://img.shields.io/badge/build-1.3.5-brightgreen.svg?maxAge=2592000)](https://bintray.com/shaohui/maven/AdvancedLuban) 3 | [![license](https://img.shields.io/badge/license-Apache%202-blue.svg?maxAge=2592000)](https://github.com/shaohui10086/AdvancedLuban/blob/master/LICENSE) 4 | 5 | 6 | [中文版](/README_ZH.md) 7 | 8 | ![sketch](/image/sketch_map.png) 9 | 10 | 11 | `AdvancedLuban` —— Is a convenient simple `Android` image compression tool library.Provides multiple compression strategies.Different calling methods,Custom compression,Multi-Image synchronous compression and so on,Focus on a better picture compression experience 12 | 13 | Image Count | Origin Total size | Compressed Total size | Time Cost 14 | --- | --- | --- | --- 15 | 1 | 4.3Mb | 85Kb | 0.23s 16 | 4 | 14.22Mb | 364Kb | 1.38s 17 | 9 | 36.23Mb | 745Kb | 4.43s 18 | 19 | 20 | ## Import 21 | 22 | Maven 23 | 24 | 25 | me.shaohui.advancedluban 26 | library 27 | 1.3.5 28 | pom 29 | 30 | 31 | 32 | or Gradle 33 | 34 | compile 'me.shaohui.advancedluban:library:1.3.5' 35 | 36 | ## Usage 37 | 38 | 39 | ### `Listener` mode 40 | 41 | `Advanced Luban` internal` Computation` thread for image compression, external calls simply set the Listener can be: 42 | 43 | Luban.compress(context, file) 44 | .putGear(Luban.THIRD_GEAR) // set the compress mode, default is : THIRD_GEAR 45 | .launch(listener); // start compression and set the listener 46 | 47 | ### `RxJava` mode 48 | 49 | `RxJava` call the same default` Computation` thread to compress, you can also define any thread, can be observed in any thread: 50 | 51 | Luban.compress(context, file) 52 | .putGear(Luban.CUSTOM_GEAR) 53 | .asObservable() // generate Observable 54 | .subscribe(successAction, errorAction) // subscribe the compress result 55 | 56 | ### Compression mode 57 | 58 | 59 | #### 1. CUSTOM_GEAR 60 | 61 | compress image file according to the restrictions you set, you can limit: the width, height or file size of the image file 62 | 63 | Luban.compress(context, file) 64 | .setMaxSize(500) // limit the final image size(unit:Kb) 65 | .setMaxHeight(1920) // limit image height 66 | .setMaxWidth(1080) // limit image width 67 | .putGear(Luban.CUSTOM_GEAR) // use CUSTOM GEAR compression mode 68 | .asObservable() 69 | 70 | #### 2. THIRD_GEAR 71 | 72 | Using custom algorithms, according to the picture aspect ratio, the picture is compressed quickly, the resulting image size is about 100Kb, for general compression, no file size limit and picture width limit 73 | 74 | #### 3. FIRST_GEAR 75 | 76 | The simplified version of `THIRD GEAR`, the compressed image resolution is less than 1280 x 720, the final file is less than 60Kb. suitable for fast compression, regardless of the final picture quality 77 | 78 | ## Multi-Image synchronous compression 79 | 80 | If you choose to call the way `Listener`: 81 | 82 | Luban.get(this) 83 | .putGear(Luban.CUSTOM_GEAR) 84 | .load(fileList) // load all images 85 | .launch(multiCompressListener); // passing an OnMultiCompress Listener 86 | 87 | or the `RxJava` way to use: 88 | 89 | Luban.get(this) 90 | .putGear(Luban.CUSTOM_GEAR) 91 | .load(fileList) // load all images 92 | .asListObservable() // Generates Observable . Returns the result of all the images compressed successfully 93 | 94 | ## About OOM 95 | 96 | If you use a multi-map compression, we must take into account the risk of OOM, recommend you use CUSTOM_GEAR, and then customize the compression index, to a large extent reduce the risk of OOM, the current test did not find the problem of OOM 97 | 98 | ## ChangeLog 99 | 100 | #### 1.3.5 101 | - Add custom compression cache directory 102 | 103 | #### 1.3.4 104 | - update RxJava to RxJava2 105 | 106 | #### 1.3.3 107 | - Set the default observed in the main thread 108 | 109 | #### 1.3.2 110 | - Optimize memory usage 111 | 112 | #### 1.3.1 113 | - Added custom compression format 114 | - COMO_GEAR used to solve the problem of OOM 115 | - Refactored most of the code 116 | - To support WebP, the minimum supported version is increased to 14 117 | 118 | ## Issue 119 | 120 | You can according to your needs to choose a different compression mode and call mode ! b( ̄▽ ̄)d !Finally, I welcome the Issue 121 | 122 | ## Thanks For 123 | - https://github.com/Curzibn/Luban 124 | - https://github.com/ReactiveX/Rxjava 125 | - https://github.com/ReactiveX/RxAndroid 126 | 127 | ## License 128 | 129 | Copyright 2016 shaohui10086 130 | 131 | Licensed under the Apache License, Version 2.0 (the "License"); 132 | you may not use this file except in compliance with the License. 133 | You may obtain a copy of the License at 134 | 135 | http://www.apache.org/licenses/LICENSE-2.0 136 | 137 | Unless required by applicable law or agreed to in writing, software 138 | distributed under the License is distributed on an "AS IS" BASIS, 139 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 140 | See the License for the specific language governing permissions and 141 | limitations under the License. 142 | 143 | 144 | -------------------------------------------------------------------------------- /README_ZH.md: -------------------------------------------------------------------------------- 1 | # AdvancedLuban 2 | [![build](https://img.shields.io/badge/build-1.3.5-brightgreen.svg?maxAge=2592000)](https://bintray.com/shaohui/maven/AdvancedLuban) 3 | [![license](https://img.shields.io/badge/license-Apache%202-blue.svg?maxAge=2592000)](https://github.com/shaohui10086/AdvancedLuban/blob/master/LICENSE) 4 | 5 | ![sketch](/image/sketch_map.png) 6 | 7 | `AdvancedLuban` —— 是一个方便简约的 `Android` 图片压缩工具库,提供多种压缩策略(包括`Luban`原有的压缩策略),多种调用方式,自定义压缩,多图压缩,专注更好的图片压缩使用体验 8 | 9 | 10 | 照片数量 | 原图总大小 | 压缩后总大小 | 总耗时 11 | --- | --- | --- | --- 12 | 1 | 4.3Mb | 85Kb | 0.23s 13 | 4 | 14.22Mb | 364Kb | 1.38s 14 | 9 | 36.23Mb | 745Kb | 4.43s 15 | 16 | ## Import 17 | 18 | Maven 19 | 20 | 21 | me.shaohui.advancedluban 22 | library 23 | 1.3.5 24 | pom 25 | 26 | 27 | 28 | or Gradle 29 | 30 | compile 'me.shaohui.advancedluban:library:1.3.5' 31 | 32 | ## Usage 33 | 34 | 35 | ### `Listener`方式 36 | 37 | `AdvancedLuban`内部采用`Computation`线程进行图片压缩,外部调用只需设置好结果监听即可: 38 | 39 | Luban.compress(context, file) // 初始化Luban,并传入要压缩的图片 40 | .putGear(Luban.THIRD_GEAR) // 设定压缩模式,默认 THIRD_GEAR 41 | .launch(listener); // 启动压缩并设置监听 42 | 43 | ### `RxJava`方式 44 | 45 | `RxJava`调用方式同样默认`Computation`线程进行压缩, 主线程处理结果 46 | 47 | Luban.compress(context, file) 48 | .putGear(Luban.CUSTOM_GEAR) 49 | .asObservable() // 生成Observable 50 | .subscribe(successAction, errorAction) // 订阅压缩事件 51 | 52 | ### 压缩模式 53 | 54 | 55 | #### 1. CUSTOM_GEAR 56 | 57 | `AdvancedLuban`增加的个性化压缩,根据限制要求对图片进行压缩,可以限制:图片的宽度、高度以及图片文件的大小 58 | 59 | Luban.compress(context, file) 60 | .setMaxSize(500) // 限制最终图片大小(单位:Kb) 61 | .setMaxHeight(1920) // 限制图片高度 62 | .setMaxWidth(1080) // 限制图片宽度 63 | .setCompressFormat() // 自定义压缩图片格式,目前只支持:JEPG和WEBP,因为png不支持压缩图片品质 64 | .putGear(Luban.CUSTOM_GEAR) // 使用 CUSTOM_GEAR 压缩模式 65 | .asObservable() 66 | 67 | #### 2. THIRD_GEAR 68 | 69 | 主要使用`Luban`的算法,提供了类似微信的压缩效果,适用于普通压缩,没有文件大小限制以及图片的宽高限制 70 | 71 | #### 3. FIRST_GEAR 72 | 73 | `THIRD_GEAR`的简化版本,压缩之后的图片分辨率小于 1280 x 720, 文件最后小于60Kb,特殊情况下,小于原图片的1/5,适用于快速压缩,不计较最终图片品质 74 | 75 | ## 多图压缩 76 | 77 | 如果你选择的调用方式的是`Listener`方式: 78 | 79 | Luban.compress(context, fileList) // 加载多张图片 80 | .putGear(Luban.CUSTOM_GEAR) 81 | .launch(multiCompressListener); // 传入一个 OnMultiCompressListener 82 | 83 | `RxJava` 方式: 84 | 85 | Luban.compress(context, fileList) // 加载多张图片 86 | .putGear(Luban.CUSTOM_GEAR) 87 | .asListObservable() // 生成Observable 返回压缩成功的所有图片结果 88 | 89 | > 为什么不是多图并行压缩的?之前曾经尝试过多图并行压缩,但是因为在压缩的过程中,需要占用一定的内存,如果同时压缩9张5Mb左右大小的图片,很容易导致OOM,所以决定在解决OOM问题之前,多图压缩都是串行的。 90 | 91 | ## 关于OOM 92 | 93 | 如果用的是多图压缩,一定要考虑到OOM的风险,推荐大家使用 CUSTOM_GEAR, 然后自定义压缩指标,能够很大程度上降低OOM的风险,目前测试暂时没有发现过OOM的问题 94 | 95 | ## ChangeLog 96 | 97 | #### 1.3.5 98 | - 增加自定义压缩缓存目录 99 | 100 | #### 1.3.4 101 | - 更新RxJava2 102 | 103 | #### 1.3.3 104 | - 设置默认观察在主线程 105 | 106 | #### 1.3.2 107 | - 优化内存占用 108 | 109 | #### 1.3.1 110 | - 增加自定义压缩格式 111 | - 用CUSTOM_GEAR 解决了OOM的问题 112 | - 重构了大部分代码 113 | - 为了支持WebP,最低支持版本提高到14 114 | 115 | ## Issue 116 | 117 | 大家可以根据自己的需求选择不同的压缩模式以及调用方式 b( ̄▽ ̄)d !最后,欢迎大家提Issue 118 | 119 | ## TODO 120 | 121 | - 取消旋转 122 | - 增加各类compresser: JPEG,PNG,GIF,WEBP 123 | 124 | ## Thanks For 125 | - https://github.com/Curzibn/Luban 126 | - https://github.com/ReactiveX/Rxjava 127 | - https://github.com/ReactiveX/RxAndroid 128 | 129 | ## License 130 | 131 | Copyright 2016 shaohui10086 132 | 133 | Licensed under the Apache License, Version 2.0 (the "License"); 134 | you may not use this file except in compliance with the License. 135 | You may obtain a copy of the License at 136 | 137 | http://www.apache.org/licenses/LICENSE-2.0 138 | 139 | Unless required by applicable law or agreed to in writing, software 140 | distributed under the License is distributed on an "AS IS" BASIS, 141 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 142 | See the License for the specific language governing permissions and 143 | limitations under the License. 144 | 145 | 146 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.3.0' 9 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | plugins { 16 | id "com.jfrog.bintray" version "1.7" 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | jcenter() 22 | maven { url "https://jitpack.io" } 23 | } 24 | } 25 | 26 | task clean(type: Delete) { 27 | delete rootProject.buildDir 28 | } -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /example/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion '25.0.0' 6 | defaultConfig { 7 | applicationId "me.shaohui.advancedluban" 8 | minSdkVersion 15 9 | targetSdkVersion 24 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | 15 | splits { 16 | density { 17 | enable false 18 | } 19 | abi { 20 | enable false 21 | } 22 | } 23 | buildTypes { 24 | release { 25 | minifyEnabled false 26 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 27 | } 28 | } 29 | } 30 | 31 | dependencies { 32 | compile fileTree(include: ['*.jar'], dir: 'libs') 33 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 34 | exclude group: 'com.android.support', module: 'support-annotations' 35 | }) 36 | compile 'com.android.support:appcompat-v7:24.2.1' 37 | testCompile 'junit:junit:4.12' 38 | compile project(':library') 39 | compile 'com.github.lovetuzitong:MultiImageSelector:1.2' 40 | } 41 | -------------------------------------------------------------------------------- /example/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/shaohui/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /example/src/androidTest/java/me/shaohui/advancedlubanexample/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package me.shaohui.advancedlubanexample; 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 | * Instrumentation 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("me.shaohui.advancedluban", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /example/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/src/main/java/me/shaohui/advancedlubanexample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package me.shaohui.advancedlubanexample; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.RadioGroup; 11 | 12 | import java.io.File; 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | import io.reactivex.functions.Consumer; 17 | import me.nereo.multi_image_selector.MultiImageSelector; 18 | import me.nereo.multi_image_selector.MultiImageSelectorActivity; 19 | import me.shaohui.advancedluban.Luban; 20 | import me.shaohui.advancedluban.OnCompressListener; 21 | import me.shaohui.advancedluban.OnMultiCompressListener; 22 | 23 | public class MainActivity extends AppCompatActivity { 24 | 25 | private static final String TAG = "LubanExample"; 26 | 27 | private static final int REQUEST_CODE = 1; 28 | 29 | private List mFileList; 30 | 31 | private List mImageViews; 32 | 33 | private RadioGroup mMethodGroup; 34 | 35 | private RadioGroup mGearGroup; 36 | 37 | @Override 38 | protected void onCreate(Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | setContentView(R.layout.activity_main); 41 | 42 | mFileList = new ArrayList<>(); 43 | 44 | mImageViews = new ArrayList<>(); 45 | mImageViews.add((ImageView) findViewById(R.id.image_1)); 46 | mImageViews.add((ImageView) findViewById(R.id.image_2)); 47 | mImageViews.add((ImageView) findViewById(R.id.image_3)); 48 | mImageViews.add((ImageView) findViewById(R.id.image_4)); 49 | mImageViews.add((ImageView) findViewById(R.id.image_5)); 50 | mImageViews.add((ImageView) findViewById(R.id.image_6)); 51 | mImageViews.add((ImageView) findViewById(R.id.image_7)); 52 | mImageViews.add((ImageView) findViewById(R.id.image_8)); 53 | mImageViews.add((ImageView) findViewById(R.id.image_9)); 54 | 55 | mMethodGroup = (RadioGroup) findViewById(R.id.method_group); 56 | mGearGroup = (RadioGroup) findViewById(R.id.gear_group); 57 | 58 | findViewById(R.id.select_image).setOnClickListener(new View.OnClickListener() { 59 | @Override 60 | public void onClick(View v) { 61 | MultiImageSelector.create().start(MainActivity.this, REQUEST_CODE); 62 | } 63 | }); 64 | findViewById(R.id.compress_image).setOnClickListener(new View.OnClickListener() { 65 | @Override 66 | public void onClick(View v) { 67 | compressImage(); 68 | } 69 | }); 70 | } 71 | 72 | private void compressImage() { 73 | int gear; 74 | switch (mGearGroup.getCheckedRadioButtonId()) { 75 | case R.id.custom_gear: 76 | gear = Luban.THIRD_GEAR; 77 | break; 78 | case R.id.third_gear: 79 | gear = Luban.THIRD_GEAR; 80 | break; 81 | case R.id.first_gear: 82 | gear = Luban.FIRST_GEAR; 83 | break; 84 | default: 85 | gear = Luban.THIRD_GEAR; 86 | } 87 | switch (mMethodGroup.getCheckedRadioButtonId()) { 88 | case R.id.method_listener: 89 | if (mFileList.size() == 1) { 90 | compressSingleListener(gear); 91 | } else { 92 | compressMultiListener(gear); 93 | } 94 | break; 95 | case R.id.method_rxjava: 96 | if (mFileList.size() == 1) { 97 | compressSingleRxJava(gear); 98 | } else { 99 | compressMultiRxJava(gear); 100 | } 101 | break; 102 | default: 103 | } 104 | } 105 | 106 | 107 | private void compressSingleRxJava(int gear) { 108 | if (mFileList.isEmpty()) { 109 | return; 110 | } 111 | 112 | Luban.compress(mFileList.get(0), getFilesDir()) 113 | .putGear(gear) 114 | .asObservable() 115 | .subscribe(new Consumer() { 116 | @Override 117 | public void accept(File file) throws Exception { 118 | Log.i("TAG", file.getAbsolutePath()); 119 | mImageViews.get(0).setImageURI(Uri.fromFile(file)); 120 | } 121 | }, new Consumer() { 122 | @Override 123 | public void accept(Throwable throwable) throws Exception { 124 | throwable.printStackTrace(); 125 | } 126 | }); 127 | } 128 | 129 | private void compressMultiRxJava(int gear) { 130 | if (mFileList.isEmpty()) { 131 | return; 132 | } 133 | Luban.compress(this, mFileList) 134 | .putGear(gear) 135 | .asListObservable() 136 | .subscribe(new Consumer>() { 137 | @Override 138 | public void accept(List files) throws Exception { 139 | int size = files.size(); 140 | while (size-- > 0) { 141 | mImageViews.get(size).setImageURI(Uri.fromFile(files.get(size))); 142 | } 143 | } 144 | }, new Consumer() { 145 | @Override 146 | public void accept(Throwable throwable) throws Exception { 147 | throwable.printStackTrace(); 148 | } 149 | }); 150 | } 151 | 152 | private void compressSingleListener(int gear) { 153 | if (mFileList.isEmpty()) { 154 | return; 155 | } 156 | Luban.compress(mFileList.get(0), getFilesDir()) 157 | .putGear(gear) 158 | .launch(new OnCompressListener() { 159 | @Override 160 | public void onStart() { 161 | Log.i(TAG, "start"); 162 | } 163 | 164 | @Override 165 | public void onSuccess(File file) { 166 | Log.i("TAG", file.getAbsolutePath()); 167 | mImageViews.get(0).setImageURI(Uri.fromFile(file)); 168 | } 169 | 170 | @Override 171 | public void onError(Throwable e) { 172 | e.printStackTrace(); 173 | } 174 | }); 175 | } 176 | 177 | private void compressMultiListener(int gear) { 178 | if (mFileList.isEmpty()) { 179 | return; 180 | } 181 | Luban.compress(this, mFileList) 182 | .putGear(gear) 183 | .launch(new OnMultiCompressListener() { 184 | @Override 185 | public void onStart() { 186 | Log.i(TAG, "start"); 187 | } 188 | 189 | @Override 190 | public void onSuccess(List fileList) { 191 | int size = fileList.size(); 192 | while (size-- > 0) { 193 | mImageViews.get(size).setImageURI(Uri.fromFile(fileList.get(size))); 194 | } 195 | } 196 | 197 | @Override 198 | public void onError(Throwable e) { 199 | e.printStackTrace(); 200 | } 201 | }); 202 | } 203 | 204 | @Override 205 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 206 | if (requestCode == REQUEST_CODE && data != null) { 207 | mFileList.clear(); 208 | List path = data 209 | .getStringArrayListExtra(MultiImageSelectorActivity.EXTRA_RESULT); 210 | for (String str : path) { 211 | mFileList.add(new File(str)); 212 | } 213 | } 214 | 215 | super.onActivityResult(requestCode, resultCode, data); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /example/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 21 | 26 | 32 | 37 | 38 | 39 | 43 | 48 | 54 | 59 | 64 | 65 |