Giter Club home page Giter Club logo

batchprocessimage's Introduction

批量压缩图片,批量替换图片

背景

最近产品提了个需求,要求把包压缩一下,而项目是OC&Swift混编,这期还加上了RN,还要包不能增大。脑壳疼。。。。他则不上天呢。但需求出来了,还是要做的。所以就想了下面几个方法:

  1. 先用LSUnusedResources分析项目中无用的图片和类,删除;
  2. 然后对项目中的图片进行压缩替换;
  3. 再接着分析linkMap文件,找出大的文件进行优化。
  4. 基于clang插件的一种iOS包大小瘦身方案

实现

这篇就是关于第二步的,项目里大约有1600多张图片,之前几次压缩都是按大小排序,然后把大于10kb的图片一个个上传到tinypng上压缩,再下载替换。tinypng web最多支持一次20张,每次上传压缩,然后等,就问问烦不烦。。。。

图片批量压缩

so,这次我终于受不了,我要找批量压缩的,还真给我搜到了图片批量压缩脚本(Python),这种使用方式GitHub上已经写得很清楚了,每月可以500张批量压缩,然后有一个输出文件夹:

使用这个脚本的时候,要注意:

  1. 安装Python
  2. 安装click和tinify
  3. 到此处申请 API key: https://tinypng.com/developers ,一个 key 每个月可以免费压缩500张图片,可以申请多个 key。
pip install click // 安装click库
pip install --upgrade tinify // 安装tinify库

然后使用脚本,GitHub里那位大佬脚本print函数没更新,贴一下我更新后的:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import os
import sys
import os.path
import click
import tinify

tinify.key = "Your API Key"		# API KEY
version = "1.0.1"				# 版本

# 压缩的核心
def compress_core(inputFile, outputFile, img_width):
	source = tinify.from_file(inputFile)
	if img_width is not -1:
		resized = source.resize(method = "scale", width  = img_width)
		resized.to_file(outputFile)
	else:
		source.to_file(outputFile)

# 压缩一个文件夹下的图片
def compress_path(path, width):
	print ("compress_path-------------------------------------")
	if not os.path.isdir(path):
		print ("这不是一个文件夹,请输入文件夹的正确路径!")
		return
	else:
		fromFilePath = path 			# 源路径
		toFilePath = path+"/tiny" 		# 输出路径
		print ("fromFilePath=%s" %fromFilePath)
		print ("toFilePath=%s" %toFilePath)

		for root, dirs, files in os.walk(fromFilePath):
			print ("root = %s" %root)
			print ("dirs = %s" %dirs)
			print ("files= %s" %files)
			for name in files:
				fileName, fileSuffix = os.path.splitext(name)
				if fileSuffix == '.png' or fileSuffix == '.jpg' or fileSuffix == '.jpeg':
					toFullPath = toFilePath + root[len(fromFilePath):]
					toFullName = toFullPath + '/' + name
					if os.path.isdir(toFullPath):
						pass
					else:
						os.mkdir(toFullPath)
					compress_core(root + '/' + name, toFullName, width)
			break									# 仅遍历当前目录

# 仅压缩指定文件
def compress_file(inputFile, width):
	print ("compress_file-------------------------------------")
	if not os.path.isfile(inputFile):
		print ("这不是一个文件,请输入文件的正确路径!")
		return
	print ("file = %s" %inputFile)
	dirname  = os.path.dirname(inputFile)
	basename = os.path.basename(inputFile)
	fileName, fileSuffix = os.path.splitext(basename)
	if fileSuffix == '.png' or fileSuffix == '.jpg' or fileSuffix == '.jpeg':
		compress_core(inputFile, dirname+"/tiny_"+basename, width)
	else:
		print ("不支持该文件类型!")

@click.command()
@click.option('-f', "--file",  type=str,  default=None,  help="单个文件压缩")
@click.option('-d', "--dir",   type=str,  default=None,  help="被压缩的文件夹")
@click.option('-w', "--width", type=int,  default=-1,    help="图片宽度,默认不变")
def run(file, dir, width):
	print ("GcsSloop TinyPng V%s" %(version))
	if file is not None:
		compress_file(file, width)				# 仅压缩一个文件
		pass
	elif dir is not None:
		compress_path(dir, width)				# 压缩指定目录下的文件
		pass
	else:
		compress_path(os.getcwd(), width)		# 压缩当前目录下的文件
	print ("结束!")

if __name__ == "__main__":
    run()

图片批量替换

Yeah,使用了这个脚本之后,图片可以批量压缩了,但是压缩之后的图片是生成在一个独立文件夹,我需要批量替换,but,我图片的目录不确定,换句话说,我不知道这些文件具体在哪个目录下面。。。。oh no。

so,这是你逼我的,开动脑壳,我就想能不能做到我在读取图片压缩的之后直接替换;又或者,写一个单独的批量替换的脚本,因为大的目录确定,压缩前后图片名字没有变化,这么做应该可行,说干就干 使用的时候,把Python文件里TargetPath改成要替换的总目录,SourcePath改成上个脚本执行后压缩后图片的目录,然后运行,binggo,done 原理:

  1. 读取指定目录&子目录下所有文件
  2. 判断是不是图片,是就存到数组里
  3. 读取Target目录和Source目录,然后遍历用'/'分割,取最后一个,判断是否相等,相等就写入
import os
import shutil

# 判断是否是图片
def is_img(ext):
    ext = ext.lower()
    if ext in ['.jpg', '.png', '.jpeg', '.bmp']:
        return True
    else:
        return False

TargetPath = 'Your Target Path' # 要拷贝到哪个目录
SourcePath = 'Your Source Path' # 从哪个目录拷贝

# 获取指定目录下所有图片
def get_img_files(dir):
    py_files = []
    for root, dirs, files in os.walk(dir):
        for file in files:
            pre, suf = os.path.splitext(file)
            if is_img(suf):
                py_files.append(os.path.join(root, file))
    return py_files

TargetFiles = get_img_files(TargetPath)
SourceFiles = get_img_files(SourcePath)

for target in TargetFiles:
    for source in SourceFiles:
        targetName = target.split('/')[-1]
        sourceName = source.split('/')[-1]
        if targetName == sourceName:
            shutil.copyfile(source, target)

图片批量压缩 & 替换,二合一

这样通过两个脚本就可以实现批量压缩、替换,but,我要跑两个脚本,好麻烦,能不能合二为一,就问你能不能? 小样,这怎么可能难倒机智的我,

  1. 压缩脚本的输出目录是替换脚本的源目录,压缩脚本的源目录是替换脚本的输出目录
  2. 所以改一下压缩脚本的实现,读取目录改成是固定的,再改一下压缩脚本的输出目录,注意跟读取目录不要再是读取的子目录,要不然会有问题
  3. 然后在压缩脚本执行成功后,执行批量替换脚本,done
#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import os
import sys
import os.path
import click
import tinify
import shutil

tinify.key = "Your API KEY"		# API KEY
version = "1.0.1"				# 版本

TargetPath = 'Your Target Path' # 要拷贝到哪个目录
SourcePath = 'Your Source Path' # 从哪个目录拷贝

# 压缩的核心
def compress_core(inputFile, outputFile, img_width):
	source = tinify.from_file(inputFile)
	if img_width is not -1:
		resized = source.resize(method = "scale", width  = img_width)
		resized.to_file(outputFile)
	else:
		source.to_file(outputFile)

# 压缩一个文件夹下的图片
def compress_path(path, width):
	print ("compress_path-------------------------------------")
	if not os.path.isdir(path):
		print ("这不是一个文件夹,请输入文件夹的正确路径!")
		return
	else:
		fromFilePath = path 			# 源路径
		toFilePath = SourcePath 		# 输出路径
		print ("fromFilePath=%s" %fromFilePath)
		print ("toFilePath=%s" %toFilePath)

		for root, dirs, files in os.walk(fromFilePath):
			print ("root = %s" %root)
			print ("dirs = %s" %dirs)
			print ("files= %s" %files)
			for name in files:
				fileName, fileSuffix = os.path.splitext(name)
				if fileSuffix == '.png' or fileSuffix == '.jpg' or fileSuffix == '.jpeg':
					toFullPath = toFilePath + root[len(fromFilePath):]
					toFullName = toFullPath + '/' + name
					if os.path.isdir(toFullPath):
						pass
					else:
						os.mkdir(toFullPath)
					compress_core(root + '/' + name, toFullName, width)
			# break									# 仅遍历当前目录

# 仅压缩指定文件
def compress_file(inputFile, width):
	print ("compress_file-------------------------------------")
	if not os.path.isfile(inputFile):
		print ("这不是一个文件,请输入文件的正确路径!")
		return
	print ("file = %s" %inputFile)
	dirname  = os.path.dirname(inputFile)
	basename = os.path.basename(inputFile)
	fileName, fileSuffix = os.path.splitext(basename)
	if fileSuffix == '.png' or fileSuffix == '.jpg' or fileSuffix == '.jpeg':
		compress_core(inputFile, dirname+"/tiny_"+basename, width)
	else:
		print ("不支持该文件类型!")

# 判断是否是图片
def is_img(ext):
    ext = ext.lower()
    if ext in ['.jpg', '.png', '.jpeg', '.bmp']:
        return True
    else:
        return False

# 获取指定目录下所有图片
def get_img_files(dir):
    py_files = []
    for root, dirs, files in os.walk(dir):
        for file in files:
            pre, suf = os.path.splitext(file)
            if is_img(suf):
                py_files.append(os.path.join(root, file))
    return py_files

# 批处理替换
def batch_replace_img():
    TargetFiles = get_img_files(TargetPath)
    SourceFiles = get_img_files(SourcePath)

    for target in TargetFiles:
        for source in SourceFiles:
            targetName = target.split('/')[-1]
            sourceName = source.split('/')[-1]
            if targetName == sourceName:
                shutil.copyfile(source, target)

@click.command()
@click.option('-f', "--file",  type=str,  default=None,  help="单个文件压缩")
@click.option('-d', "--dir",   type=str,  default=None,  help="被压缩的文件夹")
@click.option('-w', "--width", type=int,  default=-1,    help="图片宽度,默认不变")
def run(file, dir, width):
	print ("GcsSloop TinyPng V%s" %(version))
	if file is not None:
		compress_file(file, width)				# 仅压缩一个文件
		pass
	elif dir is not None:
		compress_path(dir, width)				# 压缩指定目录下的文件
		pass
	else:
		compress_path(os.getcwd(), width)		# 压缩当前目录下的文件
	print ("压缩结束!")

if __name__ == "__main__":
    # run(None, TargetPath, None)
    compress_path(TargetPath, -1)
    batch_replace_img()
    print("替换结束")

待续

but,因为我的工程目录下有1600多张的图片,而批量压缩脚本每月最多执行500张,而且我读取图片又不固定,所以没有办法一次性压缩。so,我还要想我这个能不能一步到位

  1. 有没有批量压缩不限数量的API
  2. 如果没有的话,怎么保证我多次执行这个脚本的连续性,即:我执行了一次之后,下一次换个key,怎么接着执行
  3. 。。。想想就脑壳疼

....to be continued

batchprocessimage's People

Contributors

mokong avatar

Stargazers

 avatar  avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.