tiny png

golang

package main

import (
    "encoding/base64"
    "fmt"
    "os"
    "net/http"
    "io/ioutil"
    "strings"
    "path/filepath"
    "encoding/json"
    "errors"
    "bytes"
    "time"
    "sync"
)

var sum_file_count int = 0
var handle_file_count int = 0
var wg sync.WaitGroup

func main() {
    keys := [] string{"1343vE6yKv5mlsx6anJ","REjZlZbNJdfdfQjRvE6yKv5mlsx6anJ"}
    url := "https://api.tinify.com/shrink"

    dirPath := "images"
    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 张图片需要处理,请稍候~~\n",sum_file_count)

    startTime := time.Now()
    for i:=0;i<sum_file_count;i++ {
        wg.Add(1)
        shrink(url,keys,files[i])
    }
    wg.Wait()
    fmt.Printf("任务总耗时: %s\n",time.Since(startTime))
}

//上传图片,阻塞等待服务器压缩,服务器压缩成功返回结果后,去下载图片覆盖原图片
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:=0;i<len(keys);i++ {
        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 == 401 {
            //KEY不正确,使用下一个KEY
            fmt.Println("Next Key")
            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
            break
        } else {
            //其它错误
            error_msg := fmt.Sprintf("Tiny状态码: %d\tTiny错误信息: %s\n",res.StatusCode,string(body))
            fmt.Println(error_msg)
            return errors.New(error_msg)
        }
    }
    //CompressionCount := res.Header.Get("Compression-Count")
    //fmt.Printf("Key(%s) UseCount: %s\n",key,CompressionCount)

    if down_url == "" {
        error_msg := "可能所有 KEY 都已经不可用。"
        fmt.Println(error_msg)
        return errors.New(error_msg)
    }

    //覆盖原文件
    down_bytes := []byte{}
    for i:= 0;i < 10;i++ {
        if i>0 {
            fmt.Printf("下载图片 %s 出错,正在进行第 %d 次尝试...\n",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\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, 0600)
    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 += 1
    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, 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"`
    }
}
时间: 2024-09-21 00:26:05

tiny png的相关文章

Tiny Core Linux 显示中文的方法

Tiny Core Linux的下载地址: http://www.tinycorelinux.net/downloads.html 当前的版本为:4.7.5 每个人的需求都不一样,我选择 Tiny Core Linux 的原因很简单--因为体积小.建立这个系统的目的就是看看网页,所以只要让网页浏览器能正常显示出中文即可. 一.利用ISO文件启动计算机,启动后安装"tc-install.tcz",这个程序是部署系统的GUI工具. 二.运行"Tiny Core Installat

Crash Google Chrome with one tiny URL

http://www.theregister.co.uk/2015/09/20/chrome_url_crash/ Crash Google Chrome with one tiny URL: We cram a probe in this bug How clicking on or even rolling your mouse over it will knacker browser Twitter 317 Facebook 94 G+ linkedin 67 20 Sep 2015 at

CSAPP Tiny web server源代码分析及搭建执行

1. Web基础 webclient和server之间的交互使用的是一个基于文本的应用级协议HTTP(超文本传输协议). 一个webclient(即浏览器)打开一个到server的因特网连接,而且请求某些内容.server响应所请求的内容,然后关闭连接.浏览器读取这些内容.并把它显示在屏幕上. 对于webclient和server而言.内容是与一个MIME类型相关的字节序列. 常见的MIME类型: MIME类型 描写叙述 text/html HTML页面 text/plain 无格式文本 ima

You-Get , A Tiny Downloader,视频下载小工具

You-Get    You-Get is a tiny command-line utility to download media contents (videos, audios, images) from the Web, in case there is no other handy way to do it. Here's how you use you-get to download a video from this web page: 1 you-get -o E:/Deskt

CSAPP Tiny web 服务器源码分析及搭建运行

1. Web基础 web客户端和服务器之间的交互使用的是一个基于文本的应用级协议HTTP(超文本传输协议).一个web客户端(即浏览器)打开一个到服务器的因特网连接,并且请求某些内容.服务器响应所请求的内容,然后关闭连接.浏览器读取这些内容,并把它显示在屏幕上. 对于web客户端和服务器而言,内容是与一个MIME类型相关的字节序列.常见的MIME类型: MIME类型 描述 text/html HTML页面 text/plain 无格式文本 image/gif GIF格式编码的二进制图像 imag

Tiny server:小型Web服务器

一.背景 csapp的网络编程粗略的介绍了关于网络编程的一些知识,在最后的一节主要就实现了一个小型的Webserver.这个server名叫Tiny,它是一个小型的可是功能齐全的Webserver.在短短300行左右的代码中,结合了很多思想,比如,进程控制,unix I/O.套接字.HTTP等,令人兴奋的是,它能够为Web浏览器提供静态和动态的内容,也就是说在浏览器中要打开的HTML之类的文件能够直接通过Tiny直接显示在窗体. 我一直想要学习网络编程,这或许就是第一个做成的东西吧,想想都让人兴

Tiny PXE Server简介

Tiny PXE Server简介Tiny PXE Server是一款小巧而功能强大的网启软件.支持DHCP TFTP HTTP BINL DNS等多个协议,支持grub4dos,pxelinux,ipxe等多个引导器,支持从PXE/gPXE/IPXE启动,最新版居然能够直接从互联网通过http协议启动,实在逆天.Tiny PXE Server下载地址:http://erwan.labalec.fr/tinypxeserver/pxesrv.zip1.启动IPXETiny PXE Server可

推荐使用Tiny Framework web开发UI组件

TINY FRAMEWORK 基于组件化的J2EE开发框架,from:http://www.tinygroup.org/ 名字 Tiny名称的来历 取名Tiny是取其微不足道,微小之意. Tiny的构建者认为,一个J2EE开发框架是非常复杂的,只有把框架分解成非常细小.可控的部分,并且对每个细小.可控的部分都有一个最优解或相对最优解, 那么整个方案也就可以非常不错的落地. 策略 Tiny框架的构建策略 Think big, start small, scale fast. 想法要宏伟,但是要从小

编译原理学习:TINY语言词法扫描程序实现

最近对解释型程序(类似python或者是linux里的bc计算器)非常感兴趣,就开始学习一下编译原理.今天自己实现了TINY语言的词法扫描程序.大部分参考<编译原理及实践>一书.但是我做了一些小小的改进. 先说一下TINY语言: 1.注释:放在一对大括号内.书上的注释不能嵌套,我做了一点改进,允许嵌套. 2.关键字:read write if end repeat until else 3.类型:只支持整型和布尔型. 4.计算:+ - * / ( ) < = :=,其中:=为赋值运算,=

《深入理解计算机系统》Tiny服务器4——epoll类型IO复用版Tiny

前几篇博客分别讲了基于多进程.select类型的IO复用.poll类型的IO复用以及多线程版本的Tiny服务器模型,并给出了主要的代码.至于剩下的epoll类型的IO复用版,本来打算草草带过,毕竟和其他两种IO复用模型差不太多.但今天在看Michael Kerrisk的<Linux/UNIX系统编程手册>时,看到了一章专门用来讲解epoll函数,及其IO复用模型.于是,自己也就动手把Tiny改版了一下.感兴趣的同学可以参考上述手册的下册1113页,有对于epoll比较详细的讲解. 前边针对IO