tiny png
golang
package main import (
"encoding/base64"
"fmt"
"os"
"net/http"
"io/ioutil"
"strings"
"path/filepath"
"encoding/json"
"errors"
"bytes"
"time"
"sync"
"strconv"
"bufio"
"io"
) var sum_file_count int =
var handle_file_count int =
var wg sync.WaitGroup
var invalid_keys map[string]int
var keys_user_count map[string]int func main() {
url := "https://api.tinify.com/shrink" if len(os.Args) < {
fmt.Println("==该工具用于使用 TinyPng 服务进行图片压缩处理,需要传一个文件夹参数,程序会自动递归搜索其中的 *.png 文件进行处理,处理完毕后会覆盖原文件==\n")
return
}
dirPath := os.Args[] keys := []string{}
key_file, err := os.Open("keys.txt")
defer key_file.Close()
if err != nil {
error_msg := fmt.Sprintf("读取 KEY 文件错误,文件路径错误! (path: %s\terror: %s)", "keys.txt", err.Error())
fmt.Printf(error_msg)
return
}
rd := bufio.NewReader(key_file)
for {
line, err := rd.ReadString('\n')
if err != nil || err == io.EOF {
break
}
if len(line) > {
keys = append(keys,strings.Trim(line,"\n"))
}
} /*
for _,v := range keys{
println(v)
}
*/ files, err := WalkDir(dirPath, ".png")
if err != nil {
fmt.Println("请检查目录是否存在~~")
return
} sum_file_count = len(files)
if sum_file_count == {
fmt.Println("没有 *.png 图片需要处理~~")
return
} fmt.Printf("有 %d 张图片需要处理,请稍候~~\n",sum_file_count) invalid_keys = make(map[string]int)
keys_user_count = make(map[string]int) startTime := time.Now()
for i:=;i<sum_file_count;i++ {
wg.Add()
shrink(url,keys,files[i])
}
wg.Wait()
fmt.Printf("任务总耗时: %s\n",time.Since(startTime)) if len(keys_user_count) > {
fmt.Printf("\n==KEY的本月已使用次数如下:\n")
for k,v := range keys_user_count {
fmt.Printf("KEY: %s\tUseCount: %d\n",k,v)
}
}
} //上传图片,阻塞等待服务器压缩,服务器压缩成功返回结果后,去下载图片覆盖原图片
func shrink(url string, keys []string, filePath string) error {
defer wg.Done()
file_bytes, err := ioutil.ReadFile(filePath)
if err != nil {
error_msg := fmt.Sprintf("读取本地文件错误,文件路径错误! (path: %s\terror: %s)", filePath, err.Error())
fmt.Println(error_msg)
return err
} down_url := ""
for i:=;i<len(keys);i++ {if _,ok := invalid_keys[keys[i]];ok {
continue
}
req, err := http.NewRequest("POST", url, bytes.NewReader(file_bytes))
if err != nil {
error_msg := fmt.Sprintf("请求 Tiny 出现网络错误! (error: %s)\n",err.Error())
fmt.Println(error_msg)
return errors.New(error_msg)
}
credentials := base64.StdEncoding.EncodeToString([]byte("api:" + keys[i]))
req.Header.Set("Authorization", "Basic "+credentials)
//处理返回结果
res, err := http.DefaultClient.Do(req)
if err != nil {
error_msg := fmt.Sprintf("请求 Tiny 出现网络错误! (error: %s)\n",err.Error())
fmt.Println(error_msg)
return errors.New(error_msg)
}
status := res.StatusCode
body, err := ioutil.ReadAll(res.Body)
if err != nil {
error_msg := fmt.Sprintf("请求 Tiny 出现网络错误! (error: %s)\n",err.Error())
fmt.Println(error_msg)
return errors.New(error_msg)
} //判断HTTP状态码,如果是 415表示文件类型不正确;401表示证书不正确;400表示输入文件为空;5xx表示服务器异常;2xx表示成功
if status == || status == {
//KEY不正确,使用下一个KEY
/*
if status == 400 {
fmt.Printf("该 KEY: %s 很可能是格式非法,请留意。\n",keys[i])
}
*/
invalid_keys[keys[i]] =
time.Sleep(time.Millisecond * )
continue
} else if status < && status >= {
//正确
right_data := new(RightData)
json.Unmarshal(body, right_data)
down_url = right_data.Output.Url CompressionCount := res.Header.Get("Compression-Count")
CompressionCountInt, err := strconv.Atoi(CompressionCount)
if err != nil {
CompressionCountInt =
}
if CompressionCountInt > keys_user_count[keys[i]] {
keys_user_count[keys[i]] = CompressionCountInt
} break
} else {
//其它错误
error_msg := fmt.Sprintf("Tiny状态码: %d\tTiny错误信息: %s\n",res.StatusCode,string(body))
fmt.Println(error_msg)
return errors.New(error_msg)
}
} if down_url == "" {
error_msg := "可能所有 KEY 都已经不可用。"
fmt.Println(error_msg)
return errors.New(error_msg)
} //CompressionCount := res.Header.Get("Compression-Count")
//fmt.Printf("Key(%s) UseCount: %s\n",key,CompressionCount) //覆盖原文件
down_bytes := []byte{}
for i:= ;i < ;i++ {
if i> {
fmt.Printf("下载图片 %s 出错,正在进行第 %d 次尝试...\n",down_url,i+)
time.Sleep(time.Millisecond*)
}
res_down, err := http.Get(down_url)
if err != nil {
continue
}
down_bytes, err = ioutil.ReadAll(res_down.Body)
if err != nil {
continue
}
break
}
if len(down_bytes) == {
error_msg := fmt.Sprintf("下载图片出错!(filePath: %s\turl: %s\terror: %s)\n", filePath,down_url,err.Error())
fmt.Printf(error_msg)
return errors.New(error_msg)
} file, err := os.OpenFile(filePath,os.O_RDWR | os.O_TRUNC, )
defer file.Close()
if err != nil {
error_msg := fmt.Sprintf("清空原图片出错!(filePath: %s\turl: %s\terror: %s)\n", filePath,down_url,err.Error())
fmt.Printf(error_msg)
return errors.New(error_msg)
}
_, err = file.Write(down_bytes)
if err != nil {
error_msg := fmt.Sprintf("覆写原图片出错!(filePath: %s\turl: %s\terror: %s)\n", filePath,down_url,err.Error())
fmt.Printf(error_msg)
return errors.New(error_msg)
} handle_file_count +=
fmt.Printf("任务进度[%d/%d]\n",handle_file_count,sum_file_count)
return nil
} //获取指定目录下的所有文件,不进入下一级目录搜索,可以匹配后缀过滤。
func ListDir(dirPth string, suffix string) (files []string, err error) {
files = make([]string, , )
dir, err := ioutil.ReadDir(dirPth)
if err != nil {
return nil, err
}
PthSep := string(os.PathSeparator)
suffix = strings.ToUpper(suffix) //忽略后缀匹配的大小写
for _, fi := range dir {
if fi.IsDir() { // 忽略目录
continue
}
if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) { //匹配文件
files = append(files, dirPth+PthSep+fi.Name())
}
}
return files, nil
} //获取指定目录及所有子目录下的所有文件,可以匹配后缀过滤。
func WalkDir(dirPth, suffix string) (files []string, err error) {
files = make([]string, , )
suffix = strings.ToUpper(suffix) //忽略后缀匹配的大小写
err = filepath.Walk(dirPth, func(filename string, fi os.FileInfo, err error) error { //遍历目录
//if err != nil { //忽略错误
// return err
//}
if fi.IsDir() { // 忽略目录
return nil
}
if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
files = append(files, filename)
}
return nil
})
return files, err
} type RightData struct {
Input struct {
Size int `json:"size"`
Type string `json:"type"`
} `json:"input"`
Output struct {
Size int `json:"size"`
Type string `json:"type"`
Width int `json:"width"`
Height int `json:"height"`
Ratio float32 `json:"ratio"`
Url string `json:"url"`
}
}
tiny png的更多相关文章
- .NET平台开源项目速览(14)最快的对象映射组件Tiny Mapper
好久没有写文章,工作甚忙,但每日还是关注.NET领域的开源项目.五一休息,放松了一下之后,今天就给大家介绍一个轻量级的对象映射工具Tiny Mapper:号称是.NET平台最快的对象映射组件.那就一起 ...
- Tiny Mapper
今天看到一个对象映射工具-TinyMapper 1.介绍 Tiny Mapper是一个.net平台的开源的对象映射组件,其它的对象映射组件比如AutoMapper有兴趣的可以去看,Tiny Mappe ...
- 微型Http服务器Tiny Http Server
Tiny Http Server 一个简单的跨平台Http服务器.服务器部分使用了Mongoose的代码,界面是使用QT开发的. 开发为了在临时需要使用一个http服务器来做发布代码文档的时候,不用去 ...
- 对象映射组件Tiny Mapper
1.Tiny Mapper的简单实用例子 using System; using System.Collections.Generic; using System.Linq; using System ...
- Tiny Rss简明安装与配置笔记
对于某些自己喜欢的却没有RSS订阅功能的网站,可以通过Feed43定制抓取规则来获取所需信息.但由于其服务器在国外,抓取时常失败,且免费账户抓取频率太低,遂仿造他自行实现了一个并挂到服务器上,然后通过 ...
- 世界上最小的发行版之一Tiny Core
Tiny Core Linux不足之处驱动不给力 Tiny Core是一个简单的范例来说明核心项目可以提供什么.它提供了一个12MB的FLTK/FLWM桌面.用户对提供的程序和外加的硬件有完整的控制权 ...
- Tiny PXE Server简介
Tiny PXE Server简介Tiny PXE Server是一款小巧而功能强大的网启软件.支持DHCP TFTP HTTP BINL DNS等多个协议,支持grub4dos,pxelinux,i ...
- 神奇的linux发行版 tiny core linux
首先官网在此 http://tinycorelinux.net/ 真正轻量级 名字里带有“tiny”又带有“core”,想必又是一个所谓的“轻量级”发行版. 轻量级我们见多了,debian号称是轻量级 ...
- .NET平台开源项目速览-最快的对象映射组件Tiny Mapper之项目实践
心情小札:近期换了工作,苦逼于22:00后下班,房间一篇狼藉~ 小翠鄙视到:"你就适合生活在垃圾堆中!!!" 晚上浏览博客园 看到一篇非常实用的博客:.NET平台开源项目速览(14 ...
- Tiny语言执行环境TM机源码
TM机就是TINY语言编译器编译之后的汇编代码的执行环境.TM机的主要功能是将TM的汇编代码读入和执行,它具有一般计算机类似的精简指令级RISC.TM汇编语言和一般的Intel汇编语言差点儿相同,包含 ...
随机推荐
- 编程菜鸟的日记-初学尝试编程-C++ Primer Plus 第4章编程练习5
#include <iostream>using namespace std;struct CandyBar{ char kind[20]; float weight; int calor ...
- 1. Spring 简介以及关于 Eclipse 的 Spring Tool Suite 插件安装
今天开始学 Spring 了,就先来认识一下什么是 Spring 吧. 1. 首先,Spring 是一个框架,而且是开源的. 2. Spring 为简化企业级应用开发而生.使用 Spring 可以使简 ...
- Html图像标签、绝对路径和相对路径:
Html图像标签: <img>标签可以在网页上插入一张图片,它是独立使用的标签,它的常用属性有: (1)src 属性 定义图片的引用地址 (2)alt 属性 定义图片加载失败时显示的文字, ...
- sqlserver数据类型转换
Insert into [Cet.4] Select CONVERT(VARCHAR(20),CONVERT(DECIMAL(20,7),F1)) FROM Sheet1$ 我从外部导入了一个学号表, ...
- 第三届“百越杯”福建省高校网络空间安全大赛writeup--Do you know upload?
一打开网址,可以看出应该是文件上传漏洞,查看源码,也有可能是文件包含 上传个图片,成功,然后上传一句话木马 通过bp进行上传绕过 , 开始菜刀连接http://e00b6eca3c9c4e14a31c ...
- 【想法题】Knot Puzzle @AtCoder Grand Contest 002 C/upcexam5583
时间限制: 2 Sec 内存限制: 256 MB 题目描述 We have N pieces of ropes, numbered 1 through N. The length of piece i ...
- Compiler Error: Function call with parameters that may be unsafe
如下的代码: #include <stdio.h> #include <string> #include <algorithm> #include <cass ...
- Spring HttpInvoker 从实战到源码追溯
Spring HttpInvoker 作为 Spring 家族中老牌远程调用模型,深受开发者喜爱. 其主要目的是来执行基于 HTTP 的远程调用(轻松穿越防火墙),并使用标准的 JDK 序列化机制. ...
- 【20180111】【物流FM专访】贝业新兄弟李济宏:我们是如何做到大件家居B2C物流第一的?
在2017年的双11中,贝业新兄弟承接了日日顺家装和卫浴行业的仓储和配送,上海仓和武汉仓双十一期间及时出库率为100%,KPI位列第一:此外,贝业新兄弟还是科勒18年以来中国区唯一的物流服务商以及宜家 ...
- SNF快速开发平台项目实践介绍
SNF快速开发平台分如下子平台: 1.CS快速开发平台 2.BS快速开发平台 3.H5移动端快速开发平台 4.软件开发机器人平台(目前是CS版本,后续有规划BS版本) SNF快速开发平台是一个比较成熟 ...