美文网首页
图片压缩插件McImage

图片压缩插件McImage

作者: 风月寒 | 来源:发表于2021-04-05 15:10 被阅读0次
使用
classpath 'com.smallsoho.mobcase:McImage:1.5.1'

apply plugin: 'McImage'

McImageConfig {
    isCheckSize true 
    optimizeType "ConvertWebp" //Optimize Type,"ConvertWebp" or "Compress",default "Compress", "CompressWebp" is a better compression ratio but it don't support api < 18
    maxSize 1*1024*1024 //big image size threshold,default 1MB
    enableWhenDebug true //switch in debug build,default true
    isCheckPixels true // Whether to detect image pixels of width and height,default true
    maxWidth 1200 //default 1000
    maxHeight 1000 //default 1000
    whiteList = [ 

    ]
    mctoolsDir "$rootDir"
    isSupportAlphaWebp true  
    multiThread true  
    bigImageWhiteList = [
        "icon_login_bg.png"

    ] 
}

解释下下面参数的意思:

isCheckSize:是否检查图片的大小

optimizeType:方式,包括压缩和转化成Webp格式

maxSize:大图的判定条件,如果超过这个就会报错,要想不报错,则将改图片放到bigImageWhiteList中,这样就会跳过大图片检测。

enableWhenDebug:是否在dengbug进行build。

isCheckPixels:检查图片的宽和高,如果超过这个就会报错,其限制为maxWidth和maxHeight参数决定

whiteList:加入这个list的不会进行转变

multiThread:是否支持多线程

bigImageWhiteList:加入到这个的图片不需要进行大图检测

源码分析
override fun apply(project: Project) {

        mcImageProject = project

        //check is library or application
        val hasAppPlugin = project.plugins.hasPlugin("com.android.application")
        val variants = if (hasAppPlugin) {
            (project.property("android") as AppExtension).applicationVariants
        } else {
            (project.property("android") as LibraryExtension).libraryVariants
        }

        //set config
        project.extensions.create("McImageConfig", Config::class.java)
        mcImageConfig = project.property("McImageConfig") as Config // 1

        project.afterEvaluate {
            variants.all { variant ->

                variant as BaseVariantImpl

                checkMcTools(project)//2

                val mergeResourcesTask = variant.mergeResourcesProvider.get()//3
                val mcPicTask = project.task("McImage${variant.name.capitalize()}")//4

                mcPicTask.doLast {

                    val dir = variant.allRawAndroidResources.files

                    val cacheList = ArrayList<String>()

                    val imageFileList = ArrayList<File>()

                    for (channelDir: File in dir) {
                        traverseResDir(channelDir, imageFileList, cacheList, object : IBigImage {
                            override fun onBigImage(file: File) {
                                bigImgList.add(file.absolutePath)
                            }
                        })
                    }

                    checkBigImage()//5

                    val start = System.currentTimeMillis()

                    mtDispatchOptimizeTask(imageFileList)//6
                    LogUtil.log(sizeInfo())
                    LogUtil.log("---- McImage Plugin End ----, Total Time(ms) : ${System.currentTimeMillis() - start}")
                }

                //chmod task
                val chmodTaskName = "chmod${variant.name.capitalize()}"
                val chmodTask = project.task(chmodTaskName)//7
                chmodTask.doLast {
                    //chmod if linux
                    if (Tools.isLinux()) {
                        Tools.chmod()
                    }
                }

                //inject task
                (project.tasks.findByName(chmodTask.name) as Task).dependsOn(mergeResourcesTask.taskDependencies.getDependencies(mergeResourcesTask))
                (project.tasks.findByName(mcPicTask.name) as Task).dependsOn(project.tasks.findByName(chmodTask.name) as Task)
                mergeResourcesTask.dependsOn(project.tasks.findByName(mcPicTask.name))//8

            }
        }

    }

1处可以理解就是创建一个java bean类对象,其赋值则是上面的McImageConfig里面的东西。并且在build.gradle文件中的McImageConfig这个名字是根据project.extensions.create("McImageConfig", Config::class.java)确定的,而且必须要一致,不然会报错。具体字段如下:

public class Config {

    public static final String OPTIMIZE_WEBP_CONVERT = "ConvertWebp"; //webp化
    public static final String OPTIMIZE_COMPRESS_PICTURE = "Compress"; //压缩图片

    public float maxSize = 1024 * 1024;
    public boolean isCheckSize = true; //是否检查大体积图片
    public String optimizeType = OPTIMIZE_WEBP_CONVERT; //优化方式,webp化、压缩图片
    public boolean enableWhenDebug = true;
    public boolean isCheckPixels = true; //是否检查大像素图片
    public int maxWidth = 1000;
    public int maxHeight = 1000;
    public String[] whiteList = new String[]{}; //优化图片白名单
    public String mctoolsDir = "";
    public boolean isSupportAlphaWebp = false; //是否支持webp化透明通道的图片,如果开启,请确保minSDK >= 18,或做了其他兼容措施
    public boolean multiThread = true;
    public String[] bigImageWhiteList = new String[]{}; //大图检测白名单
}

在2处检查工具,即转化成webP格式的在window,mac,linux平台下的工具。

下载下来需要放在根目录下。

下载路径 https://github.com/smallSohoSolo/McImage/releases

3处则是拿到mergeDebugResourcesTask,一般执行mergeDebugResources会将所有的资源进行合并,这样我们就可拿到所有的资源文件。

而我们的插件则是在这一步之后,遍历拿到所有的图片资源进行操作。

4处则是创建两个个task,分别有debug和release。创建之后可以在AS的右侧的gradle的other文件夹看到这两个task。

然后执行dolast里面的东西。拿到所有的资源文件,然后进行遍历。

private fun traverseResDir(file: File, imageFileList: ArrayList<File>, cacheList: ArrayList<String>, iBigImage: IBigImage) {
        if (cacheList.contains(file.absolutePath)) {
            return
        } else {
            cacheList.add(file.absolutePath)
        }
        if (file.isDirectory) {
            file.listFiles()?.forEach {
                if (it.isDirectory) {
                    traverseResDir(it, imageFileList, cacheList, iBigImage)
                } else {
                    filterImage(it, imageFileList, iBigImage)
                }
            }
        } else {
            filterImage(file, imageFileList, iBigImage)
        }
    }

在这里采用递归的方式,并且对图片进行一个过滤。

在5处继续对大图进行检查。

private fun checkBigImage() {
        if (bigImgList.size != 0) {
            val stringBuffer = StringBuffer("You have big Imgages with big size or large pixels," +
                    "please confirm whether they are necessary or whether they can to be compressed. " +
                    "If so, you can config them into bigImageWhiteList to fix this Exception!!!\n")
            for (i: Int in 0 until bigImgList.size) {
                stringBuffer.append(bigImgList[i])
                stringBuffer.append("\n")
            }
            throw GradleException(stringBuffer.toString())
        }
    }

如果在build.gradle里面配置了,则不满足条件的则报异常。

6处则是判定是否进行多线程进行图片处理。

7处则是有重新创建一个task。

在8处则是对创建的task的一个先后执行的顺序。

在项目中进行webp图片转换是在WebpUtils类中。

private fun formatWebp(imgFile: File) {
            if (ImageUtil.isImage(imgFile)) {
                val webpFile = File("${imgFile.path.substring(0, imgFile.path.lastIndexOf("."))}.webp")
                Tools.cmd("cwebp", "${imgFile.path} -o ${webpFile.path} -m 6 -quiet")
                if (webpFile.length() < imgFile.length()) {
                    LogUtil.log(TAG, imgFile.path, imgFile.length().toString(), webpFile.length().toString())
                    if (imgFile.exists()) {
                        imgFile.delete()
                    }
                } else {
                    //如果webp的大的话就抛弃
                    if (webpFile.exists()) {
                        webpFile.delete()
                    }
                    LogUtil.log("[${TAG}][${imgFile.name}] do not convert webp because the size become larger!")
                }
            }
        }

将每个文件以.webp结尾,然后调用工具生成。

如果不支持透明通道的png,则进行压缩,压缩的代码在CompressUtil 中。

fun compressImg(imgFile: File) {
            if (!ImageUtil.isImage(imgFile)) {
                return
            }
            val oldSize = imgFile.length()
            val newSize: Long
            if (ImageUtil.isJPG(imgFile)) {
                val tempFilePath: String = "${imgFile.path.substring(0, imgFile.path.lastIndexOf("."))}_temp" +
                        imgFile.path.substring(imgFile.path.lastIndexOf("."))
                Tools.cmd("guetzli", "${imgFile.path} $tempFilePath")
                val tempFile = File(tempFilePath)
                newSize = tempFile.length()
                LogUtil.log("newSize = $newSize")
                if (newSize < oldSize) {
                    val imgFileName: String = imgFile.path
                    if (imgFile.exists()) {
                        imgFile.delete()
                    }
                    tempFile.renameTo(File(imgFileName))
                } else {
                    if (tempFile.exists()) {
                        tempFile.delete()
                    }
                }

            } else {
                Tools.cmd("pngquant", "--skip-if-larger --speed 1 --nofs --strip --force --output ${imgFile.path} -- ${imgFile.path}")
                newSize = File(imgFile.path).length()
            }

            LogUtil.log(TAG, imgFile.path, oldSize.toString(), newSize.toString())
        }
    }

这里的压缩有两种方式,对于JPG格式的则采用guetzli压缩,PNG格式的则采用pngquant压缩。guetzli压缩是无损压缩,压缩时间比较长,压缩率只能到百分之30.而pngquant算法是有损压缩,不过损失度在可接受范围内。

遇到的问题

,部分转换的会把原来png格式的图片删掉,但是还有部分的没有删掉,会同时存在两张不同格式的图片。到mergeDebugResource这一步报错,很多张图片Duplicate resources。

相关文章

  • 图片压缩插件McImage

    使用 解释下下面参数的意思: isCheckSize:是否检查图片的大小 optimizeType:方式,包括压缩...

  • android App图片资源文件压缩利器McImage

    Android App图片资源文件压缩利器McImage 这个图片资源压缩利器McImage在我司的产品线中使用了...

  • McImage

    McImage是无侵入式的全量压缩资源图片插件 包括 Jar包中的图 AAR中的图 子Module中的图 插件使用...

  • Android自动化批量图片压缩插件McImage

    文 | Promise Sun 一、资源图片压缩 关于资源图片压缩,可以在tinypng这个网站进行手动图片压缩,...

  • 图片压缩插件

    利用canvas封装的压缩图片插件,解决了iphone照片图片方向问题。(笔者在getBase64()回调中,调用...

  • 烈风裘的前端技能

    切图Photoshop切图插件Cutterman标注插件Parker图片压缩ImageOptim/HummingB...

  • gulp--自动化构建工具

    常用的gulp插件: 1、css压缩:gulp-caanano; 2、图片压缩:gulp-imagemin; 3、...

  • cli3 图片压缩配置

    1、安装插件 2、配置信息 已在用,图片压缩有效。

  • 2019-07-23

    vue打包图片压缩插件 1.安装插件 yarn addimage-webpack-loader 2.配置build...

  • CocosCreator和gulp-使用gulp-imagemi

    在游戏开发中,打包前进行图片压缩是必需工作,gulp内置了很多构建、优化插件,例如:图片压缩、js文件合并等等,这...

网友评论

      本文标题:图片压缩插件McImage

      本文链接:https://www.haomeiwen.com/subject/btydkltx.html