Created
January 3, 2011 07:50
-
-
Save visnup/763229 to your computer and use it in GitHub Desktop.
recover jpg version of image out of corrupt/weird raw/dng tiff
This file contains 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
#!/usr/bin/env ruby | |
require 'rubygems' | |
require 'ruby-debug' | |
def out s = '' | |
puts "#{$indent}#{s}" | |
end | |
def read_ifd f, order = 'n', indent = '' | |
old_indent, $indent = $indent, indent | |
n = f.read(2).unpack(order).first | |
out | |
out "\e[42m#{n} IFD entries.\e[00m" | |
entries = f.read 12 * n | |
next_ifd = f.read(4).unpack(order.upcase).first | |
sub_ifd = nil | |
jpg_offset = jpg_length = nil | |
(0 ... n).each do |i| | |
entry = entries[12 * i, 12] | |
tag, type, count, value = entry.unpack "#{order}2#{order.upcase}2" | |
next if type == 2 | |
out "ifd#{i}" | |
out sprintf " 0x%04x %d %2d 0x%08x (%d)", tag, type, count, value, value | |
short_value = value >> 16 | |
case tag | |
when 0x106 | |
out " PhotometricInterpretation" | |
case short_value | |
when 0 | |
out " white is zero" | |
when 1 | |
out " black is zero" | |
when 2 | |
out " RGB" | |
when 32803 | |
out " CFA (Color Filter Array)" | |
else | |
out " unknown value" | |
end | |
when 0x112 | |
out " Orientation" | |
when 0x11c | |
out " PlanarConfiguration" | |
case short_value | |
when 1 | |
out " chunky" | |
else | |
out " unknown value" | |
end | |
when 0x115 | |
out " SamplesPerPixel" | |
when 0x102 | |
out " BitsPerSample" | |
when 0x103 | |
out " Compression" | |
case short_value | |
when 1 | |
out " no compression" | |
when 2 | |
out " ccitt group 3" | |
when 6 | |
out " JPEG (old)" | |
when 32773 | |
out " packbits" | |
else | |
out " unknown value" | |
end | |
when 0x101 | |
out " ImageLength" | |
when 0x100 | |
out " ImageWidth" | |
when 0x128 | |
out " ResolutionUnit" | |
case short_value | |
when 1 | |
out " no absolute unit of measurement" | |
when 2 | |
out " inch" | |
when 3 | |
out " centimeter" | |
else | |
out " unknown value" | |
end | |
when 0x11a | |
out " XResolution" | |
when 0x11b | |
out " YResolution" | |
when 0x116 | |
out " RowsPerStrip" | |
when 0x111 | |
out " StripOffsets" | |
when 0x117 | |
out " StripByteCounts" | |
when 0xfe | |
out " NewSubfileType" | |
when 0x214 | |
out " ReferenceBlackWhite" | |
when 0x10f | |
out " Make" | |
when 0x110 | |
out " Model" | |
when 0x131 | |
out " Software" | |
when 0x132 | |
out " DateTime" | |
when 0x201 | |
jpg_offset = value | |
when 0x202 | |
jpg_length = value | |
when 0x14a | |
out " \e[44mSubIFDs\e[00m" | |
f.seek value | |
offsets = f.read(4 * count).unpack "#{order.upcase}#{count}" | |
count.times do |i| | |
out " subifd#{i}: #{offsets[i]}" | |
f.seek offsets[i] | |
read_ifd f, order, indent + ' ' | |
end | |
else | |
out " \e[31mUNKNOWN\e[00m" | |
end | |
case type | |
when 2 | |
if count > 4 | |
f.seek value | |
out " \"#{f.read(count)}\"" | |
else | |
out [value].pack "c#{count-1}" | |
end | |
when 3 | |
case count | |
when 1 | |
out sprintf " 0: 0x%04x (%d)", short_value, short_value | |
when 2 | |
out sprintf " 0: 0x%04x (%d)", short_value, short_value | |
out sprintf " 1: 0x%04x (%d)", value & 0xffff, value & 0xffff | |
else | |
f.seek value | |
count.times do |i| | |
v = f.read(2).unpack(order).first | |
out sprintf " %d: 0x%04x (%d)", i, v, v | |
end | |
end | |
when 5 | |
f.seek value | |
count.times do |i| | |
n, d = f.read(8).unpack("#{order}2") | |
out " #{i}: #{n}/#{d}" | |
end | |
end | |
out | |
end | |
if jpg_offset && jpg_length | |
out " outputting jpg to jpg/#{ARGV.first}.jpg" | |
open "jpg/#{ARGV.first}.jpg", 'w' do |w| | |
f.seek jpg_offset | |
w.write f.read(jpg_length) | |
end | |
end | |
$indent = old_indent | |
next_ifd | |
end | |
open ARGV.first do |f| | |
# decode header | |
header = f.read 8 | |
order = | |
case header[0, 2] | |
when 'II' | |
puts "little-endian." | |
'v' | |
when 'MM' | |
puts "big-endian." | |
'n' | |
else | |
warn "not a tiff file\n" | |
return | |
end | |
tiff = header[2, 2].unpack(order).first | |
puts "tiff file." if tiff == 42 | |
offset = header[4, 4].unpack(order.upcase).first | |
puts "offset: #{offset}." | |
f.seek offset | |
# read image file directory (IFD) | |
next_ifd = read_ifd f, order | |
puts "next ifd: #{next_ifd}" | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment