Class: Jpegsan::Jpeg

Inherits:
Object
  • Object
show all
Defined in:
lib/jpegsan/jpeg.rb

Defined Under Namespace

Classes: JpegMarker

Constant Summary collapse

JPEG_MARKERS =
[
  JpegMarker.new(?\xc0, 'SOF0',  'non-differential, Huffman coding - Baseline DCT'),
  JpegMarker.new(?\xc1, 'SOF1',  'non-differential, Huffman coding - Extended sequential DCT'),
  JpegMarker.new(?\xc2, 'SOF2',  'non-differential, Huffman coding - Progressive DCT'),
  JpegMarker.new(?\xc3, 'SOF3',  'non-differential, Huffman coding - Lossless (sequential)'),
  JpegMarker.new(?\xc5, 'SOF5',  'differential, Huffman coding - Differential sequential DCT'),
  JpegMarker.new(?\xc6, 'SOF6',  'differential, Huffman coding - Differential progressive DCT'),
  JpegMarker.new(?\xc7, 'SOF7',  'differential, Huffman coding - Differential lossless (sequential)'),
  JpegMarker.new(?\xc8, 'JPG',   'non-differential, arithmetic coding - Reversed for JPEG extensions'),
  JpegMarker.new(?\xc9, 'SOF9',  'non-differential, arithmetic coding - Extended sequential DCT'),
  JpegMarker.new(?\xca, 'SOF10', 'non-differential, arithmetic coding - Progressive DCT'),
  JpegMarker.new(?\xcb, 'SOF11', 'non-differential, arithmetic coding - Lossless (sequential)'),
  JpegMarker.new(?\xcd, 'SOF13', 'differential, arithmetic coding - Differential sequential DCT'),
  JpegMarker.new(?\xce, 'SOF14', 'differential, arithmetic coding - Differential progressive DCT'),
  JpegMarker.new(?\xcf, 'SOF15', 'differential, arithmetic coding - Differential lossless (sequential)'),
  JpegMarker.new(?\xc4, 'DHT',   'Huffman table specification - Define Huffman table(s)'),
  JpegMarker.new(?\xcc, 'DAC',   'Arithmetic coding conditioning specification - Define arithmetic coding conditioning(s)'),
  JpegMarker.new(?\xd0, 'RST0',  'Restart interval termination - Restart with modulo count 0'),
  JpegMarker.new(?\xd1, 'RST1',  'Restart interval termination - Restart with modulo count 1'),
  JpegMarker.new(?\xd2, 'RST2',  'Restart interval termination - Restart with modulo count 2'),
  JpegMarker.new(?\xd3, 'RST3',  'Restart interval termination - Restart with modulo count 3'),
  JpegMarker.new(?\xd4, 'RST4',  'Restart interval termination - Restart with modulo count 4'),
  JpegMarker.new(?\xd5, 'RST5',  'Restart interval termination - Restart with modulo count 5'),
  JpegMarker.new(?\xd6, 'RST6',  'Restart interval termination - Restart with modulo count 6'),
  JpegMarker.new(?\xd7, 'RST7',  'Restart interval termination - Restart with modulo count 7'),
  JpegMarker.new(?\xd8, 'SOI',   'Start of image'),
  JpegMarker.new(?\xd9, 'EOI',   'End of image'),
  JpegMarker.new(?\xda, 'SOS',   'Start of scan'),
  JpegMarker.new(?\xdb, 'DQT',   'Define quantization table(s)'),
  JpegMarker.new(?\xdc, 'DNL',   'Define number of lines'),
  JpegMarker.new(?\xdd, 'DRI',   'Define restart interval'),
  JpegMarker.new(?\xde, 'DHP',   'Define hierarchical progression'),
  JpegMarker.new(?\xdf, 'EXP',   'Expand reference component(s)'),
  JpegMarker.new(?\xe0, 'APP0',  'Reserved for application segments'),
  JpegMarker.new(?\xe1, 'APP1',  'Reserved for application segments'),
  JpegMarker.new(?\xe2, 'APP2',  'Reserved for application segments'),
  JpegMarker.new(?\xe3, 'APP3',  'Reserved for application segments'),
  JpegMarker.new(?\xe4, 'APP4',  'Reserved for application segments'),
  JpegMarker.new(?\xe5, 'APP5',  'Reserved for application segments'),
  JpegMarker.new(?\xe6, 'APP6',  'Reserved for application segments'),
  JpegMarker.new(?\xe7, 'APP7',  'Reserved for application segments'),
  JpegMarker.new(?\xe8, 'APP8',  'Reserved for application segments'),
  JpegMarker.new(?\xe9, 'APP9',  'Reserved for application segments'),
  JpegMarker.new(?\xea, 'APP10', 'Reserved for application segments'),
  JpegMarker.new(?\xeb, 'APP11', 'Reserved for application segments'),
  JpegMarker.new(?\xec, 'APP12', 'Reserved for application segments'),
  JpegMarker.new(?\xed, 'APP13', 'Reserved for application segments'),
  JpegMarker.new(?\xee, 'APP14', 'Reserved for application segments'),
  JpegMarker.new(?\xef, 'APP15', 'Reserved for application segments'),
  JpegMarker.new(?\xf0, 'JPG0',  'Reserved for JPEG extensions'),
  JpegMarker.new(?\xf1, 'JPG1',  'Reserved for JPEG extensions'),
  JpegMarker.new(?\xf2, 'JPG2',  'Reserved for JPEG extensions'),
  JpegMarker.new(?\xf3, 'JPG3',  'Reserved for JPEG extensions'),
  JpegMarker.new(?\xf4, 'JPG4',  'Reserved for JPEG extensions'),
  JpegMarker.new(?\xf5, 'JPG5',  'Reserved for JPEG extensions'),
  JpegMarker.new(?\xf6, 'JPG6',  'Reserved for JPEG extensions'),
  JpegMarker.new(?\xf7, 'JPG7',  'Reserved for JPEG extensions'),
  JpegMarker.new(?\xf8, 'JPG8',  'Reserved for JPEG extensions'),
  JpegMarker.new(?\xf9, 'JPG9',  'Reserved for JPEG extensions'),
  JpegMarker.new(?\xfa, 'JPG10', 'Reserved for JPEG extensions'),
  JpegMarker.new(?\xfb, 'JPG11', 'Reserved for JPEG extensions'),
  JpegMarker.new(?\xfc, 'JPG12', 'Reserved for JPEG extensions'),
  JpegMarker.new(?\xfd, 'JPG13', 'Reserved for JPEG extensions'),
  JpegMarker.new(?\xfe, 'COM',   'Comment'),
  JpegMarker.new(?\x01, 'TEM',   'For temporary private use in arithmetic coding'),
  # Markers for "Reserved" are from X'FF02' thru X'FFBF' actually, but we have only X'FF02' for this.
  JpegMarker.new(?\x02, 'RES',   'Reserved'),
]
MARKER_BY_SUFFIX =
JPEG_MARKERS.map {|a| [a.code_suffix, a]}.to_h

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file) ⇒ Jpeg

Returns a new instance of Jpeg.



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/jpegsan/jpeg.rb', line 95

def initialize(file)
  @data = []

  items = []
  marker = false
  current_marker = nil

  file.read.chars.each do |e|
    if marker
      marker = false
      # "X'FF00' is NOT a marker but X'FF' value"
      if e == ?\x00
        items << ?\xff
        items << ?\x00
        next
      end

      # "X'FFFF' is treated as is
      if e == ?\xff
        items << ?\xff
        items << ?\xff
        next
      end

      if !items.empty?
        current_marker.data_sequence = items.join.b
        items.clear
      end

      current_marker = MARKER_BY_SUFFIX[e].dup
      if current_marker.nil?
        current_marker = JpegMarker.new(e, 'UNK', 'Unknown marker')
      end

      @data << current_marker
      next
    end

    if e == ?\xff
      marker = true
      next
    end
    items << e
  end

  if !items.empty?
    @data << items.join
  end
end

Instance Attribute Details

#dataObject

Returns the value of attribute data.



3
4
5
# File 'lib/jpegsan/jpeg.rb', line 3

def data
  @data
end

Instance Method Details

#open_fileObject



150
151
152
153
154
155
156
157
# File 'lib/jpegsan/jpeg.rb', line 150

def open_file
  if @last_filename.nil?
    STDERR.puts('WARN: No file to open')
    return
  end

  system('open', @last_filename)
end

#save(dest = 'out.jpg') ⇒ Object



145
146
147
148
# File 'lib/jpegsan/jpeg.rb', line 145

def save(dest = 'out.jpg')
  @last_filename = dest
  open(dest, 'w').write(@data.map(&:to_bytes).join)
end

#show_listObject



159
160
161
162
163
164
165
166
167
168
# File 'lib/jpegsan/jpeg.rb', line 159

def show_list
 @data.each do |e|
   STDERR.puts "= MARKER #{e.code_suffix.b.inspect}: #{e&.symbol} (#{e&.description}) ="
   if e.sequence_in_hex
     STDERR.puts e.sequence_in_hex
   end
 end

 nil
end