├── .gitignore
├── .idea
├── codeStyles
│ └── Project.xml
├── gradle.xml
├── markdown-navigator.xml
├── markdown-navigator
│ └── profiles_settings.xml
├── misc.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── androidlibrary
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── wanglei
│ │ └── androidlibrary
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── wanglei
│ └── androidlibrary
│ └── ExampleUnitTest.java
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── wanglei
│ │ └── imageoptimization
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── wanglei
│ │ │ └── imageoptimization
│ │ │ └── MainActivity.java
│ └── res
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-hdpi
│ │ ├── cdc.PNG
│ │ ├── dewdw.jpeg
│ │ ├── g.9.png
│ │ ├── h.png
│ │ ├── i.JPEG
│ │ ├── j.JPG
│ │ ├── k.png
│ │ ├── qw.jpeg
│ │ ├── wece.jpg
│ │ └── wew.jpeg
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── wanglei
│ └── imageoptimization
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── imageafter
├── h.png
├── h_lossless.png
├── h_lossy.png
├── h_webp.webp
├── h_webp_lossless.webp
├── log.jpg
├── tasks.jpg
├── wece.jpg
├── wece_lossy.jpg
└── wece_webp.webp
├── optimization
├── .gitignore
├── build.gradle
├── src
│ └── main
│ │ ├── groovy
│ │ └── com
│ │ │ └── wanglei
│ │ │ └── optimizer
│ │ │ ├── ImageOptimizationConstants.groovy
│ │ │ ├── ImageOptimizationExtensions.groovy
│ │ │ ├── ImageOptimizationPlugin.groovy
│ │ │ ├── ImageOptimizationTask.groovy
│ │ │ ├── ImageOptimizationUtils.groovy
│ │ │ ├── compressjpg
│ │ │ ├── AbstractCompressJpg.groovy
│ │ │ ├── LosslessCompressJpg.groovy
│ │ │ ├── LossyCompressJpg.groovy
│ │ │ ├── factory
│ │ │ │ └── CompressJpgFactory.groovy
│ │ │ └── inter
│ │ │ │ └── ICompressJpg.groovy
│ │ │ ├── compresspng
│ │ │ ├── AbstractCompressPng.groovy
│ │ │ ├── LosslessCompressPng.groovy
│ │ │ ├── LossyCompressPng.groovy
│ │ │ ├── factory
│ │ │ │ └── CompressPngFactory.groovy
│ │ │ └── inter
│ │ │ │ └── ICompressPng.groovy
│ │ │ └── convertwebp
│ │ │ ├── AbstractConvertWebp.groovy
│ │ │ ├── LosslessConvertWebp.groovy
│ │ │ ├── LossyConvertWebp.groovy
│ │ │ ├── factory
│ │ │ └── ConvertWebpFactory.groovy
│ │ │ └── inter
│ │ │ └── IConvertWebp.java
│ │ └── resources
│ │ ├── META-INF
│ │ └── gradle-plugins
│ │ │ └── com.wanglei.image-optimization.properties
│ │ ├── cwebp
│ │ ├── cwebp_darwin
│ │ ├── cwebp_linux
│ │ └── cwebp_win.exe
│ │ ├── guetzli
│ │ ├── guetzli_darwin
│ │ ├── guetzli_linux
│ │ └── guetzli_win.exe
│ │ ├── pngout
│ │ ├── pngout_darwin
│ │ ├── pngout_linux
│ │ └── pngout_win.exe
│ │ └── pngquant
│ │ ├── pngquant_darwin
│ │ ├── pngquant_linux
│ │ └── pngquant_win.exe
├── upload2Jcenter.gradle
└── upload2PrivateMaven.gradle
├── orginalimage
├── cdc.PNG
├── dewdw.jpeg
├── g.9.png
├── h.png
├── i.JPEG
├── j.JPG
├── k.png
├── qw.jpeg
├── wece.jpg
└── wew.jpeg
├── settings.gradle
└── updateLog.md
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/markdown-navigator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/.idea/markdown-navigator/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ImageOptimization
2 |
3 | 安卓图片优化插件:能有效减少apk安装包大小,支持png/jpg转为webp,支持png图片有损无损压缩,支持jpg有损压缩
4 |
5 | ### 支持的os
6 |
7 | `macOS`、`windows10`上已经测试通过,linux上暂时没测试。
8 |
9 | ### 引入ImageOptimization
10 |
11 | 在Project的build.gradle文件中:
12 |
13 | ```
14 | buildscript {
15 | repositories {
16 | jcenter()
17 | }
18 | dependencies {
19 | ...
20 | classpath 'com.wanglei.image-optimization:optimization:2.0'
21 | }
22 | }
23 | ```
24 |
25 | 在你想要优化的module的build.gradle文件中引入插件: 如在多个module使用则每个module都要引入插件
26 |
27 | `apply plugin:'com.wanglei.image-optimization'`
28 |
29 | 同步之后会生成如下任务:双击执行任务即可
30 |
31 | 
32 |
33 | ### 任务生成规则
34 |
35 | imageOptimization_module名字_variant名字
36 |
37 | ### 配置项
38 |
39 | 在module的build.gradle文件中添加配置选项,配置插件优化的策略以及参数:
40 |
41 | ```
42 | ImageOptimization{
43 | pluginStrategy = "compress"
44 | convertWebpQuality = 80
45 | jpegCompressQuality = 90
46 | appIconName = "ic_launcher"
47 | appIconRoundName = "ic_launcher_round"
48 | convertWebpType = "lossy"
49 | compressPngType = "lossless"
50 | pngCompressQuality = 79
51 | filter{
52 | filterDirs = ["mipmap-hdpi","mipmap-xhdpi","mipmap-xxhdpi"]
53 | filterImageNames = ["cdc.PNG","wew.jpeg","c.png"]
54 | }
55 | }
56 | ```
57 | ImageOptimization支持多项参数配置,灵活度高,可根据项目需要自己配置参数,可配置优先转为webp不能转换的在进行图片的压缩,同样你也可以配置只进行图片的压缩而不转为webp
58 |
59 | ### 配置项参数说明
60 |
61 | | 参数 | 是否必须 |参数配置 |参数说明 |
62 | |--|--|--|--|
63 | | pluginStrategy | 否 | 可配置"webp"或者"compress" | 插件运行策略参数:如配置为"webp"则会将图片优先转为webp格式,如果不能转换或者转换失败或转换为图片更大则进行图片的压缩,如配置为"compress"则只进行图片的压缩不会转为webp,此参数如不配置默认为"compress" |
64 | | convertWebpType | 否 | 可配置"lossy"或者"lossless" | webp转换类型参数:"lossy"转为webp采用有损转换模式,"lossless"转为webp采用无损模式,此参数默认为"lossy" |
65 | | compressPngType | 否 | 可配置"lossy"或者"lossless" | png图片压缩类型参数:"lossy"为压缩png采用有损压缩模式,"lossless"为压缩png采用无损压缩模式,此参数默认为"lossy" |
66 | | pngCompressQuality | 否 | 可配置范围为[0,100] | png图片压缩质量参数:默认为80,建议使用默认即可,此参数为compressPngType为"lossy"时起作用,也就是有损压缩才起作用 |
67 | | convertWebpQuality | 否 | 可配置范围为[0,100] | 图片转为webp的质量参数:默认为75,此参数为谷歌建议的参数,建议不要更改,转换webp有损模式下此参数才起作用 |
68 | | jpegCompressQuality | 否 | 可配置范围为[84,100] | jpg图片压缩质量参数:默认为84 |
69 | | appIconRoundName | 否 | 项目app圆形启动图标的名字,不包括图片扩展名 | 如圆形启动图标为:icon_round.png,这里配置为icon_round |
70 | | appIconName | 是 | 项目app启动图标的名字,不包括图片扩展名 | 如启动图标为:icon.png,这里配置为icon |
71 | | filterDirs | 否 | 不需要压缩或转换的图片目录名 | 如 filterDirs = ["mipmap-hdpi","mipmap-xhdpi"] ,mipmap-hdpi与mipmap-xhdpi目录下图片资源保持原样|
72 | | filterImageNames | 否 | 不需要压缩或转换的图片的名字 | 如 filterImageNames = ["cdc.PNG","wew.jpeg"] ,cdc.PNG与wew.jpeg图片均保持原样,这里要配置完整的图片名包括扩展名并且区分大小写|
73 |
74 | ### 图片压缩效果对比
75 |
76 | #### PNG图片
77 | | 原图 | 有损转为webp | 无损转为webp | lossy有损压缩 | lossless无损压缩 |
78 | |--|--|--|--|--|
79 | |  |  |  |  |  |
80 | | 50.05k | 15.28k | 30.30k | 13.64k | 42.21k |
81 |
82 | #### jpg图片
83 | | 原图 | 有损转为webp | lossy有损压缩 |
84 | |--|--|--|
85 | |  |  |  |
86 | | 7.91k | 2.82k | 5.17k |
87 |
88 | #### 由于GitHub有时不能正常显示webp图片,上图webp图片可能无法正常显示,可到imageafter文件夹中查看对应图片
89 |
90 | ### 额外说明
91 |
92 | #### 插件运行的时候会有相应信息打印出:
93 |
94 | 
95 |
96 | #### 安卓对webp图片的支持
97 |
98 | 安卓不同sdk版本对webp的支持有所不同,具体如下:
99 |
100 | sdk<14:不支持webp格式图片
101 | 14<= sdk <18:支持webp格式图片,但是不支持有透明通道的 webp格式图片
102 | sdk >=18:有透明通道的webp图片也支持
103 |
104 | 此外如果想以无损方式将png/jpg图片转为webp,需要的sdk版本最小为18。
105 |
106 | **ImageOptimization对以上情况都做了适配,你只需放心使用即可**
107 |
108 | #### .9.png图片的处理
109 |
110 | ImageOptimization插件对.9.png图片不做任何处理,既不转换也不压缩保持原样。
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/androidlibrary/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/androidlibrary/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 28
5 |
6 | defaultConfig {
7 | minSdkVersion 14
8 | targetSdkVersion 28
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 |
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 |
21 | }
22 |
23 | dependencies {
24 | implementation fileTree(dir: 'libs', include: ['*.jar'])
25 | implementation 'com.android.support:appcompat-v7:28.0.0'
26 | testImplementation 'junit:junit:4.12'
27 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
28 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
29 | }
30 | //上传的库的名字,是和你Module的名字是一样的!!!所以你的Module叫什么,
31 | // 你的gradle依赖路径就是: groupId:moduleName:publishVersion
32 | //module是android library如下配置上传jcenter,
33 | // 先执行other分组中的instal任务生成pom文件,在执行publishing分组中的bintrayUpload任务上传
34 | group "com.wanglei.image-optimization"
35 | version "1.0"
36 |
37 |
38 | //源代码打包任务
39 | task sourcesJar(type :Jar){
40 | classifier 'sources' //分类器 区分其他jar包
41 | from android.sourceSets.main.java.srcDirs
42 | }
43 | //创建文档生成任务
44 | task javadoc(type:Javadoc){
45 | source = android.sourceSets.main.java.srcDirs
46 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
47 | options.encoding "UTF-8"
48 | options.charSet 'UTF-8'
49 | failOnError false
50 | }
51 |
52 | task docJar(type :Jar,dependsOn:javadoc){
53 | classifier 'doc' //分类器 区分其他jar包
54 | from javadoc.destinationDir
55 | }
56 | //配置 工程工件 jar产出的配置
57 | artifacts{
58 | archives sourcesJar
59 | archives docJar
60 | }
61 |
62 |
63 | buildscript {
64 | repositories {
65 | jcenter()
66 | }
67 | dependencies {
68 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
69 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
70 | }
71 | }
72 | apply plugin: 'com.jfrog.bintray'
73 | apply plugin: 'com.github.dcendents.android-maven'
74 |
75 | bintray {
76 | user = 'xxxx'
77 | key = 'apiKey'
78 | configurations = ['archives']
79 | pkg {
80 | repo = 'AndroidImageOptimization' //仓库名
81 | name = 'optimization' //项目名
82 | licenses = ['Apache-2.0']
83 | vcsUrl = 'https://github.com/MISAYAWANGLEI/ImageOptimization.git'
84 | version {
85 | desc = 'android image optimizer plugin'
86 | released = new Date()
87 | vcsTag = '1.0'
88 | }
89 | }
90 |
91 | }
92 |
93 |
94 | install {
95 | repositories.mavenInstaller {
96 | pom.project {
97 | licenses {
98 | license {
99 | name 'The Apache Software License, Version 2.0'
100 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
101 | distribution 'repo'
102 | }
103 | }
104 | developers {
105 | developer {
106 | id 'misaya'
107 | name 'wanglei'
108 | email 'wanglei.pado@gmail.com'
109 | }
110 | }
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/androidlibrary/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 |
--------------------------------------------------------------------------------
/androidlibrary/src/androidTest/java/com/wanglei/androidlibrary/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.wanglei.androidlibrary;
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() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.wanglei.androidlibrary.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/androidlibrary/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/androidlibrary/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | androidLibrary
3 |
4 |
--------------------------------------------------------------------------------
/androidlibrary/src/test/java/com/wanglei/androidlibrary/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.wanglei.androidlibrary;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin:'com.wanglei.image-optimization'
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "com.wanglei.imageoptimization"
7 | minSdkVersion 14
8 | targetSdkVersion 28
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | ImageOptimization{
22 | pluginStrategy = "compress"
23 | convertWebpQuality = 80
24 | jpegCompressQuality = 90
25 | appIconName = "ic_launcher"
26 | appIconRoundName = "ic_launcher_round"
27 | convertWebpType = "lossy"
28 | compressPngType = "lossless"
29 | pngCompressQuality = 80
30 | filter{
31 | //filterDirs = ["mipmap-hdpi","mipmap-xhdpi","mipmap-xxhdpi"]
32 | //filterImageNames = ["cdc.PNG","wew.jpeg","c.png"]
33 | }
34 | }
35 |
36 | dependencies {
37 | implementation fileTree(dir: 'libs', include: ['*.jar'])
38 | implementation 'com.android.support:appcompat-v7:28.0.0'
39 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
40 | testImplementation 'junit:junit:4.12'
41 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
42 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
43 | }
44 |
--------------------------------------------------------------------------------
/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/wanglei/imageoptimization/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.wanglei.imageoptimization;
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() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.wanglei.imageoptimization", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wanglei/imageoptimization/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.wanglei.imageoptimization;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 |
6 | public class MainActivity extends AppCompatActivity {
7 |
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | setContentView(R.layout.activity_main);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/cdc.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/app/src/main/res/mipmap-hdpi/cdc.PNG
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/dewdw.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/app/src/main/res/mipmap-hdpi/dewdw.jpeg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/g.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/app/src/main/res/mipmap-hdpi/g.9.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/app/src/main/res/mipmap-hdpi/h.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/i.JPEG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/app/src/main/res/mipmap-hdpi/i.JPEG
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/j.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/app/src/main/res/mipmap-hdpi/j.JPG
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/k.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/app/src/main/res/mipmap-hdpi/k.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/qw.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/app/src/main/res/mipmap-hdpi/qw.jpeg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/wece.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/app/src/main/res/mipmap-hdpi/wece.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/wew.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/app/src/main/res/mipmap-hdpi/wew.jpeg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ImageOptimization
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/wanglei/imageoptimization/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.wanglei.imageoptimization;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/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 | google()
6 | jcenter()
7 | //mavenLocal()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.3.1'
11 | classpath 'com.wanglei.image-optimization:optimization:2.0'
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 |
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
15 |
16 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Feb 20 22:19:29 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/imageafter/h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/imageafter/h.png
--------------------------------------------------------------------------------
/imageafter/h_lossless.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/imageafter/h_lossless.png
--------------------------------------------------------------------------------
/imageafter/h_lossy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/imageafter/h_lossy.png
--------------------------------------------------------------------------------
/imageafter/h_webp.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/imageafter/h_webp.webp
--------------------------------------------------------------------------------
/imageafter/h_webp_lossless.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/imageafter/h_webp_lossless.webp
--------------------------------------------------------------------------------
/imageafter/log.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/imageafter/log.jpg
--------------------------------------------------------------------------------
/imageafter/tasks.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/imageafter/tasks.jpg
--------------------------------------------------------------------------------
/imageafter/wece.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/imageafter/wece.jpg
--------------------------------------------------------------------------------
/imageafter/wece_lossy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/imageafter/wece_lossy.jpg
--------------------------------------------------------------------------------
/imageafter/wece_webp.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/imageafter/wece_webp.webp
--------------------------------------------------------------------------------
/optimization/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/optimization/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java-library'
2 | apply plugin: 'groovy'
3 |
4 | dependencies {
5 | compile fileTree(dir: 'libs', include: ['*.jar'])
6 | compile gradleApi()
7 | compile localGroovy()
8 | compile 'com.android.tools.build:gradle:3.3.1'
9 | }
10 |
11 | sourceCompatibility = "1.7"
12 | targetCompatibility = "1.7"
13 |
14 | apply from: 'upload2Jcenter.gradle'
15 |
16 | group "com.wanglei.image-optimization"
17 | version "2.0"
18 |
19 | //apply plugin: 'maven-publish'
20 | //
21 | ////上传本地配置
22 | //publishing{
23 | // publications{
24 | // optimizer(MavenPublication){
25 | // from components.java
26 | // artifactId = "optimization"
27 | // }
28 | // }
29 | //}
30 |
31 | //源代码打包任务
32 | task sourcesJar(type :Jar){
33 | baseName 'optimization'
34 | classifier 'sources'
35 | from sourceSets.main.allSource
36 | }
37 | //生成文档任务
38 | task docJar(type :Jar,dependsOn:[javadoc,groovydoc]){
39 | baseName 'optimization'
40 | classifier 'doc'
41 | from javadoc.destinationDir,groovydoc.destinationDir
42 | }
43 | //配置 工程工件 jar产出的配置
44 | artifacts{
45 | archives sourcesJar
46 | archives docJar
47 | }
48 |
49 | buildscript {
50 | repositories {
51 | jcenter()
52 | }
53 | dependencies {
54 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
55 | }
56 | }
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/ImageOptimizationConstants.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer
2 |
3 | class ImageOptimizationConstants {
4 |
5 | def static final PNG = ".png"
6 | def static final PNG9 = ".9.png"
7 | def static final JPG = ".jpg"
8 | def static final JPEG = ".jpeg"
9 | def static final TOOLSDIR = "image_tools"
10 | def static final DRAWABLE_FOLDER = "drawable"
11 | def static final MIPMAP_FOLDER = "mipmap"
12 | def static final IMG_EXT_NAME = "ImageOptimization"
13 | def static final IMG_FILTER_EXT_NAME = "filter"
14 | //
15 | def static final defaultJpegCompressQuality = 84//[84,100]
16 | def static final defaultConvertWebpQuality = 75//[0,100]
17 | def static final defaultCompressPngQuality = 80//[0,100]
18 | //转换webp的工具类型
19 | def static final LOSSY = "lossy"//默认,有损模式,可指定压缩质量
20 | def static final LOSSLESS = "lossless"//无损模式
21 |
22 | def static final CWEBP_TOOL_NAME = "cwebp"
23 | def static final LOSSY_PNG_TOOL_NAME = "pngquant"
24 | def static final LOSSLESS_PNG_TOOL_NAME = "pngout"
25 | def static final JPG_TOOL_NAME = "guetzli"
26 |
27 | //插件策略
28 | def static final STRATEGY_WEBP = "webp"//优先转换为webp,不能转换的进行压缩
29 | def static final STRATEGY_ONLIY_COMPRESS = "compress"//只进行压缩,不转为webp
30 |
31 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/ImageOptimizationExtensions.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer
2 |
3 | class ImageOptimizationExtensions{
4 |
5 | def jpegCompressQuality = ImageOptimizationConstants.defaultJpegCompressQuality
6 | //有损模式指定才有意义,无损模式用不到这个参数
7 | def convertWebpQuality = ImageOptimizationConstants.defaultConvertWebpQuality
8 | def pngCompressQuality = ImageOptimizationConstants.defaultCompressPngQuality
9 | String appIconName //启动图标的图片名字
10 | String appIconRoundName //圆形启动图标的图片名字
11 | def convertWebpType = ImageOptimizationConstants.LOSSY //转换webp的模式,默认有损
12 | def compressPngType = ImageOptimizationConstants.LOSSY //压缩png的模式,默认有损
13 | def pluginStrategy = ImageOptimizationConstants.STRATEGY_ONLIY_COMPRESS //默认插件策略为只压缩图片
14 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/ImageOptimizationPlugin.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer
2 |
3 | import com.android.build.gradle.AppPlugin
4 | import com.android.build.gradle.LibraryPlugin
5 | import com.android.build.gradle.api.BaseVariant
6 | import com.android.sdklib.repository.targets.PlatformTarget
7 | import org.gradle.api.DomainObjectCollection
8 | import org.gradle.api.GradleException
9 | import org.gradle.api.Plugin
10 | import org.gradle.api.Project
11 |
12 | class ImageOptimizationPlugin implements Plugin {
13 |
14 | @Override
15 | void apply(Project project) {
16 | if (project.plugins.hasPlugin(AppPlugin)) {
17 | startApply(project, (DomainObjectCollection) project.android.applicationVariants)
18 | } else if (project.plugins.hasPlugin(LibraryPlugin)) {
19 | startApply(project, (DomainObjectCollection) project.android.libraryVariants)
20 | } else {
21 | throw new GradleException("image-optimization plugin should be used in android module")
22 | }
23 | }
24 |
25 | static void startApply(Project project, DomainObjectCollection variants) {
26 | //创建扩展,外部可以配置的参数
27 | def imgExt = project.extensions.create(ImageOptimizationConstants.IMG_EXT_NAME, ImageOptimizationExtensions)
28 | def imgFilterExt = project.ImageOptimization.extensions.create(ImageOptimizationConstants.IMG_FILTER_EXT_NAME, ImageOptimizationFilterExtensions)
29 |
30 | project.afterEvaluate {
31 | project.logger.error "过滤图片文件夹目录名:${imgFilterExt.filterDirs}"
32 | variants.all {
33 | BaseVariant variant ->
34 | //存放图片文件夹集合
35 | List imgDirs = []
36 | variant.sourceSets.each { sourceSet ->
37 | sourceSet.resDirectories.each { res ->
38 | if (res.exists()) {
39 | res.eachDir {
40 | //是图片目录
41 | if (it.directory && ImageOptimizationUtils.isImageFolder(it)) {
42 | //过滤用户配置的满足条件的图片
43 | if (imgFilterExt.filterDirs == null ||
44 | (imgFilterExt.filterDirs != null
45 | && !imgFilterExt.filterDirs.contains(it.name))){
46 | imgDirs << it
47 | }
48 | }
49 | }
50 | }
51 | }
52 | }
53 |
54 | if (!imgDirs.empty) {
55 | def task = project.tasks.create("imageOptimization_${project.name.capitalize()}_${variant.name.capitalize()}", ImageOptimizationTask) {
56 | // //获取manifest.xml文件
57 | // def variantOutput = variant.outputs.first()
58 | // if (variantOutput.processManifest.properties['manifestOutputFile'] != null) {
59 | // manifestFile = variantOutput.processManifest.manifestOutputFile
60 | // } else if (variantOutput.processResources.properties['manifestFile'] != null) {
61 | // manifestFile = variantOutput.processResources.manifestFile
62 | // }
63 | //获取minSdk
64 | //variant.mergedFlavor.minSdkVersion.apiLevel
65 | //variant.variantData.variantConfiguration
66 | minSdk = variant.mergeResourcesProvider.get().minSdk
67 | //图片文件夹集合
68 | res = imgDirs
69 | //启动图标名字
70 | appIconName = imgExt.appIconName
71 | appIconRoundName = imgExt.appIconRoundName
72 | //
73 | convertWebpType = imgExt.convertWebpType
74 | compressPngType = imgExt.compressPngType
75 | //配置参数
76 | jpegCompressQuality = imgExt.jpegCompressQuality
77 | convertWebpQuality = imgExt.convertWebpQuality
78 | pngCompressQuality = imgExt.pngCompressQuality
79 | //插件策略,默认只压缩
80 | pluginStrategy = imgExt.pluginStrategy
81 | //
82 | filterImageNames = imgFilterExt.filterImageNames
83 | }
84 | //task.dependsOn variant.outputs.first().processManifest
85 | }
86 | }
87 | }
88 | }
89 |
90 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/ImageOptimizationTask.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer
2 |
3 | import com.wanglei.optimizer.compressjpg.factory.CompressJpgFactory
4 | import com.wanglei.optimizer.compressjpg.inter.ICompressJpg
5 | import com.wanglei.optimizer.compresspng.factory.CompressPngFactory
6 | import com.wanglei.optimizer.compresspng.inter.ICompressPng
7 | import com.wanglei.optimizer.convertwebp.factory.ConvertWebpFactory
8 | import com.wanglei.optimizer.convertwebp.inter.IConvertWebp
9 | import org.gradle.api.DefaultTask
10 | import org.gradle.api.tasks.Input
11 | import org.gradle.api.tasks.Optional
12 | import org.gradle.api.tasks.TaskAction
13 |
14 | class ImageOptimizationTask extends DefaultTask{
15 |
16 | def webPTool
17 | def pngTool
18 | def jpgTool
19 |
20 | // @Input
21 | // def manifestFile
22 |
23 | @Input
24 | def minSdk
25 |
26 | @Input
27 | List res
28 |
29 | @Input
30 | @Optional
31 | def jpegCompressQuality = ImageOptimizationConstants.defaultJpegCompressQuality
32 |
33 | @Input
34 | @Optional
35 | def convertWebpQuality = ImageOptimizationConstants.defaultConvertWebpQuality
36 |
37 | @Input
38 | @Optional
39 | def pngCompressQuality = ImageOptimizationConstants.defaultCompressPngQuality
40 |
41 | @Input
42 | String appIconName
43 |
44 | @Input
45 | @Optional
46 | String appIconRoundName
47 |
48 | @Input
49 | @Optional
50 | String convertWebpType = ImageOptimizationConstants.LOSSY
51 |
52 | @Input
53 | @Optional
54 | String compressPngType = ImageOptimizationConstants.LOSSY
55 |
56 | @Input
57 | @Optional
58 | String pluginStrategy = ImageOptimizationConstants.STRATEGY_ONLIY_COMPRESS
59 |
60 | @Input
61 | @Optional
62 | def filterImageNames = null //需要过滤的图片名字集合
63 |
64 | //jpg的压缩目前不支持外部设置,统一有损压缩
65 | String compressJpgType = ImageOptimizationConstants.LOSSY
66 |
67 | //
68 | IConvertWebp convertWebpTool
69 | ICompressPng compressPngTool
70 | ICompressJpg compressJpgTool
71 |
72 | ImageOptimizationTask(){
73 | group = "WLImageOptimization"
74 | }
75 |
76 | @TaskAction
77 | def run(){
78 | //检查参数是否合法
79 | ImageOptimizationUtils.checkOptionalParams(jpegCompressQuality,convertWebpQuality,appIconName,convertWebpType,minSdk,compressPngType,pluginStrategy,pngCompressQuality)
80 | //拷贝工具
81 | webPTool = ImageOptimizationUtils.copyTool(project,ImageOptimizationConstants.CWEBP_TOOL_NAME)
82 | if (compressPngType.equalsIgnoreCase(ImageOptimizationConstants.LOSSY)){
83 | pngTool = ImageOptimizationUtils.copyTool(project,ImageOptimizationConstants.LOSSY_PNG_TOOL_NAME)
84 | }else {
85 | pngTool = ImageOptimizationUtils.copyTool(project,ImageOptimizationConstants.LOSSLESS_PNG_TOOL_NAME)
86 | }
87 | jpgTool = ImageOptimizationUtils.copyTool(project,ImageOptimizationConstants.JPG_TOOL_NAME)
88 | //获取对应工具
89 | convertWebpTool = ConvertWebpFactory.getConvertWebpTool(convertWebpType)
90 | compressPngTool = CompressPngFactory.getCompressPngTool(compressPngType)
91 | compressJpgTool = CompressJpgFactory.getCompressJpgTool(compressJpgType)
92 | //
93 | project.logger.error "=========WL ImageOptimization Start=========="
94 | project.logger.error "pluginStrategy : $pluginStrategy"
95 | project.logger.error "jpegCompressQuality : $jpegCompressQuality"
96 | project.logger.error "pngCompressQuality : $pngCompressQuality"
97 | project.logger.error "convertWebpQuality : $convertWebpQuality"
98 | project.logger.error "webp tool : $webPTool"
99 | project.logger.error "png tool : $pngTool"
100 | project.logger.error "jpg tool : $jpgTool"
101 | project.logger.error "mini sdk : $minSdk"
102 | project.logger.error "convertWebpType : $convertWebpType"
103 | project.logger.error "compressPngType : $compressPngType"
104 | project.logger.error "需要过滤的图片:$filterImageNames"
105 | res.each {
106 | project.logger.error "image dir : $it.absolutePath"
107 | }
108 | // project.logger.error "manifestFile : $manifestFile.absolutePath"
109 | project.logger.error "=========1,parse Manifest.xml=========="
110 | //解析Manifest.xml获取启动图标,启动图标不转为webp
111 | // def ns = new Namespace("http://schemas.android.com/apk/res/android","android")
112 | // def node = new XmlParser().parse(manifestFile)
113 | // Node application = node.application[0]
114 | // icon = application.attributes()[ns.icon]//@mipmap/ic_launcher
115 | // roundIcon = application.attributes()[ns.roundIcon]//@mipmap/ic_launcher_round
116 | // icon = icon.substring(icon.lastIndexOf("/")+1,icon.length())//ic_launcher
117 | // roundIcon = roundIcon.substring(roundIcon.lastIndexOf("/")+1,roundIcon.length())//ic_launcher_round
118 |
119 | project.logger.error "launcher Icon Name:$appIconName"
120 | project.logger.error "launcher Round Icon Name :$appIconRoundName"
121 |
122 | project.logger.error "=========2, parse resDir=========="
123 | //存放png图片
124 | def pngs = []
125 | //存放jpg图片
126 | def jpgs = []
127 | //遍历文件夹
128 | res.each{
129 | if (ImageOptimizationUtils.isImageFolder(it)){
130 | it.eachFile {
131 | if (ImageOptimizationUtils.isJpgImage(it) && ImageOptimizationUtils.isNotLauncherIcon(it,appIconName,appIconRoundName)){
132 | if (filterImageNames == null ||
133 | (filterImageNames != null && !filterImageNames.contains(it.name))){
134 | jpgs << it
135 | }
136 | }else if(ImageOptimizationUtils.isPngImage(it) && ImageOptimizationUtils.isNotLauncherIcon(it,appIconName,appIconRoundName)){
137 | if (filterImageNames == null ||
138 | (filterImageNames != null && !filterImageNames.contains(it.name))){
139 | pngs << it
140 | }
141 | }
142 | }
143 | }
144 | }
145 |
146 | //输出全部图片信息
147 | pngs.each {
148 | project.logger.error "${it.absolutePath}"
149 | }
150 |
151 | jpgs.each {
152 | project.logger.error "${it.absolutePath}"
153 | }
154 | //这里只进行简单的判断
155 | if (pluginStrategy.equalsIgnoreCase(ImageOptimizationConstants.STRATEGY_ONLIY_COMPRESS)){
156 | project.logger.error "=========3,start compress Image=========="
157 | pngs.each {
158 | compressPng(it)
159 | }
160 | //
161 | jpgs.each {
162 | compressJpg(it)
163 | }
164 | }else {
165 | project.logger.error "=========3,start ConvertImage to Webp=========="
166 | //保存png转webp失败或者转换后图片更大的集合
167 | def pngConvertFailed = []
168 | //保存jpg转webp失败或者转换后图片更大的集合
169 | def jpgConvertFailed = []
170 | if (minSdk >= 14 && minSdk < 18){
171 | def compress = []//保存不能转换的图片,[14,18)之间有透明通道的png图片不能转为webp,18以上均可以
172 | //处理png 如果带透明度 则加入压缩集合,不能转为webp
173 | project.logger.error "=========minSdk >= 14 && minSdk < 18=========="
174 | pngs.each {
175 | if (ImageOptimizationUtils.isTransparent(it)){
176 | compress << it
177 | }else{
178 | convertWebp(it,pngConvertFailed)
179 | }
180 | }
181 | compress.each {
182 | compressPng(it)
183 | }
184 | //
185 | jpgs.each {
186 | convertWebp(it,jpgConvertFailed)
187 | }
188 | }else if(minSdk >=18){//18及以上均可转换
189 | project.logger.error "=========minSdk >=18=========="
190 | pngs.each {
191 | convertWebp(it,pngConvertFailed)
192 | }
193 | //
194 | jpgs.each {
195 | convertWebp(it,jpgConvertFailed)
196 | }
197 | }else{//小于14只能压缩操作
198 | project.logger.error "=========minSdk < 14=========="
199 | pngs.each {
200 | compressPng(it)
201 | }
202 | //
203 | jpgs.each {
204 | compressJpg(it)
205 | }
206 | }
207 | project.logger.error "=========4,start compress Failed Image=========="
208 | //输出信息
209 | pngConvertFailed.each {
210 | project.logger.error "${it.absolutePath}"
211 | }
212 |
213 | jpgConvertFailed.each {
214 | project.logger.error "${it.absolutePath}"
215 | }
216 | //转换失败的图片执行压缩操作
217 | pngConvertFailed.each {
218 | compressPng(it)
219 | }
220 |
221 | jpgConvertFailed.each {
222 | compressJpg(it)
223 | }
224 | }
225 | project.logger.error "=========WL ImageOptimization End=========="
226 | }
227 |
228 |
229 | def convertWebp(File file, def convertFailedList){
230 | convertWebpTool.convertWebp(webPTool,project,file,convertFailedList,convertWebpQuality)
231 | }
232 |
233 | def compressPng(File file){
234 | compressPngTool.compressPng(pngTool,project,file,pngCompressQuality)
235 | }
236 |
237 | def compressJpg(File file){
238 | compressJpgTool.compressJpg(jpgTool,project,file,jpegCompressQuality)
239 | }
240 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/ImageOptimizationUtils.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer
2 |
3 |
4 | import org.apache.tools.ant.taskdefs.condition.Os
5 | import org.gradle.api.GradleException
6 | import org.gradle.api.Project
7 |
8 | import javax.imageio.ImageIO
9 | import java.awt.image.BufferedImage
10 | import java.security.InvalidParameterException
11 |
12 | class ImageOptimizationUtils {
13 |
14 | /**
15 | * 判断是否是文件夹
16 | * @param file
17 | * @return
18 | */
19 | def static isImageFolder(File file) {
20 | return file.name.startsWith(ImageOptimizationConstants.DRAWABLE_FOLDER) || file.name.startsWith(ImageOptimizationConstants.MIPMAP_FOLDER)
21 | }
22 |
23 | def static isPngImage(File file) {
24 | return (file.name.endsWith(ImageOptimizationConstants.PNG) || file.name.endsWith(ImageOptimizationConstants.PNG.toUpperCase())) &&
25 | !file.name.endsWith(ImageOptimizationConstants.PNG9) && !file.name.endsWith(ImageOptimizationConstants.PNG9.toUpperCase())
26 | }
27 |
28 | def static isJpgImage(File file) {
29 | return file.name.endsWith(ImageOptimizationConstants.JPG) || file.name.endsWith(ImageOptimizationConstants.JPG.toUpperCase()) ||
30 | file.name.endsWith(ImageOptimizationConstants.JPEG) || file.name.endsWith(ImageOptimizationConstants.JPEG.toUpperCase())
31 | }
32 |
33 | /**
34 | * 判断图片是否存在透明通道
35 | */
36 | def static isTransparent(File file) {
37 | BufferedImage image = ImageIO.read(file)
38 | return image.colorModel.hasAlpha()
39 | }
40 |
41 | /**
42 | * 获取图片处理工具
43 | */
44 | def static copyTool(Project project, String name) {
45 | String toolName
46 | //获得对应平台的工具
47 | if (Os.isFamily(Os.FAMILY_MAC)) {
48 | toolName = "${name}_darwin"
49 | } else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
50 | toolName = "${name}_win.exe"
51 | } else {
52 | toolName = "${name}_linux"
53 | }
54 | def tool = "${project.buildDir}/${ImageOptimizationConstants.TOOLSDIR}/$toolName"
55 | def file = new File(tool)
56 | //resources目录下对应工具拷贝到app/build/tools/目录下
57 | if (!file.exists()) {
58 | file.parentFile.mkdirs()
59 | file.withOutputStream {
60 | def is = ImageOptimizationUtils.class.getResourceAsStream("/$name/$toolName")
61 | it << is.bytes
62 | is.close()
63 | }
64 | }
65 | if (file.exists() && file.setExecutable(true)) {
66 | return file.absolutePath
67 | }
68 | throw new GradleException("$tool :无法执行或者不存在")
69 | }
70 |
71 | def static checkOptionalParams(def defaultJpegCompressQuality, def defaultConvertWebpQuality, String appIconName, String convertWebpType, int minSdk, String compressPngType, String pluginStrategy, int pngCompressQuality) {
72 | if (defaultJpegCompressQuality < 84 || defaultJpegCompressQuality > 100) {
73 | throw new InvalidParameterException("JpegCompressQuality should be [84,100] , default value is 84 ,you set $defaultJpegCompressQuality")
74 | }
75 | if (defaultConvertWebpQuality < 0 || defaultConvertWebpQuality > 100) {
76 | throw new InvalidParameterException("ConvertWebpQuality should be [0,100] , default value is 75 ,you set $defaultConvertWebpQuality")
77 | }
78 |
79 | if (appIconName == null || appIconName.isEmpty()) {
80 | throw new InvalidParameterException("appIconName should not be empty ,you set $appIconName")
81 | }
82 |
83 | if (!convertWebpType.equalsIgnoreCase(ImageOptimizationConstants.LOSSY)
84 | && !convertWebpType.equalsIgnoreCase(ImageOptimizationConstants.LOSSLESS)) {
85 | throw new InvalidParameterException("convertWebpType error. Please use lossy or lossless, default is lossy ,you set $convertWebpType")
86 | }
87 |
88 | if (convertWebpType.equalsIgnoreCase(ImageOptimizationConstants.LOSSLESS) && minSdk < 18) {
89 | throw new InvalidParameterException("convertWebpType lossless type only support minsdk >=18 ,you set $minSdk")
90 | }
91 |
92 | if (!compressPngType.equalsIgnoreCase(ImageOptimizationConstants.LOSSY)
93 | && !compressPngType.equalsIgnoreCase(ImageOptimizationConstants.LOSSLESS)) {
94 | throw new InvalidParameterException("compressPngType error. Please use lossy or lossless, default is lossy ,you set $compressPngType")
95 | }
96 |
97 | if (!pluginStrategy.equalsIgnoreCase(ImageOptimizationConstants.STRATEGY_ONLIY_COMPRESS)
98 | && !pluginStrategy.equalsIgnoreCase(ImageOptimizationConstants.STRATEGY_WEBP)) {
99 | throw new InvalidParameterException("pluginStrategy error. Please use webp or compress, default is compress ,you set $pluginStrategy")
100 | }
101 |
102 | if (pngCompressQuality < 0 || pngCompressQuality > 100){
103 | throw new InvalidParameterException("pngCompressQuality should be [0,100] , default value is 80 ,you set $pngCompressQuality")
104 | }
105 | }
106 |
107 | //排除启动图标
108 | def static isNotLauncherIcon(File file, String appIconName, String appIconRoundName) {
109 | return (appIconRoundName == null || appIconRoundName.isEmpty()) ?
110 | (file.name != "${appIconName}.png")
111 | : (file.name != "${appIconName}.png" && file.name != "${appIconRoundName}.png")
112 | }
113 |
114 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/compressjpg/AbstractCompressJpg.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer.compressjpg
2 |
3 | import com.wanglei.optimizer.compressjpg.inter.ICompressJpg
4 |
5 | abstract class AbstractCompressJpg implements ICompressJpg{
6 |
7 | @Override
8 | void compressJpg(Object jpgTool, Object project, Object file, Object compressJpgQuality) {
9 | long originalSize = file.length()
10 | def out = new File(file.parent,"temp-${file.name}")
11 | def result =commandLine(jpgTool,file,out,compressJpgQuality) .execute()
12 | result.waitForProcessOutput()
13 | if (result.exitValue() == 0){
14 | long compressedSize = out.length()
15 | float rate = 1.0f * (originalSize - compressedSize) / originalSize * 100
16 | file.delete()
17 | out.renameTo(file)
18 | project.logger.error "compress jpg image ${file.absolutePath} success from ${originalSize}B down to ${compressedSize}B, ${rate}% saved!"
19 | }else{
20 | project.logger.error "compress jpg image ${file.absolutePath} error : ${result.err.text}"
21 | }
22 | }
23 |
24 | abstract String commandLine(jpgTool,inFile,outFile,compressJpgQuality)
25 |
26 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/compressjpg/LosslessCompressJpg.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer.compressjpg
2 |
3 | class LosslessCompressJpg extends AbstractCompressJpg{
4 |
5 |
6 | @Override
7 | String commandLine(Object jpgTool, Object file, Object out, Object jpegCompressQuality) {
8 | return null
9 | }
10 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/compressjpg/LossyCompressJpg.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer.compressjpg
2 |
3 | class LossyCompressJpg extends AbstractCompressJpg{
4 |
5 |
6 | @Override
7 | String commandLine(Object jpgTool, Object file, Object out, Object jpegCompressQuality) {
8 | return "${jpgTool} --quality ${jpegCompressQuality} ${file.absolutePath} ${out.absolutePath}"
9 | }
10 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/compressjpg/factory/CompressJpgFactory.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer.compressjpg.factory
2 |
3 | import com.wanglei.optimizer.ImageOptimizationConstants
4 | import com.wanglei.optimizer.compressjpg.LosslessCompressJpg
5 | import com.wanglei.optimizer.compressjpg.LossyCompressJpg
6 | import com.wanglei.optimizer.compressjpg.inter.ICompressJpg
7 |
8 | class CompressJpgFactory {
9 |
10 | private CompressJpgFactory() {}
11 |
12 | static ICompressJpg getCompressJpgTool(String type) {
13 | if (ImageOptimizationConstants.LOSSY .equalsIgnoreCase(type)) {
14 | return new LossyCompressJpg()
15 | } else if (ImageOptimizationConstants.LOSSLESS .equalsIgnoreCase(type)) {
16 | return new LosslessCompressJpg()
17 | } else {
18 | throw new IllegalArgumentException("compressJpgType error. Please use lossy or lossless, default is lossy")
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/compressjpg/inter/ICompressJpg.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer.compressjpg.inter
2 |
3 | interface ICompressJpg {
4 |
5 | void compressJpg(jpgTool, project, file, compressJpgQuality)
6 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/compresspng/AbstractCompressPng.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer.compresspng
2 |
3 | import com.wanglei.optimizer.compresspng.inter.ICompressPng
4 |
5 | abstract class AbstractCompressPng implements ICompressPng{
6 |
7 | @Override
8 | void compressPng(Object pngTool, Object project, Object file, Object compressPngQuality) {
9 | long originalSize = file.length()
10 | def result = commandLine(pngTool,file,compressPngQuality).execute()
11 | result.waitForProcessOutput()
12 | if (result.exitValue() == 0){
13 | long compressedSize = new File(file.absolutePath).length()
14 | float rate = 1.0f * (originalSize - compressedSize) / originalSize * 100
15 | project.logger.error "compress png image ${file.absolutePath} success from ${originalSize}B down to ${compressedSize}B, ${rate}% saved!"
16 | }else if (result.exitValue() == 98) {//有损压缩已经被压缩过则放弃压缩
17 | project.logger.error "Lossy Type skip compress ${file.absolutePath} has been compressed"
18 | }else if (result.exitValue() == 2) {//无损压缩已经被压缩过则放弃压缩
19 | project.logger.error "Lossless Type skip compress ${file.absolutePath} has been compressed"
20 | } else{
21 | project.logger.error "compress png image ${file.absolutePath} error : ${result.err.text}"
22 | }
23 | }
24 |
25 | abstract String commandLine(pngTool,inFile,compressPngQuality)
26 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/compresspng/LosslessCompressPng.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer.compresspng
2 |
3 |
4 | class LosslessCompressPng extends AbstractCompressPng {
5 |
6 | @Override
7 | String commandLine(Object pngTool, Object file, Object compressPngQuality) {
8 | return "${pngTool} ${file.absolutePath}"
9 | }
10 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/compresspng/LossyCompressPng.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer.compresspng
2 |
3 | class LossyCompressPng extends AbstractCompressPng{
4 |
5 | @Override
6 | String commandLine(Object pngTool, Object file, Object pngCompressQuality) {
7 | def suffix = file.name.substring(file.name.lastIndexOf("."), file.name.length())
8 | //--quality min-max min and max are numbers in range 0 (worst) to 100 (perfect)
9 | //--speed N, -sN Speed/quality trade-off from 1 (brute-force) to 10 (fastest).
10 | //The default is 3. Speed 10 has 5% lower quality, but is 8 times faster than the default.
11 | return "${pngTool} -f --skip-if-larger --ext $suffix --quality ${pngCompressQuality}-${pngCompressQuality} --speed 1 ${file.absolutePath}"
12 | }
13 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/compresspng/factory/CompressPngFactory.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer.compresspng.factory
2 |
3 | import com.wanglei.optimizer.ImageOptimizationConstants
4 | import com.wanglei.optimizer.compresspng.LosslessCompressPng
5 | import com.wanglei.optimizer.compresspng.LossyCompressPng
6 | import com.wanglei.optimizer.compresspng.inter.ICompressPng
7 |
8 | class CompressPngFactory {
9 |
10 | private CompressPngFactory() {}
11 |
12 | static ICompressPng getCompressPngTool(String type) {
13 | if (ImageOptimizationConstants.LOSSY .equalsIgnoreCase(type)) {
14 | return new LossyCompressPng()
15 | } else if (ImageOptimizationConstants.LOSSLESS .equalsIgnoreCase(type)) {
16 | return new LosslessCompressPng()
17 | } else {
18 | throw new IllegalArgumentException("compressPngType error. Please use lossy or lossless, default is lossy")
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/compresspng/inter/ICompressPng.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer.compresspng.inter
2 |
3 | interface ICompressPng {
4 |
5 | void compressPng(pngTool, project, file, compressPngQuality)
6 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/convertwebp/AbstractConvertWebp.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer.convertwebp
2 |
3 | import com.wanglei.optimizer.convertwebp.inter.IConvertWebp
4 | import org.gradle.api.Project
5 |
6 | abstract class AbstractConvertWebp implements IConvertWebp {
7 |
8 | @Override
9 | void convertWebp(String webPTool, Project project, File file, List convertFailedList, int convertWebpQuality) {
10 |
11 | def name = file.name.substring(0,file.name.lastIndexOf("."))
12 | def outPutFile = new File(file.parent, "${name}.webp")
13 | //
14 | def result = commandLine(webPTool,file,outPutFile,convertWebpQuality).execute()
15 | result.waitForProcessOutput()
16 | if (result.exitValue() == 0){
17 | def orgFileLen = file.length()//没有转换前图片大小
18 | def outPutFileLen = outPutFile.length()//转为webp后图片大小
19 | if(orgFileLen > outPutFileLen){
20 | file.delete()
21 | project.logger.error "convert webp ${file.absolutePath} success"
22 | }else {
23 | convertFailedList << file
24 | outPutFile.delete()
25 | project.logger.error "convert webp ${file.absolutePath} success but bigger than orgFile"
26 | }
27 | }else{
28 | convertFailedList << file
29 | project.logger.error "convert webp ${file.absolutePath} error"
30 | }
31 | }
32 |
33 | abstract String commandLine(String webPTool,File inFile,File outFile,int convertWebpQuality)
34 |
35 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/convertwebp/LosslessConvertWebp.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer.convertwebp
2 |
3 |
4 | class LosslessConvertWebp extends AbstractConvertWebp{
5 |
6 | @Override
7 | String commandLine(String webPTool, File inFile, File outFile, int convertWebpQuality) {
8 | return "$webPTool -lossless ${inFile.absolutePath} -o ${outFile.absolutePath}"
9 | }
10 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/convertwebp/LossyConvertWebp.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer.convertwebp
2 |
3 |
4 | class LossyConvertWebp extends AbstractConvertWebp {
5 |
6 | @Override
7 | String commandLine(String webPTool,File inFile, File outFile, int convertWebpQuality) {
8 | return "$webPTool -q ${convertWebpQuality} ${inFile.absolutePath} -o ${outFile.absolutePath}"
9 | }
10 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/convertwebp/factory/ConvertWebpFactory.groovy:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer.convertwebp.factory
2 |
3 | import com.wanglei.optimizer.ImageOptimizationConstants
4 | import com.wanglei.optimizer.convertwebp.LosslessConvertWebp
5 | import com.wanglei.optimizer.convertwebp.LossyConvertWebp
6 | import com.wanglei.optimizer.convertwebp.inter.IConvertWebp
7 |
8 |
9 | class ConvertWebpFactory{
10 |
11 | private ConvertWebpFactory() {}
12 |
13 | static IConvertWebp getConvertWebpTool(String type) {
14 | if (ImageOptimizationConstants.LOSSY .equalsIgnoreCase(type)) {
15 | return new LossyConvertWebp()
16 | } else if (ImageOptimizationConstants.LOSSLESS .equalsIgnoreCase(type)) {
17 | return new LosslessConvertWebp()
18 | } else {
19 | throw new IllegalArgumentException("convertWebpType error. Please use lossy or lossless, default is lossy")
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/optimization/src/main/groovy/com/wanglei/optimizer/convertwebp/inter/IConvertWebp.java:
--------------------------------------------------------------------------------
1 | package com.wanglei.optimizer.convertwebp.inter;
2 |
3 | import org.gradle.api.Project;
4 |
5 | import java.io.File;
6 | import java.util.List;
7 |
8 | public interface IConvertWebp {
9 |
10 | void convertWebp(String webPTool, Project project, File file, List convertFailedList, int convertWebpQuality);
11 | }
12 |
--------------------------------------------------------------------------------
/optimization/src/main/resources/META-INF/gradle-plugins/com.wanglei.image-optimization.properties:
--------------------------------------------------------------------------------
1 | implementation-class=com.wanglei.optimizer.ImageOptimizationPlugin
--------------------------------------------------------------------------------
/optimization/src/main/resources/cwebp/cwebp_darwin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/optimization/src/main/resources/cwebp/cwebp_darwin
--------------------------------------------------------------------------------
/optimization/src/main/resources/cwebp/cwebp_linux:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/optimization/src/main/resources/cwebp/cwebp_linux
--------------------------------------------------------------------------------
/optimization/src/main/resources/cwebp/cwebp_win.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/optimization/src/main/resources/cwebp/cwebp_win.exe
--------------------------------------------------------------------------------
/optimization/src/main/resources/guetzli/guetzli_darwin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/optimization/src/main/resources/guetzli/guetzli_darwin
--------------------------------------------------------------------------------
/optimization/src/main/resources/guetzli/guetzli_linux:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/optimization/src/main/resources/guetzli/guetzli_linux
--------------------------------------------------------------------------------
/optimization/src/main/resources/guetzli/guetzli_win.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/optimization/src/main/resources/guetzli/guetzli_win.exe
--------------------------------------------------------------------------------
/optimization/src/main/resources/pngout/pngout_darwin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/optimization/src/main/resources/pngout/pngout_darwin
--------------------------------------------------------------------------------
/optimization/src/main/resources/pngout/pngout_linux:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/optimization/src/main/resources/pngout/pngout_linux
--------------------------------------------------------------------------------
/optimization/src/main/resources/pngout/pngout_win.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/optimization/src/main/resources/pngout/pngout_win.exe
--------------------------------------------------------------------------------
/optimization/src/main/resources/pngquant/pngquant_darwin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/optimization/src/main/resources/pngquant/pngquant_darwin
--------------------------------------------------------------------------------
/optimization/src/main/resources/pngquant/pngquant_linux:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/optimization/src/main/resources/pngquant/pngquant_linux
--------------------------------------------------------------------------------
/optimization/src/main/resources/pngquant/pngquant_win.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/optimization/src/main/resources/pngquant/pngquant_win.exe
--------------------------------------------------------------------------------
/optimization/upload2Jcenter.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.jfrog.bintray'
2 | apply plugin: 'maven-publish'
3 | //发布到jcenter的配置
4 | bintray {
5 | user = 'xxxxxx'
6 | key = 'xxxxxxxxxxxxxxxx'
7 | publications = ['plugin']
8 | pkg {
9 | repo = 'AndroidImageOptimization' //仓库名
10 | name = 'optimization' //项目名
11 | licenses = ['Apache-2.0']
12 | vcsUrl = 'https://github.com/MISAYAWANGLEI/ImageOptimization.git'
13 | version {
14 | desc = 'optimizer android image resource'
15 | released = new Date()
16 | vcsTag = '1.0'//版本控制的版本号
17 | //attributes = ['gradle-plugin': 'xxxxx']
18 | }
19 | }
20 | }
21 |
22 | publishing{
23 | publications{
24 | plugin(MavenPublication){
25 | from components.java
26 | artifactId 'optimization'
27 | artifact sourcesJar
28 | artifact docJar
29 | //
30 | pom.withXml{
31 | def root = asNode()
32 | def licensesNode = root.appendNode('licenses').appendNode('license')
33 | licensesNode.appendNode('name','Apache License, Version 2.0')
34 | licensesNode.appendNode('url','https://www.apache.org/licenses/LICENSE-2.0.txt')
35 | licensesNode.appendNode('distribution','repo')
36 | licensesNode.appendNode('comments','A business-friendly OSS license')
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/optimization/upload2PrivateMaven.gradle:
--------------------------------------------------------------------------------
1 | //私服地址:http://www.sonatype.org/nexus/ 可用于公司搭建自己的私服
2 | //发布到maven私服配置
3 | apply plugin: 'maven-publish'
4 |
5 | publishing{
6 | publications{
7 | plugin(MavenPublication){
8 | from components.java
9 | artifactId 'optimization'
10 | artifact sourcesJar
11 | artifact docJar
12 | //
13 | pom.withXml{
14 | def root = asNode()
15 | def licensesNode = root.appendNode('licenses').appendNode('license')
16 | licensesNode.appendNode('name','Apache License, Version 2.0')
17 | licensesNode.appendNode('url','https://www.apache.org/licenses/LICENSE-2.0.txt')
18 | licensesNode.appendNode('distribution','repo')
19 | licensesNode.appendNode('comments','A business-friendly OSS license')
20 | }
21 | }
22 | }
23 | //配置上传仓库信息
24 | repositories{
25 | maven{
26 | name 'xxx'//私服仓库名字
27 | url 'http://localhost:8081/repository/xxx/'//私服地址
28 | credentials{
29 | username = 'wanglei'//用户名
30 | password = '123456'//密码
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/orginalimage/cdc.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/orginalimage/cdc.PNG
--------------------------------------------------------------------------------
/orginalimage/dewdw.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/orginalimage/dewdw.jpeg
--------------------------------------------------------------------------------
/orginalimage/g.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/orginalimage/g.9.png
--------------------------------------------------------------------------------
/orginalimage/h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/orginalimage/h.png
--------------------------------------------------------------------------------
/orginalimage/i.JPEG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/orginalimage/i.JPEG
--------------------------------------------------------------------------------
/orginalimage/j.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/orginalimage/j.JPG
--------------------------------------------------------------------------------
/orginalimage/k.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/orginalimage/k.png
--------------------------------------------------------------------------------
/orginalimage/qw.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/orginalimage/qw.jpeg
--------------------------------------------------------------------------------
/orginalimage/wece.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/orginalimage/wece.jpg
--------------------------------------------------------------------------------
/orginalimage/wew.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MISAYAWANGLEI/ImageOptimization/387cbe23aa728249983aa343921b09ae550d9258/orginalimage/wew.jpeg
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':optimization', ':androidlibrary'
2 |
--------------------------------------------------------------------------------
/updateLog.md:
--------------------------------------------------------------------------------
1 | >v1.0.0
2 |
3 | - 支持png/jpg图片有损或者无损转为webp
4 | - 支持png图片的有损或者无损压缩
5 | - 支持jpg图片的有损压缩
6 |
7 | 如选择优先转为webp图片,那么插件会将png/jpg图片优先转为webp图片
8 | ,不能转换或者转换失败或者转换后图片更大则执行压缩图片的操作。
9 |
10 | 如选择压缩图片模式,那么插件只会对png/jpg图片进行压缩
11 |
12 | >v2.0.0
13 |
14 | - 增加过滤图片不转换不压缩的功能,图片保持原样
--------------------------------------------------------------------------------