zoukankan      html  css  js  c++  java
  • 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 = 0
    var handle_file_count int = 0
    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) < 2 {
            fmt.Println("==该工具用于使用 TinyPng 服务进行图片压缩处理,需要传一个文件夹参数,程序会自动递归搜索其中的 *.png 文件进行处理,处理完毕后会覆盖原文件==
    ")
            return
        }
        dirPath := os.Args[1]
    
        keys := []string{}
        key_file, err := os.Open("keys.txt")
        defer key_file.Close()
        if err != nil {
            error_msg := fmt.Sprintf("读取 KEY 文件错误,文件路径错误! (path: %s	error: %s)", "keys.txt", err.Error())
            fmt.Printf(error_msg)
            return
        }
        rd := bufio.NewReader(key_file)
        for {
            line, err := rd.ReadString('
    ')
            if err != nil || err == io.EOF {
                break
            }
            if len(line) > 1 {
                keys = append(keys,strings.Trim(line,"
    "))
            }
        }
    
        /*
        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 == 0 {
            fmt.Println("没有 *.png 图片需要处理~~")
            return
        }
    
        fmt.Printf("有 %d 张图片需要处理,请稍候~~
    ",sum_file_count)
    
        invalid_keys = make(map[string]int)
        keys_user_count = make(map[string]int)
    
        startTime := time.Now()
        for i:=0;i<sum_file_count;i++ {
            wg.Add(1)
            shrink(url,keys,files[i])
        }
        wg.Wait()
        fmt.Printf("任务总耗时: %s
    ",time.Since(startTime))
    
        if len(keys_user_count) > 0 {
            fmt.Printf("
    ==KEY的本月已使用次数如下:
    ")
            for k,v := range keys_user_count {
                fmt.Printf("KEY: %s	UseCount: %d
    ",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	error: %s)", filePath, err.Error())
            fmt.Println(error_msg)
            return err
        }
    
        down_url := ""
        for i:=0;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)
    ",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)
    ",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)
    ",err.Error())
                fmt.Println(error_msg)
                return errors.New(error_msg)
            }
    
            //判断HTTP状态码,如果是 415表示文件类型不正确;401表示证书不正确;400表示输入文件为空;5xx表示服务器异常;2xx表示成功
            if status == 401 || status == 400 {
                //KEY不正确,使用下一个KEY
                /*
                if status == 400 {
                    fmt.Printf("该 KEY: %s 很可能是格式非法,请留意。
    ",keys[i])
                }
                */
                invalid_keys[keys[i]] = 1
                time.Sleep(time.Millisecond * 50)
                continue
            } else if status < 300 && status >= 200 {
                //正确
                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 = 0
                }
                if CompressionCountInt > keys_user_count[keys[i]] {
                    keys_user_count[keys[i]] = CompressionCountInt
                }
    
                break
            } else {
                //其它错误
                error_msg := fmt.Sprintf("Tiny状态码: %d	Tiny错误信息: %s
    ",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
    ",key,CompressionCount)
    
        //覆盖原文件
        down_bytes := []byte{}
        for i:= 0;i < 10;i++ {
            if i>0 {
                fmt.Printf("下载图片 %s 出错,正在进行第 %d 次尝试...
    ",down_url,i+1)
                time.Sleep(time.Millisecond*50)
            }
            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) == 0 {
            error_msg := fmt.Sprintf("下载图片出错!(filePath: %s	url: %s	error: %s)
    ", 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, 0600)
        defer file.Close()
        if err != nil {
            error_msg := fmt.Sprintf("清空原图片出错!(filePath: %s	url: %s	error: %s)
    ", 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	url: %s	error: %s)
    ", filePath,down_url,err.Error())
            fmt.Printf(error_msg)
            return errors.New(error_msg)
        }
    
        handle_file_count += 1
        fmt.Printf("任务进度[%d/%d]
    ",handle_file_count,sum_file_count)
        return nil
    }
    
    //获取指定目录下的所有文件,不进入下一级目录搜索,可以匹配后缀过滤。
    func ListDir(dirPth string, suffix string) (files []string, err error) {
        files = make([]string, 0, 10)
        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, 0, 30)
        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"`
        }
    }
  • 相关阅读:
    移动端文本编辑器
    jquery移动端日期插件
    Spring 4集成 Quartz2(转)
    json 特殊字符 javascript 特殊字符处理(转载)
    解决使用JavaScriptConvert转换对象为Json时,中文和&符号被转码的问题
    RFID的winform程序心得2
    异步编程模型
    DataGridView获取或者设置当前单元格的内容
    DataGridView修改数据并传到数据库
    把存储过程结果集SELECT INTO到临时表
  • 原文地址:https://www.cnblogs.com/tianyajuanke/p/8001683.html
Copyright © 2011-2022 走看看