最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Go語(yǔ)言帶你搞定圖片壓縮指南

 更新時(shí)間:2025年11月24日 08:49:25   作者:九江Mgx  
這篇文章主要為大家詳細(xì)介紹了如何使用Go語(yǔ)言實(shí)現(xiàn)圖片壓縮功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

痛點(diǎn)催生的靈感

話說(shuō)某天,我正在幫家里的大朋友處理"學(xué)生綜合素質(zhì)評(píng)價(jià)信息管理系統(tǒng)"的資料上傳。系統(tǒng)有個(gè)令人無(wú)語(yǔ)的限制:圖片大小不能超過(guò)200KB。

可是現(xiàn)在的手機(jī)拍照功能太強(qiáng)大了啊!隨隨便便一張照片都是幾MB大小。于是我就陷入了一個(gè)循環(huán):

  • 拍照片 → 太大上傳失敗
  • 找在線壓縮網(wǎng)站 → 廣告彈窗滿天飛
  • 打開(kāi)Photoshop → 等半天,然后點(diǎn)半天,最后忘了保存格式
  • 最終:心態(tài)爆炸

于是我想:“我可是個(gè)程序員啊!為什么不自己寫(xiě)一個(gè)工具呢?” 于是這個(gè)20分鐘速成的圖片壓縮小工具就誕生了。

Go語(yǔ)言:程序員的瑞士軍刀

為什么用Go語(yǔ)言?因?yàn)樗娴奶『?!用!了?/p>

  • 開(kāi)箱即用:標(biāo)準(zhǔn)庫(kù)自帶圖像處理功能,完全不用找第三方包
  • 編譯超快:寫(xiě)完代碼,"go build"一下,瞬間得到一個(gè)可執(zhí)行文件
  • 跨平臺(tái):一次編寫(xiě),到處運(yùn)行,Windows、Mac、Linux通吃
  • 代碼簡(jiǎn)潔:同樣的功能,Go代碼比其他語(yǔ)言至少短一半

工作原理:雙管齊下的壓縮策略

這個(gè)工具的核心思想很簡(jiǎn)單:先調(diào)質(zhì)量,再縮尺寸。

第一階段:質(zhì)量壓縮

JPEG圖片有個(gè)質(zhì)量參數(shù)(1-100),我們從高質(zhì)量開(kāi)始,逐步降低:

  • 從95%質(zhì)量開(kāi)始嘗試
  • 如果文件大小還是超過(guò)目標(biāo),降到90%
  • 繼續(xù)降到85%…直到10%
  • 如果某個(gè)質(zhì)量下的文件大小滿足要求,直接返回

這種方法的優(yōu)點(diǎn)是不會(huì)改變圖片尺寸,只是犧牲一點(diǎn)點(diǎn)視覺(jué)質(zhì)量。

第二階段:尺寸壓縮

如果單純降低質(zhì)量還不夠,我們就開(kāi)始縮小圖片尺寸:

  • 使用二分法智能尋找最佳縮放比例
  • 從25%到100%之間搜索
  • 每次縮放后都檢查文件大小
  • 確保圖像不會(huì)被縮得太?。ㄔO(shè)置最小尺寸保護(hù))

技術(shù)亮點(diǎn)

  • 二分查找算法:比線性搜索更高效,幾輪迭代就能找到合適的尺寸
  • 邊界保護(hù):防止圖像被壓縮得太小導(dǎo)致無(wú)法識(shí)別
  • 錯(cuò)誤處理:友好的錯(cuò)誤提示,不會(huì)讓用戶一臉懵逼
  • 多種格式支持:輸入支持JPEG、PNG、GIF等多種格式

編譯方法:三步搞定

Go語(yǔ)言的編譯超級(jí)簡(jiǎn)單,只需要幾個(gè)簡(jiǎn)單的步驟:

1. 確保已安裝Go環(huán)境

首先,確保你的電腦上已經(jīng)安裝了Go。打開(kāi)命令行,輸入:

go version

如果顯示了Go的版本信息,說(shuō)明已經(jīng)安裝好了。如果沒(méi)有,請(qǐng)先去Go官網(wǎng)下載安裝。

2. 編譯程序

進(jìn)入到包含main.go的目錄,執(zhí)行以下命令:

# Windows系統(tǒng)
go build -o 圖片壓縮.exe main.go

# Mac/Linux系統(tǒng)
go build -o 圖片壓縮 main.go

編譯完成后,當(dāng)前目錄下會(huì)生成一個(gè)可執(zhí)行文件。

3. 運(yùn)行程序

編譯完成后,使用方法超級(jí)簡(jiǎn)單:

# Windows
圖片壓縮.exe <輸入文件路徑> <輸出文件路徑> <目標(biāo)大?。↘B)>

# Mac/Linux
./圖片壓縮 <輸入文件路徑> <輸出文件路徑> <目標(biāo)大?。↘B)>

例如,要把一張照片壓縮到200KB以內(nèi):

# Windows
圖片壓縮.exe 學(xué)生照片.jpg 壓縮后的照片.jpg 200

# Mac/Linux
./圖片壓縮 學(xué)生照片.jpg 壓縮后的照片.jpg 200

運(yùn)行后,工具會(huì)告訴你壓縮結(jié)果,包括最終大小和壓縮率。

總結(jié):編程解決實(shí)際問(wèn)題的快樂(lè)

這個(gè)小工具雖然簡(jiǎn)單,但它真正解決了實(shí)際問(wèn)題?,F(xiàn)在,我再也不用為了上傳一張照片而煩惱了。

這也正是編程的魅力所在:用幾行代碼,解決生活中的一個(gè)小痛點(diǎn)。而且Go語(yǔ)言讓這個(gè)過(guò)程變得如此簡(jiǎn)單和高效。

如果你也有類(lèi)似的需求,不妨試試這個(gè)工具,或者根據(jù)源碼自己定制一個(gè)適合你的版本!

完整源碼

package main

import (
	"bytes"
	"flag"
	"fmt"
	"image"
	"image/jpeg"
	"os"
	"path/filepath"
	"strconv"
)

// resizeNearest 使用最近鄰插值算法縮放圖像
// 最近鄰插值是最簡(jiǎn)單的圖像縮放算法,通過(guò)直接映射源圖像像素來(lái)實(shí)現(xiàn)縮放
// 參數(shù):
// - src: 源圖像
// - newWidth: 目標(biāo)寬度
// - newHeight: 目標(biāo)高度
// 返回值:
// - *image.NRGBA: 縮放后的圖像
func resizeNearest(src image.Image, newWidth, newHeight int) *image.NRGBA {
	// 獲取源圖像的邊界和尺寸
	srcBounds := src.Bounds()
	srcW, srcH := srcBounds.Dx(), srcBounds.Dy()

	// 創(chuàng)建目標(biāo)圖像,使用NRGBA格式(無(wú)預(yù)乘alpha的RGBA)
	dst := image.NewNRGBA(image.Rect(0, 0, newWidth, newHeight))

	// 遍歷目標(biāo)圖像的每個(gè)像素
	for y := 0; y < newHeight; y++ {
		for x := 0; x < newWidth; x++ {
			// 計(jì)算源圖像中對(duì)應(yīng)的坐標(biāo)
			srcX := int(float64(x) * float64(srcW) / float64(newWidth))
			srcY := int(float64(y) * float64(srcH) / float64(newHeight))
			
			// 邊界檢查,確保不會(huì)越界
			if srcX >= srcW {
				srcX = srcW - 1
			}
			if srcY >= srcH {
				srcY = srcH - 1
			}
			
			// 將源圖像像素顏色復(fù)制到目標(biāo)圖像
			dst.Set(x, y, src.At(srcX, srcY))
		}
	}
	return dst
}

// encodeJPEG 將圖像編碼為JPEG格式的字節(jié)數(shù)據(jù)
// 參數(shù):
// - img: 要編碼的圖像
// - quality: JPEG壓縮質(zhì)量(1-100),值越高質(zhì)量越好
// 返回值:
// - []byte: 編碼后的JPEG字節(jié)數(shù)據(jù)
func encodeJPEG(img image.Image, quality int) []byte {
	var buf bytes.Buffer
	// 使用Go標(biāo)準(zhǔn)庫(kù)的jpeg.Encode函數(shù)進(jìn)行編碼
	jpeg.Encode(&buf, img, &jpeg.Options{Quality: quality})
	return buf.Bytes()
}

// forceCompressToSize 強(qiáng)制將圖像壓縮到指定大小
// 使用兩階段壓縮策略:先嘗試調(diào)整質(zhì)量,若不行再進(jìn)行尺寸縮放
// 參數(shù):
// - img: 原始圖像
// - targetSize: 目標(biāo)文件大小(字節(jié))
// 返回值:
// - []byte: 壓縮后的圖像數(shù)據(jù)
// - error: 可能的錯(cuò)誤信息
func forceCompressToSize(img image.Image, targetSize int64) ([]byte, error) {
	// 獲取原始圖像的尺寸
	originalBounds := img.Bounds()
	origW, origH := originalBounds.Dx(), originalBounds.Dy()

	// 階段1:僅調(diào)整JPEG質(zhì)量參數(shù)(不改變圖像尺寸)
	// 從高質(zhì)量開(kāi)始嘗試,逐步降低質(zhì)量
	for q := 95; q >= 10; q -= 5 {
		data := encodeJPEG(img, q)
		// 如果當(dāng)前質(zhì)量下的文件大小已滿足要求,直接返回
		if int64(len(data)) <= targetSize {
			return data, nil
		}
	}

	// 階段2:如果僅調(diào)整質(zhì)量無(wú)法達(dá)到目標(biāo)大小,則使用二分法縮放圖像尺寸
	lowScale, highScale := 0.25, 1.0 // 縮放比例范圍 (25% - 100%)
	bestData := make([]byte, 0)       // 存儲(chǔ)最佳壓縮結(jié)果
	minDimension := 100               // 最小維度,防止圖像被過(guò)度縮小
	const maxIterations = 100         // 最大迭代次數(shù),避免死循環(huán)

	for i := 0; i < maxIterations; i++ {
		// 計(jì)算當(dāng)前的縮放比例(二分法)
		scale := (lowScale + highScale) / 2
		// 計(jì)算新的圖像尺寸
		newW := int(float64(origW) * scale)
		newH := int(float64(origH) * scale)

		// 確保圖像不會(huì)小于最小尺寸
		if newW < minDimension || newH < minDimension {
			newW, newH = minDimension, minDimension
		}

		// 縮放圖像并以固定質(zhì)量(75)編碼
		smallImg := resizeNearest(img, newW, newH)
		data := encodeJPEG(smallImg, 75)
		fileSize := int64(len(data))

		// 根據(jù)當(dāng)前文件大小調(diào)整搜索范圍
		if fileSize <= targetSize {
			// 如果符合要求,記錄最佳結(jié)果并嘗試更大的尺寸
			if len(bestData) == 0 || fileSize < int64(len(bestData)) {
				bestData = data
			}
			lowScale = scale // 嘗試更大的尺寸
		} else {
			highScale = scale // 嘗試更小的尺寸
		}

		// 當(dāng)縮放比例的精度足夠時(shí)退出循環(huán)
		if highScale-lowScale < 0.01 { // 1%的精度
			break
		}
	}

	// 如果找到合適的壓縮結(jié)果,返回最佳數(shù)據(jù)
	if len(bestData) > 0 {
		return bestData, nil
	}

	// 最后兜底策略:如果沒(méi)有找到合適的尺寸,則返回最小尺寸的圖片
	finalImg := resizeNearest(img, minDimension, minDimension)
	return encodeJPEG(finalImg, 75), nil
}

func main() {
	// 解析命令行參數(shù)
	flag.Parse()
	args := flag.Args()

	// 檢查參數(shù)數(shù)量是否正確
	if len(args) != 3 {
		fmt.Println("用法: go run main.go <輸入文件路徑> <輸出文件路徑> <目標(biāo)大?。↘B)>")
		fmt.Println("功能: 將輸入圖像壓縮到指定大小,輸出始終為JPEG格式")
		os.Exit(1)
	}
	
	// 提取參數(shù)值
	inFile := args[0]
	outFile := args[1]
	
	// 解析目標(biāo)大小
	targetKB, err := strconv.ParseInt(args[2], 10, 64)
	if err != nil {
		fmt.Println("請(qǐng)?zhí)峁┯行У哪繕?biāo)大?。↘B)")
		os.Exit(1)
	}
	
	// 將KB轉(zhuǎn)換為字節(jié)
	target := targetKB * 1024

	// 檢查輸入文件是否存在
	if _, err := os.Stat(inFile); os.IsNotExist(err) {
		fmt.Printf("錯(cuò)誤: 輸入文件 '%s' 不存在\n", inFile)
		os.Exit(1)
	}

	// 打開(kāi)輸入文件
	f, err := os.Open(inFile)
	if err != nil {
		fmt.Printf("錯(cuò)誤: 無(wú)法打開(kāi)輸入文件: %v\n", err)
		os.Exit(1)
	}
	defer f.Close() // 確保在函數(shù)結(jié)束時(shí)關(guān)閉文件

	// 解碼圖像(支持多種格式)
	img, format, err := image.Decode(f)
	if err != nil {
		fmt.Printf("錯(cuò)誤: 無(wú)法解碼圖像: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("成功讀取 %s 格式圖像\n", format)
	fmt.Printf("開(kāi)始?jí)嚎s,目標(biāo)大小: %d 字節(jié)\n", target)

	// 執(zhí)行壓縮
	data, err := forceCompressToSize(img, target)
	if err != nil {
		fmt.Printf("錯(cuò)誤: 壓縮過(guò)程中出錯(cuò): %v\n", err)
		os.Exit(1)
	}

	// 確保輸出目錄存在
	outDir := filepath.Dir(outFile)
	if outDir != "." {
		if err := os.MkdirAll(outDir, 0755); err != nil {
			fmt.Printf("錯(cuò)誤: 無(wú)法創(chuàng)建輸出目錄: %v\n", err)
			os.Exit(1)
		}
	}

	// 寫(xiě)入壓縮后的圖像數(shù)據(jù)
	err = os.WriteFile(outFile, data, 0644)
	if err != nil {
		fmt.Printf("錯(cuò)誤: 無(wú)法寫(xiě)入輸出文件: %v\n", err)
		os.Exit(1)
	}
	
	// 輸出壓縮結(jié)果信息
	fmt.Printf("壓縮完成!\n")
	fmt.Printf("最終大小: %d 字節(jié) (目標(biāo): %d 字節(jié))\n", len(data), target)
	fmt.Printf("壓縮率: %.2f%%\n", float64(len(data))/float64(target)*100)
}

到此這篇關(guān)于使用Go語(yǔ)言帶你搞定圖片壓縮指南的文章就介紹到這了,更多相關(guān)Go語(yǔ)言圖片壓縮內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語(yǔ)言中進(jìn)行API限流的實(shí)戰(zhàn)詳解

    Go語(yǔ)言中進(jìn)行API限流的實(shí)戰(zhàn)詳解

    API?限流是控制和管理應(yīng)用程序訪問(wèn)量的重要手段,旨在防止惡意濫用、保護(hù)后端服務(wù)的穩(wěn)定性和可用性,下面我們就來(lái)看看如何在Go語(yǔ)言中具體實(shí)現(xiàn)吧
    2025-01-01
  • Golang關(guān)鍵字select的常用用法總結(jié)

    Golang關(guān)鍵字select的常用用法總結(jié)

    這篇文章主要為大家詳細(xì)介紹了golang中select關(guān)鍵字的常用用法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-10-10
  • Golang中g(shù)oroutine和channel使用介紹深入分析

    Golang中g(shù)oroutine和channel使用介紹深入分析

    一次只做一件事情并不是完成任務(wù)最快的方法,一些大的任務(wù)可以拆解成若干個(gè)小任務(wù),goroutine可以讓程序同時(shí)處理幾個(gè)不同的任務(wù),goroutine使用channel來(lái)協(xié)調(diào)它們的工作,channel允許goroutine互相發(fā)送數(shù)據(jù)并同步,這樣一個(gè)goroutine就不會(huì)領(lǐng)先于另一個(gè)goroutine
    2023-01-01
  • GPT回答:go語(yǔ)言和C語(yǔ)言切片對(duì)比

    GPT回答:go語(yǔ)言和C語(yǔ)言切片對(duì)比

    這篇文章主要為大家介紹了GPT回答:go語(yǔ)言和C語(yǔ)言切片對(duì)比,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • 從零封裝Gin框架實(shí)現(xiàn)數(shù)據(jù)庫(kù)初始化GORM

    從零封裝Gin框架實(shí)現(xiàn)數(shù)據(jù)庫(kù)初始化GORM

    這篇文章主要為大家介紹了從零封裝Gin框架實(shí)現(xiàn)數(shù)據(jù)庫(kù)初始化GORM,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Go語(yǔ)言中Struct與繼承與匿名字段和內(nèi)嵌結(jié)構(gòu)體全面詳解

    Go語(yǔ)言中Struct與繼承與匿名字段和內(nèi)嵌結(jié)構(gòu)體全面詳解

    這篇文章主要介紹了Go語(yǔ)言中Struct與繼承與匿名字段和內(nèi)嵌結(jié)構(gòu)體,Go語(yǔ)言中通過(guò)結(jié)構(gòu)體的內(nèi)嵌再配合接口比面向?qū)ο缶哂懈叩臄U(kuò)展性和靈活性,感興趣的可以了解一下
    2023-04-04
  • Go語(yǔ)言中CGO的使用實(shí)踐

    Go語(yǔ)言中CGO的使用實(shí)踐

    本文主要介紹了Go語(yǔ)言中CGO的使用實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 示例剖析golang中的CSP并發(fā)模型

    示例剖析golang中的CSP并發(fā)模型

    這篇文章主要為大家介紹了示例剖析golang中的CSP并發(fā)模型,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Go 實(shí)現(xiàn)一次性打包各個(gè)平臺(tái)的可執(zhí)行程序

    Go 實(shí)現(xiàn)一次性打包各個(gè)平臺(tái)的可執(zhí)行程序

    這篇文章主要介紹了Go 實(shí)現(xiàn)一次性打包各個(gè)平臺(tái)的可執(zhí)行程序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • 基于Go語(yǔ)言實(shí)現(xiàn)類(lèi)似tree命令的小程序

    基于Go語(yǔ)言實(shí)現(xiàn)類(lèi)似tree命令的小程序

    tree?命令是一個(gè)小型的跨平臺(tái)命令行程序,用于遞歸地以樹(shù)狀格式列出或顯示目錄的內(nèi)容。本文將通過(guò)Go語(yǔ)言實(shí)現(xiàn)類(lèi)似tree命令的小程序,需要的可以參考一下
    2022-10-10

最新評(píng)論

甘德县| 扶余县| 郧西县| 桓台县| 榆中县| 彭山县| 丹寨县| 普安县| 施甸县| 丹江口市| 天祝| 贡嘎县| 云阳县| 安西县| 泾阳县| 沈阳市| 凤凰县| 普洱| 延安市| 宜黄县| 滦南县| 吉木乃县| 迭部县| 安徽省| 虎林市| 茶陵县| 贵定县| 弥勒县| 万年县| 德阳市| 湖北省| 咸阳市| 福州市| 新泰市| 峡江县| 社会| 类乌齐县| 东光县| 鹿泉市| 甘谷县| 长宁县|