Module: Termpix::Protocols::W3m

Defined in:
lib/termpix/protocols.rb

Overview

w3mimgdisplay Protocol

Class Method Summary collapse

Class Method Details

.clear(x:, y:, width:, height:, term_width:, term_height:) ⇒ Object



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/termpix/protocols.rb', line 216

def self.clear(x:, y:, width:, height:, term_width:, term_height:)
  # Clear only the image overlay in the specified area
  terminfo = `xwininfo -id $(xdotool getactivewindow 2>/dev/null) 2>/dev/null`
  return true unless terminfo && !terminfo.empty?

  w_match = terminfo.match(/Width: (\d+)/)
  h_match = terminfo.match(/Height: (\d+)/)
  return true unless w_match && h_match
  term_w = w_match[1].to_i
  term_h = h_match[1].to_i

  # Calculate character dimensions
  char_w = term_w / term_width
  char_h = term_h / term_height

  # Convert to pixel coordinates with slight margin adjustment
  img_x = (char_w * x) - char_w
  img_y = char_h * y
  img_max_w = (char_w * width) + char_w + 2
  img_max_h = char_h * height + 2

  # Use w3mimgdisplay command "6" to clear just the image area
  cmd = "6;#{img_x};#{img_y};#{img_max_w};#{img_max_h};\n4;\n3;\n"
  IO.popen([@imgdisplay], 'w', err: '/dev/null') { |io| io.write(cmd) }
  true
end

.display(image_path, x:, y:, max_width:, max_height:) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/termpix/protocols.rb', line 147

def self.display(image_path, x:, y:, max_width:, max_height:)
  # Get terminal pixel dimensions
  terminfo = `xwininfo -id $(xdotool getactivewindow 2>/dev/null) 2>/dev/null`
  return unless terminfo && !terminfo.empty?

  w_match = terminfo.match(/Width: (\d+)/)
  h_match = terminfo.match(/Height: (\d+)/)
  return unless w_match && h_match
  term_w = w_match[1].to_i
  term_h = h_match[1].to_i

  # Calculate character dimensions
  cols = `tput cols`.to_i
  cols = 80 if cols <= 0
  lines = `tput lines`.to_i
  lines = 24 if lines <= 0
  char_w = term_w / cols
  char_h = term_h / lines

  # Convert to pixel coordinates
  img_x = char_w * x
  img_y = char_h * y
  img_max_w = char_w * max_width
  img_max_h = char_h * max_height

  # Check if image has EXIF orientation data before auto-orienting
  # This avoids unnecessary temp file creation for most images
  escaped = Shellwords.escape(image_path)

  # Quick check: only auto-orient if image has EXIF orientation tag
  has_orientation = `identify -format "%[EXIF:Orientation]" #{escaped}[0] 2>/dev/null`.strip

  if has_orientation && !has_orientation.empty? && has_orientation != "1"
    # Image needs rotation - create cached temp file
    require 'digest'
    file_hash = Digest::MD5.hexdigest(image_path)
    temp_file = "/tmp/termpix_#{file_hash}.jpg"

    unless File.exist?(temp_file)
      system("convert #{escaped}[0] -auto-orient #{temp_file} 2>/dev/null")
    end

    display_path = File.exist?(temp_file) ? temp_file : image_path
  else
    # No rotation needed - use original image
    display_path = image_path
  end

  dimensions = `identify -format "%wx%h" #{Shellwords.escape(display_path)}[0] 2>/dev/null`.strip
  return if dimensions.empty? || !dimensions.match?(/\A\d+x\d+\z/)

  img_w, img_h = dimensions.split('x').map(&:to_i)

  # Scale if needed - preserve aspect ratio
  if img_w > img_max_w || img_h > img_max_h
    scale_w = img_max_w.to_f / img_w
    scale_h = img_max_h.to_f / img_h
    scale = [scale_w, scale_h].min
    img_w = (img_w * scale).to_i
    img_h = (img_h * scale).to_i
  end

  # Display using w3mimgdisplay protocol
  cmd = "0;1;#{img_x};#{img_y};#{img_w};#{img_h};;;;;#{display_path}\n4;\n3;\n"
  IO.popen([@imgdisplay], 'w', err: '/dev/null') { |io| io.write(cmd) }

  # Don't delete temp file - keep it cached for performance
end