Jelajahi Sumber

Create tinypng

Stille 3 tahun lalu
induk
melakukan
5d160fc1cc
4 mengubah file dengan 191 tambahan dan 0 penghapusan
  1. 10 0
      tinypng/Dockerfile
  2. 28 0
      tinypng/README.md
  3. 113 0
      tinypng/tinypng.py
  4. 40 0
      tinypng/tinypng.sh

+ 10 - 0
tinypng/Dockerfile

@@ -0,0 +1,10 @@
+FROM python:3.7-alpine  
+LABEL org.opencontainers.image.authors="[email protected]"
+
+WORKDIR /
+
+ADD . /
+
+RUN pip install --no-cache-dir tinify
+
+ENTRYPOINT ["/bin/sh", "-c", "/tinypng.sh"]

+ 28 - 0
tinypng/README.md

@@ -0,0 +1,28 @@
+# tinypng
+
+GitHub [stilleshan/dockerfiles](https://github.com/stilleshan/dockerfiles)  
+Docker [stilleshan/tinypng](https://hub.docker.com/r/stilleshan/tinypng)
+> *docker image support for X86 and ARM*
+
+## 简介
+使用 TinyPNG 免费压缩图片 docker 小程序,方便本地批量压缩,支持多个 **API key** 配置。
+
+> [TinyPNG](https://tinypng.com) 是一个非常强大,高画质,高压缩比的在线压缩图片的网站,并提供免费的 API key 用于本地批量压缩。
+
+## 使用
+### 获取 API key
+访问 [TinyPNG Developer API](https://tinypng.com/developers) 获取免费 API key,免费用户每个 key 每月可以压缩 500 张图片,可以创建多个免费账户来获取多个 key 配合本程序使用。
+
+### 准备目录及 key 文件
+1. 在需要压缩照片的目录中创建`api_key.txt`并将`key`粘贴进去,多个`key`时,每行一个`key`。
+2. 确保该目录下没有`Output`文件夹,`Output`文件夹是由本 docker 压缩图片下载后生成。
+3. 图片支持 jpg / jpeg / png 格式,并支持多层子目录。
+
+### docker
+```shell
+docker run --rm -v /your/pic/path:/pic stilleshan/tinypng
+# 修改 /your/pic/path 为需要压缩的图片目录
+```
+
+## 参考
+- Python 来源于 [haoma2012/PythonProject](https://github.com/haoma2012/PythonProject)

+ 113 - 0
tinypng/tinypng.py

@@ -0,0 +1,113 @@
+# -*- coding:utf-8 -*-
+# !/usr/bin/env python3
+# 使用tinypng API压缩项目图片
+import tinify
+import os
+import time
+import shutil
+
+# tinify.key ="Your Developer API Key" # AppKey
+# 设置代理
+# tinify.proxy = ""
+
+os.mkdir("/Output")
+
+# 压缩图片的key
+online_key_list = [
+    "NtkTWRRNjqfF8qllPlrt6hMMHb3Wbb24", # 可以继续添加  防止一个key不够
+]
+
+# 获取key
+online_key_list_iter = iter(online_key_list)
+online_key = next(online_key_list_iter)
+
+# 需要压缩图片的路径
+fromPath = "/pic"  # source dir path
+# 压缩后下载的图片路径
+toPath = "/Output"  # dest dir path
+
+
+tinifyAPi = tinify.tinify
+
+
+# 在线压缩
+def compress_online(sourcefile, outputfile):
+    global online_key
+    compresskey = online_key
+
+    tinify.key = compresskey
+    rs = False
+    try:
+        source = tinifyAPi.from_file(sourcefile)
+        source.to_file(outputfile)
+        print('压缩图片...' + outputfile)
+        rs = True
+        pass
+    except tinify.AccountError:
+        # Verify your API key and account limit.
+        # 如果key值无效 换一个key继续压缩
+        print("key值无效 换一个继续。。。")
+        online_key = next(online_key_list_iter)
+        compress_online(sourcefile, outputfile, name)  # 递归方法 继续读取
+        rs = True
+
+    except tinify.ClientError:
+        # Check your source image and request options.
+        print("Check your source image and request options.")
+        rs = False
+        pass
+    except tinify.ServerError:
+        # Temporary issue with the Tinify API.
+        # print("Temporary issue with the Tinify API. %s" % e.message)
+        print("Temporary issue with the Tinify API.")
+
+        rs = False
+        pass
+    except tinify.ConnectionError:
+        # A network connection error occurred.
+        print("网络故障。。。休息1秒继续")
+        time.sleep(1)
+        compress_online(sourcefile, outputfile, name)  # 递归方法 继续读取
+        rs = True
+        pass
+    except Exception:
+        # Something else went wrong, unrelated to the Tinify API.
+        print("Something else went wrong, unrelated to the Tinify API.")
+        rs = False
+        pass
+
+    return rs
+
+
+# root, dirs, files参数的含义:目录的路径(String);root目录下所有子目录的名字(List);root目录下非目录的名字
+# os.walk(top,topdown=True,onerror=None)函数中各参数的含义:需要遍历的顶级目录的路径;默认值是“True”表示首先返回顶级目录下的文件,然后再遍历子目录中的文件;默认值为"None",表示忽略文件遍历时的错误
+for root, dirs, files in os.walk(fromPath):
+    newToPath = toPath
+    if len(root) > len(fromPath):  # 比较root和fromPath的字符长度
+        innerPath = root[len(fromPath):]  # 字符串切割,将root字符串从第len(fromPath)个位置开始截取,不包括len(fromPath)这个位置的字符
+        if innerPath[0] == '/':  # 判断innerPath的第一个字符是不是/符号
+            innerPath = innerPath[1:]  # 字符串切割,例如innerPath的值为\test,那么innerPath[1:]之后的值为test
+        newToPath = os.path.join(toPath, innerPath)  # 将toPath目录和innerPath文件或文件夹拼接之后的路径赋值给newToPath
+
+    for name in files:
+        newFromFilePath = os.path.join(root, name)
+        newToFilePath = os.path.join(newToPath, name)
+        fileName, fileSuffix = os.path.splitext(name)  # 分解文件名的扩展名
+        if fileSuffix == '.png' or fileSuffix == '.jpg' or fileSuffix == '.jpeg' or fileSuffix == '.PNG' or fileSuffix == '.JPG' or fileSuffix == '.JPEG':
+            # 			source = tinify.from_file(newFromFilePath)
+            # 			source.to_file(newToFilePath)
+            # 在线压缩
+            if not compress_online(newFromFilePath, newToFilePath):
+                print("压缩失败,检查报错信息")
+                exit()
+                pass
+        else:
+            pass
+
+    for dirName in dirs:
+        if os.path.exists(os.path.join(newToPath, dirName)):
+            pass
+        else:
+            os.mkdir(os.path.join(newToPath, dirName))
+
+shutil.move("/Output","/pic")

+ 40 - 0
tinypng/tinypng.sh

@@ -0,0 +1,40 @@
+#!/bin/sh
+
+# fonts color
+Green="\033[32m"
+Red="\033[31m"
+Yellow="\033[33m"
+GreenBG="\033[42;37m"
+RedBG="\033[41;37m"
+Font="\033[0m"
+# fonts color
+
+if [ ! -d /pic ]; then
+    echo -e "${Red}未挂载目录,请重新执行.${Font}"
+    exit 0
+fi
+
+if [ -d /pic/Output ]; then
+    echo -e "${Red}Output 目录已存在,当前已暂停执行.${Font}"
+    echo -e "${Red}请将 Output 目录移除或备份至其他目录.${Font}"
+    echo -e "${Red}否则将会导致重复压缩已输出图片,浪费 API 次数.${Font}"
+    exit 0
+fi
+
+if [ -f /pic/api_key.txt ]; then
+    sed -i '17d' /tinypng.py
+    LINE=17
+    for APIKEY in $(cat /pic/api_key.txt)
+    do
+        sed -i "${LINE}i\    \"${APIKEY}\"," /tinypng.py
+        LINE=$(($LINE+1))
+    done
+fi
+
+python /tinypng.py
+
+if [ ! -f /pic/api_key.txt ]; then
+    echo -e "${Red}未检测到 api_key.txt${Font}"
+    echo -e "${Red}已使用内置公开的 key 压缩图片,由于额度有限,图片压缩有可能失败.${Font}"
+    echo -e "${Green}建议自行免费申请 API key 配置使用更加稳定.${Font}"
+fi