Last active
September 5, 2021 15:54
-
-
Save 2minchul/ee72c5e23207737b7bf8219d9135cab4 to your computer and use it in GitHub Desktop.
get jpg size without full read. written in Golang
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"errors" | |
"io" | |
"os" | |
) | |
type ImageSize struct { | |
Width int | |
Height int | |
} | |
var InvalidImage = errors.New("invalid image") | |
func readByte(reader io.Reader) (byte, error) { | |
b := make([]byte, 1) | |
_, err := reader.Read(b) | |
if err != nil { | |
return 0, err | |
} | |
return b[0], nil | |
} | |
func readBytes(reader io.Reader, size int) ([]byte, error) { | |
b := make([]byte, size) | |
_, err := reader.Read(b) | |
if err != nil { | |
return nil, err | |
} | |
return b, nil | |
} | |
func readUInt16BE(data []byte) int { | |
return int(data[1]) | (int(data[0]) << 8) | |
} | |
func getImageSize(reader io.Reader) (*ImageSize, error) { | |
data, err := readBytes(reader, 2) | |
if err != nil { | |
return nil, err | |
} | |
if data[0] != 0xFF || data[1] != 0xD8 { | |
return nil, InvalidImage | |
} | |
for { | |
code, err := readByte(reader) | |
if err != nil { | |
return nil, err | |
} | |
if code != 0xFF { | |
return nil, InvalidImage | |
} | |
code, err = readByte(reader) | |
if err != nil { | |
return nil, err | |
} | |
// skip padding bytes | |
for code == 0xFF { | |
code, err = readByte(reader) | |
if err != nil { | |
return nil, err | |
} | |
} | |
var length int | |
// standalone markers, according to JPEG 1992, | |
// http://www.w3.org/Graphics/JPEG/itu-t81.pdf, see Table B.1 | |
if (0xD0 <= code && code <= 0xD9) || code == 0x01 { | |
length = 0 | |
} else if 0xC0 <= code && code <= 0xFE { | |
// the rest of the unreserved markers | |
data, err = readBytes(reader, 2) | |
if err != nil { | |
return nil, err | |
} | |
length = readUInt16BE(data) - 2 | |
} else { | |
// unknown markers | |
return nil, InvalidImage | |
} | |
if code == 0xD9 || code == 0xDA { | |
// end of the data stream | |
return nil, InvalidImage | |
} | |
data, err = readBytes(reader, length) | |
if err != nil { | |
return nil, err | |
} | |
if length >= 5 && | |
(0xC0 <= code && code <= 0xCF) && | |
code != 0xC4 && code != 0xC8 && code != 0xCC { | |
return &ImageSize{ | |
Width: readUInt16BE(data[3:]), | |
Height: readUInt16BE(data[1:]), | |
}, nil | |
} | |
} | |
} | |
func main() { | |
f, err := os.Open("example.jpeg") | |
if err != nil { | |
panic(err) | |
} | |
s, err := getImageSize(f) | |
if err != nil { | |
panic(err) | |
} | |
println(s.Width, s.Height) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment