Skip to content

Instantly share code, notes, and snippets.

@visnup
Created January 3, 2011 07:50
Show Gist options
  • Save visnup/763229 to your computer and use it in GitHub Desktop.
Save visnup/763229 to your computer and use it in GitHub Desktop.
recover jpg version of image out of corrupt/weird raw/dng tiff
#!/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