Created
September 17, 2012 02:53
-
-
Save mirakui/3735311 to your computer and use it in GitHub Desktop.
Extract width and height from JPEG format
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
module JpegMarkers | |
MARKERS = Hash[*%W( | |
SOF0 \xff\xc0 | |
SOF1 \xff\xc1 | |
SOF2 \xff\xc2 | |
SOF3 \xff\xc3 | |
DHT \xff\xc4 | |
SOF5 \xff\xc5 | |
SOF6 \xff\xc6 | |
SOF7 \xff\xc7 | |
JPG \xff\xc8 | |
SOF9 \xff\xc9 | |
SOF10 \xff\xca | |
SOF11 \xff\xcb | |
DAC \xff\xcc | |
SOF13 \xff\xcd | |
SOF14 \xff\xce | |
SOF15 \xff\xcf | |
RST0 \xff\xd0 | |
RST1 \xff\xd1 | |
RST2 \xff\xd2 | |
RST3 \xff\xd3 | |
RST4 \xff\xd4 | |
RST5 \xff\xd5 | |
RST6 \xff\xd6 | |
RST7 \xff\xd7 | |
SOI \xff\xd8 | |
EOI \xff\xd9 | |
SOS \xff\xda | |
DQT \xff\xdb | |
DNL \xff\xdc | |
DRI \xff\xdd | |
DHP \xff\xde | |
EXP \xff\xdf | |
APP0 \xff\xe0 | |
APP1 \xff\xe1 | |
APP2 \xff\xe2 | |
APP3 \xff\xe3 | |
APP4 \xff\xe4 | |
APP5 \xff\xe5 | |
APP6 \xff\xe6 | |
APP7 \xff\xe7 | |
APP8 \xff\xe8 | |
APP9 \xff\xe9 | |
APP10 \xff\xea | |
APP11 \xff\xeb | |
APP12 \xff\xec | |
APP13 \xff\xed | |
APP14 \xff\xee | |
APP15 \xff\xef | |
JPG0 \xff\xf0 | |
JPG1 \xff\xf1 | |
JPG2 \xff\xf2 | |
JPG3 \xff\xf3 | |
JPG4 \xff\xf4 | |
JPG5 \xff\xf5 | |
JPG6 \xff\xf6 | |
JPG7 \xff\xf7 | |
JPG8 \xff\xf8 | |
JPG9 \xff\xf9 | |
JPG10 \xff\xfa | |
JPG11 \xff\xfb | |
JPG12 \xff\xfc | |
JPG13 \xff\xfd | |
COM \xff\xfe | |
TEM \xff\x01 | |
RES1 \xff\x02 | |
RES2 \xff\xbf | |
)] | |
MARKERS.each do |k,v| | |
const_set k, v | |
end | |
def marker?(bytes) | |
MARKERS.values.include? bytes | |
end | |
def sof?(bytes) | |
(0..15).any? {|i| MARKERS["SOF#{i}"] == bytes } | |
end | |
def inspect_marker(chr) | |
key = MARKERS.key(chr) | |
if key | |
"#{key}(#{chr.unpack('n').first.to_s(16)})" | |
else | |
chr.inspect | |
end | |
end | |
end |
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
require_relative './jpeg_markers.rb' | |
class JpegParser | |
include JpegMarkers | |
attr_reader :data | |
class ParseError < Exception; end | |
def initialize(io) | |
@io = io | |
@context_stack = [] | |
@data = {} | |
end | |
def parse | |
read 2 | |
assert SOI | |
parse_frame | |
@data | |
end | |
def parse_frame | |
read 2 | |
parse_extra | |
parse_frame_header | |
end | |
def parse_extra | |
while marker?(current) && !sof?(current) | |
context "#{inspect_marker(current)}" do | |
length = read_int(2) - 2 | |
log "length: #{length}" | |
skip length | |
end | |
read 2 | |
end | |
end | |
def parse_frame_header | |
assert true, sof?(current) | |
context "frame_header" do | |
length = read_int(2) - 2 | |
log "length: #{length}" | |
skip 1 | |
@data[:height] = read_int 2 | |
@data[:width] = read_int 2 | |
skip length - 5 | |
end | |
end | |
def current | |
@current | |
end | |
def log(msg) | |
header = @context_stack.map {|c| "[#{c}]" }.join | |
puts [header, msg].join(' ') | |
end | |
def context(name) | |
@context_stack << name | |
yield | |
@context_stack.pop | |
end | |
def read_int(bytes) | |
read(bytes).unpack('n').first | |
end | |
def read(bytes) | |
@current = @io.read bytes | |
log "read(#{bytes}): #{inspect_marker(@current)}" | |
@current | |
end | |
def skip(bytes) | |
@io.read bytes | |
log "skip(#{bytes})" | |
end | |
def assert(expected, actual=nil) | |
actual ||= current | |
if expected != actual | |
msg = <<-END | |
Parse error at #{@io.pos} bytes: | |
got: #{inspect_marker(actual)} | |
expected: #{inspect_marker(expected)} | |
END | |
raise ParseError, msg | |
end | |
end | |
end | |
reader = JpegParser.new ARGF | |
data = reader.parse | |
p data |
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
$ ruby jpeg_parser.rb input.jpg | |
read(2): SOI(ffd8) | |
read(2): APP0(ffe0) | |
[APP0(ffe0)] read(2): "\x00\x10" | |
[APP0(ffe0)] length: 14 | |
[APP0(ffe0)] skip(14) | |
read(2): APP2(ffe2) | |
[APP2(ffe2)] read(2): "\x02@" | |
[APP2(ffe2)] length: 574 | |
[APP2(ffe2)] skip(574) | |
read(2): APP1(ffe1) | |
[APP1(ffe1)] read(2): "\x00t" | |
[APP1(ffe1)] length: 114 | |
[APP1(ffe1)] skip(114) | |
read(2): DQT(ffdb) | |
[DQT(ffdb)] read(2): "\x00C" | |
[DQT(ffdb)] length: 65 | |
[DQT(ffdb)] skip(65) | |
read(2): DQT(ffdb) | |
[DQT(ffdb)] read(2): "\x00C" | |
[DQT(ffdb)] length: 65 | |
[DQT(ffdb)] skip(65) | |
read(2): SOF0(ffc0) | |
[frame_header] read(2): "\x00\x11" | |
[frame_header] length: 15 | |
[frame_header] skip(1) | |
[frame_header] read(2): "\x05\xAD" | |
[frame_header] read(2): "\x04>" | |
[frame_header] skip(10) | |
{:height=>1453, :width=>1086} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment