Golang中Jpeg.decode和Jpeg.encode生成不可用数据的问题

Golang中Jpeg.decode和Jpeg.encode生成不可用数据的问题

	r := strings.Split(p.UserToEdit.PhotoString64, ",")
	if len(r) == 2 {
		imageData = r[1]
	}

	buf := bytes.NewBufferString(imageData)
	reader := base64.NewDecoder(base64.StdEncoding, buf)

	decodedImage, err := jpeg.Decode(reader)

	buff1 := new(bytes.Buffer)
	err = jpeg.Encode(buff1, decodedImage, nil)
	if buff1 == buf{
		fmt.Println("equal")
	} else{
		fmt.Println("different")
	}

我正在学习如何编码/解码图像以用于Web应用程序。在上面的代码中,p.UserToEdit.PhotoString64是一个Base64字符串,它在浏览器中可以通过以下方式正常工作: displayImage.style.backgroundImage =url({{.UserToEdit.PhotoString64}});

我尝试使用resize.Resize来调整图像大小以生成缩略图,但得到了一个无法使用的字符串。不过,我编写了上面的代码,只是为了先让解码/编码过程正常工作。当我运行这段代码时,两个缓冲区的内容差异很大。如果我能解决这个问题,或许就能成功调整图像大小了。


更多关于Golang中Jpeg.decode和Jpeg.encode生成不可用数据的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

10 回复

你确定你正确进行了Base64编码吗?

更多关于Golang中Jpeg.decode和Jpeg.encode生成不可用数据的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你的字符串表明图像是PNG格式,而不是JPEG格式。

感谢,我之前没有意识到JPEG编码之后还需要进行Base64编码。现在可以正常工作了。

rschluet:

buf1.String()

这些是随机字节,你必须对它们进行 base64 编码。

decodedImage, err := jpeg.Decode(reader)

JPEG 是有损压缩格式,因此重新编码的图像不太可能与原始图像完全相同。默认的编码质量是 75。也许将质量设置为 100 可以得到匹配的结果。

另外,你正在比较的是缓冲区的指针,它们也不会相等。可以尝试比较经过 base-64 编码后的字符串。

抱歉,不小心引入了一个PNG文件。我重新用JPEG格式运行了一下,编码后的图像以以下内容开头: data:image/jpeg;base64,����\u0000�\u0000\u

我正在编写处理JPEG、PNG和GIF格式的代码,但到目前为止还没有任何一种格式能正常工作。

感谢您的回复。我查看了缓冲区,它们确实不同。解码后的图像在浏览器中无法显示。结果只是一个空图像,并且网络检查器中出现了错误:无效字符。此外,查看网络检查器中的base64字符串,原始图像数据显示所有可打印字符,以以下内容开头:data:image/png;base64,/9j/4AAQSkZJRgABAQEAS。而编码/解码后的字符串大部分是不可打印的字符,以以下内容开头:data:image/png;base64,����\u0000�\u0000\u0008

好的,我从一个在浏览器中有效的编码字符串开始。我正在整理一个更长的代码片段来展示我所做的所有事情。我很快就会准备好…

以下是用户选择要上传的文件后运行的JavaScript代码,并且它能正确显示。

        function processFile(imageInput) {

            const reader = new FileReader()
            reader.addEventListener("load", () => {
                uploaded_image = reader.result;
                let displayImage = document.querySelector("#display_image");
                displayImage.style.backgroundImage = `url(${uploaded_image})`;
                displayImage.value = uploaded_image;
                console.log(displayImage);
            });
            reader.readAsDataURL(imageInput.files[0]);
        }

然后我将其保存到数据库中。之后,我检索该字符串并将其发送到浏览器,浏览器能正确显示它。但当我解码它、调整其大小、然后重新编码时,似乎遇到了问题。这个过程产生了一个无法在浏览器中查看的字符串。

以下是我的函数代码:

func processImage(p *generalLedgerPage) {

	if len(p.UserToEdit.PhotoString64) == 0 {
		return
	}
	log.Println("processImage: ", p.UserToEdit.PhotoString64)
	// 移除头部信息,例如:data:image/jpeg;base64, ...
	var imageData string
	r := strings.Split(p.UserToEdit.PhotoString64, ",")
	if len(r) == 2 {
		imageData = r[1]
	}

	fileType := ""
	buf := bytes.NewBufferString(imageData)
	reader := base64.NewDecoder(base64.StdEncoding, buf)
	decodedImage, err := jpeg.Decode(reader)
	if err != nil {
		log.Println("jpeg.Decode failed error: ", err)
		decodedImage, err = png.Decode(reader)
		if err != nil {
			log.Println("png.Decode failed error: ", err)
			decodedImage, err = gif.Decode(reader)
			if err != nil {
				log.Println("gif.Decode failed error: ", err)
			} else {
				fileType = "gif"
			}
		} else {
			fileType = "png"
		}
	} else {
		fileType = "jpg"
	}

	if err == nil {
		log.Println("decodedImage.Bounds(): ", decodedImage.Bounds())
	}

	//reader := base64.NewDecoder(base64.StdEncoding, strings.NewReader(p.UserToEdit.PhotoString64))
	// 这将重置位置到起始点
	buf = bytes.NewBufferString(imageData)
	reader = base64.NewDecoder(base64.StdEncoding, buf)

	config, err := jpeg.DecodeConfig(reader)
	if err != nil {
		log.Println("error jpeg.DecodeConfig: ", err)
		config, err = png.DecodeConfig(reader)
		if err != nil {
			log.Println("error png.DecodeConfig: ", err)
			config, err = gif.DecodeConfig(reader)
			if err != nil {
				log.Println("error gif.DecodeConfig: ", err)
			}
		}
	}
	if config.Width > 0 {
		log.Println("jpeg.DecodeConfig success config: ", config)
		log.Println("Width:", config.Width, "Height:", config.Height)
	}


	buf1 := new(bytes.Buffer)
	var resizedImage image.Image
	if err == nil {
		resizedImage = resize.Resize(uint(100), 0, decodedImage, resize.Lanczos3)

		switch fileType {
		case "jpg":
			err = jpeg.Encode(buf1, resizedImage, nil)
			break
		case "png":
			err = png.Encode(buf1, resizedImage)
			break
		case "gif":
			err = gif.Encode(buf1, resizedImage, nil)
			break
		}

		if err != nil {
			log.Println("Encode error: ", err)
		}
	}

	if err == nil {
		p.UserToEdit.ThumbNailString64 = r[0] + "," + buf1.String()
		//p.UserToEdit.ThumbNailString64 = buff1.String()
		log.Println("p.UserToEdit.ThumbNailString64: ", p.UserToEdit.ThumbNailString64)
	}

}

传入的文件以以下内容开头: data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEASABIAAD 文件的其余部分都是可打印字符。

生成的文件 p.UserToEdit.ThumbNailString64 以以下内容开头: data:image/jpeg;base64,ÿØÿۄaaaa 后面跟着许多不可打印字符,这基本上会导致尝试处理它的浏览器窗口崩溃。

在JPEG编解码过程中,即使图像内容看起来相同,编码后的字节数据也可能不同。这是因为JPEG编码器在压缩时可能会使用不同的量化表、霍夫曼表或元数据。你的代码中比较缓冲区内容的方式需要调整。

以下是修正后的代码示例:

package main

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"image/jpeg"
	"strings"
)

func main() {
	// 模拟的Base64图像数据(实际使用时替换为p.UserToEdit.PhotoString64)
	photoString64 := "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k="
	
	r := strings.Split(photoString64, ",")
	var imageData string
	if len(r) == 2 {
		imageData = r[1]
	}

	// 解码Base64
	buf := bytes.NewBufferString(imageData)
	reader := base64.NewDecoder(base64.StdEncoding, buf)

	// 解码JPEG
	decodedImage, err := jpeg.Decode(reader)
	if err != nil {
		fmt.Printf("解码失败: %v\n", err)
		return
	}

	// 重新编码JPEG
	buff1 := new(bytes.Buffer)
	err = jpeg.Encode(buff1, decodedImage, nil)
	if err != nil {
		fmt.Printf("编码失败: %v\n", err)
		return
	}

	// 比较原始Base64数据和新编码的Base64数据
	originalBytes, _ := base64.StdEncoding.DecodeString(imageData)
	
	if bytes.Equal(originalBytes, buff1.Bytes()) {
		fmt.Println("字节数据完全相同")
	} else {
		fmt.Printf("字节数据不同 - 原始长度: %d, 新编码长度: %d\n", 
			len(originalBytes), buff1.Bytes())
		
		// 验证新编码的数据是否有效
		_, err := jpeg.Decode(bytes.NewReader(buff1.Bytes()))
		if err != nil {
			fmt.Printf("新编码的数据无效: %v\n", err)
		} else {
			fmt.Println("新编码的数据是有效的JPEG图像")
			
			// 生成可用的Base64字符串
			newBase64 := base64.StdEncoding.EncodeToString(buff1.Bytes())
			fmt.Printf("data:image/jpeg;base64,%s\n", newBase64)
		}
	}
}

如果你要调整图像大小,这里是一个完整的示例:

package main

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"image/jpeg"
	"strings"
	
	"github.com/nfnt/resize"
)

func processImage(photoString64 string, width, height uint) (string, error) {
	// 分离Base64数据
	r := strings.Split(photoString64, ",")
	if len(r) != 2 {
		return "", fmt.Errorf("无效的Base64字符串格式")
	}
	imageData := r[1]

	// 解码Base64
	decodedBytes, err := base64.StdEncoding.DecodeString(imageData)
	if err != nil {
		return "", fmt.Errorf("Base64解码失败: %v", err)
	}

	// 解码JPEG图像
	img, err := jpeg.Decode(bytes.NewReader(decodedBytes))
	if err != nil {
		return "", fmt.Errorf("JPEG解码失败: %v", err)
	}

	// 调整图像大小
	resizedImg := resize.Resize(width, height, img, resize.Lanczos3)

	// 编码为JPEG
	var buf bytes.Buffer
	err = jpeg.Encode(&buf, resizedImg, &jpeg.Options{Quality: 85})
	if err != nil {
		return "", fmt.Errorf("JPEG编码失败: %v", err)
	}

	// 生成Base64字符串
	newBase64 := base64.StdEncoding.EncodeToString(buf.Bytes())
	return "data:image/jpeg;base64," + newBase64, nil
}

func main() {
	photoString64 := "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k="
	
	resizedImage, err := processImage(photoString64, 100, 100)
	if err != nil {
		fmt.Printf("处理失败: %v\n", err)
		return
	}
	
	fmt.Printf("调整大小后的图像: %s...\n", resizedImage[:100])
}

运行go mod init example && go get github.com/nfnt/resize来安装resize包。

回到顶部