首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Go图像字节和Python PIL tobytes生成不同的字节数据

Go图像字节和Python PIL tobytes生成不同的字节数据
EN

Stack Overflow用户
提问于 2021-07-03 05:30:41
回答 2查看 181关注 0票数 0

我接管了一些代码,这些代码以前是由别人用python编写的,而no是由我自己编写的。

这段代码的一部分是打开一个图像,读取它的数据,并生成一个MD5散列以防止重复。

这段代码的python版本使用了PIL:

代码语言:javascript
复制
from PIL import Image
f = Image.open('2d16395b-da48-11eb-8cbe-36a331f79a1e.png')
hashlib.md5(f.tobytes()).hexdigest()
'c699a448b38df386d036ed418d7714f3'

而go版本只是将字节读取到md5散列中

代码语言:javascript
复制
    f, _ := os.Open(p)
    _, err := f.Seek(0, io.SeekStart)
    if err != nil {
        fmt.Println(err)
    }

    h := md5.New()
    if _, err := io.Copy(h, f); err != nil {
        log.Fatal(err)
    }

    hb := h.Sum(nil)
    hash := hex.EncodeToString(hb)

但是,它们会产生不同的MD5。

似乎PIL库正在以不同的方式准备字节,也许剥离了头/元数据或其他什么?

有没有人知道一种方法,我可以在go中复制PIL的字节读取来获得相同的MD5散列?

EN

回答 2

Stack Overflow用户

发布于 2021-07-03 05:51:52

我将从我使用的(虚拟)测试映像开始:

这是只有2种颜色的32X16 (RGBA) .png:

  • 红(237,28,36)
  • 蓝(0,0,255)

回到问题:[ReadTheDocs.Pillow]: Image.load() (由open隐式调用)处理(解码)图像,产生与(编码的)文件内容完全不同的原始位图数据。

这是两者之间的区别。

code00.py

代码语言:javascript
复制
#!/usr/bin/env python

import sys
from PIL import Image
from hashlib import md5


def read_file_data(file_name):
    with open(file_name, "rb") as fin:
        return fin.read()


def read_img_data(file_name):
    with Image.open(file_name) as img:
        return img.tobytes()


def process_bytes(buf, first=20, last=20):
    print("Len: {:d}\nFirst bytes:\n  ".format(len(buf)), end=" ")
    for i in range(first):
        print("0x{:02X}".format(buf[i]), end=" ")
    print("\nLast bytes:\n  ", end=" ")
    for i in range(-last, 0, 1):
        print("0x{:02X}".format(buf[i]), end=" ")
    print("\nMD5: {:}".format(md5(buf).hexdigest()))


def main(*argv):
    img_name = "rb.png"
    funcs = [
        read_file_data,
        read_img_data,
    ]
    for func in funcs:
        print("\nFunction {:s}".format(func.__name__))
        b = func(img_name)
        process_bytes(b)


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.")
    sys.exit(rc)

输出

在粘贴到cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q068231412> "e:\Work\Dev\VEnvs\py_pc064_03.08.07_test0\Scripts\python.exe“StackOverflow 00.py cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q068231412> 3.8.7 (tags/v3.8.7:6503f05,Dec 21 2020,17:59:51) MSC v.1928 64位(AMD64) 064位win32函数read_file_data: Len: 169第一个字节: 0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A 0x00 0x00 0x0D 0x49 0x48 0x44 0x52 0x00 0x00 0x00 0x10最后几个字节: 0xE2 0x8A 0x24 0x69 0x53 0x4C 0xB3 0x03 0x00 0x00 0x00 0x49 0x45 0x4E 0x44 0xAE 0x42 0x60 0x82 MD5: 8368b5c29a12b298cea2adb32955830函数read_img_data: Len: 2048第一个字节: 0xED 0x1C 0x24 64 0x0x1C 0x24 64 0x0x1C 0x24 64 0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x4E 0x40x00x0A 0x1A 0x0A 0x00 0x00 0x0A 0x0A 0x0A 0x00 0x0D 0x49 0x00 0x00 0x0D 0x49 0x00 0x00 0x0D 0x49 0x00 0x00 0x0D 0x4D 0x0x00 0x00 0xFF 0xFF 0x00 0x00 0xFF 0xFF 0x00 0x00 0xFF 0xFF 0x00 0x00 0xFF 0xFF 0x00 0x00 0xFF 0xFF 0x00 0x00 0xFF MD5: ebdf44b7ad36d79b221a70ea2b0fa0c7完成。

经过几个小时的研究(试验和错误,Google_ing,阅读_doc_s和示例-我不能在这里不提[SO]: Get a pixel array from from golang image.Image (@ArunaHerath's answer)),我能够将上面的脚本翻译成_Go。

code00.go

代码语言:javascript
复制
package main

import (
    "crypto/md5"
    "fmt"
    "image"
    "image/draw"
    "io/ioutil"
    "os"

    _ "image/gif"
    _ "image/jpeg"
    _ "image/png"
)

type ImageFunc func(string) []byte
type ImageFuncs []ImageFunc

func ReadFileData(fileName string) []byte {
    buf, _ := ioutil.ReadFile(fileName)
    return buf
}

func ReadImgData(fileName string) []byte {
    reader, _ := os.Open(fileName)
    defer reader.Close()
    img, _, _ := image.Decode(reader)
    rect := img.Bounds()
    rgba := image.NewRGBA(rect)
    draw.Draw(rgba, rect, img, rect.Min, draw.Src)
    //fmt.Printf("%v\n", rgba.Pix)
    return rgba.Pix
}

func ProcessBytes(buf []byte, first int, last int) {
    lb := len(buf)
    fmt.Printf("Len: %d\nFirst bytes:\n  ", lb)
    for i := 0; i < first; i++ {
        fmt.Printf("0x%02X ", buf[i])
    }
    fmt.Printf("\nLast bytes:\n  ")
    for i := lb - last; i < lb; i++ {
        fmt.Printf("0x%02X ", buf[i])
    }
    fmt.Printf("\nMD5: %x", md5.Sum(buf))
}

func main() {
    imgName := "rb.png"
    first := 20
    last := 20
    funcs := ImageFuncs{
        ReadFileData,
        ReadImgData,
    }
    for idx := range funcs {
        function := funcs[idx]
        fmt.Printf("\n\nFunction %#v:\n", function)
        b := function(imgName)
        ProcessBytes(b, first, last)
    }
    fmt.Printf("\n\nDone.\n")
}

输出

prompt> "f:\Install\pc064\Google\GoLang\1.16.5\bin\go.exe“运行代码00.go函数(main.ImageFunc)(0x9f1060):Len: 169第一个字节: 0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A 0x00 0x00 0x00 0x0D 0x49 0x48 0x44 0x52 0x00 0x00 0x00 0x10最后一个字节: 0xE2 0x8A 0x24 0x69 0x53 0x4C 0xB3 0x03 0x00 0x00 0x00 0x49 0x45 0x4E 0x44 0xAE 0x42 0x60 0x82 MD5: 8368b5c29a12b298cea2ad4b32955830函数(main.ImageFunc)(0x9f10e0):Len: 2048第一个字节: 0xED 0x1C 0x00 0xED 0xED 0x1C0x24 0xFF 0xED 0x1C 0x24 0xFF 0xED 0x1C 0x24 0xFF 0xED 0x1C 0x24 0xFF最后字节: 0x00 0x00 0xFF 0xFF 0x00 0x00 0xFF 0xFF 0x00 0x00 0xFF 0xFF 0x00 0x00 0xFF 0xFF 0x00 0x00 0xFF 0x00 0x00 0xFF 0xFF MD5: ebdf44b7ad36d79b221a70ea2b0fa0c7完成。

笔记

  • Important:我只测试了(虚拟) RGBA图像的代码,对于其他颜色格式,它可能需要额外的工作
  • 正如所见,我没有做任何错误处理,以保持代码简短(但不管怎样,这超出了这个问题的范围)
票数 2
EN

Stack Overflow用户

发布于 2021-07-04 02:05:28

这里有一个根本性的误解。

一个JPEG/PNG/TIFF文件是磁盘上的编码的。它包含以下部分或全部内容:

  • 图像宽度和高度
  • 图像颜色空间和压缩表
  • date of creation
  • GPS

前几个字节将是一个JPEG/PNG幻数(或签名),后面是其他PNG块或JPEG部分,包含上面列出的信息。

转换为字节后的PIL Image只包含未压缩的像素。前几个字节将是左上角的像素,接下来的几个字节将是第一行中的第二个像素。

它们是fundamentally不同的,并且永远不会有相同的MD5校验和。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68231412

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档