cheap-impression-presenter 1.1.3 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 559b5a0157ab1677e1e1f57de21cb22327e6b779ef25da65124e5e02f115585f
4
- data.tar.gz: 4e92ed0ae3c091965b6df6444200b56c240046194646ede5d1637faf165e4a95
3
+ metadata.gz: 4209c6083d151bd361c30b8f9023a0423129a9c574dbbbbf1a985604b92ce613
4
+ data.tar.gz: fdeae446fbbab6131e8c9057f8497742216e236e23c435fda32faebb3d13eb50
5
5
  SHA512:
6
- metadata.gz: 43bdfcddc75072ec0d3767bbb58802c55af33973ceeed469ee3eb9a3ddbfa49cc947b56b629f97184562295a25a98cc5d5b9b3720dfe1fff2088f8491e54c8f1
7
- data.tar.gz: af3794816e59ea883cfd2149c43350cd22298013a79d9d854db5fba7e0250aff35835952eb0e1fd1c4c75049bf685315dd16f3ef0ab72adc6aba04807f553237
6
+ metadata.gz: 9871191241cc17fff202da966deafa55bc51f05300d02d19608e165d1cb52f902ec8a859787f08091ba2f49d086a399769d770eccec0c68e87ad39e1b25eb29b
7
+ data.tar.gz: ed9f7d89cd31fc5f9f97257795d2116b38aac833b475e8ca37076932aa55b3e4d9356d8803368cdde545d09060aa5dc43650d7b13b4600a78e932af859870c51
data/INSTALL.md CHANGED
@@ -6,11 +6,17 @@ It wont work in a windows terminal for now.
6
6
 
7
7
  You can utilize 'figlet' (chimp has a plugin).
8
8
 
9
- You can utilize 'img2sixel' if you want to display graphics on your terminal
10
- (chimp has a sixel plugin).
9
+ You can utilize 'img2sixel' if you want to display graphics on a terminal with
10
+ sixel support (chimp has a sixel plugin).
11
11
 
12
- You can utilize 'inkscape' if you want to display svgs as sixel graphics on
13
- your terminal, or include them in the PDF output (chimp has a sixel plugin).
12
+ You can utilize 'magick' (ImageMagick 7) if you want to display graphics on a
13
+ terminal with kitty graphics support, e.g. kitty, Ghostty, WezTerm (chimp has a
14
+ kitty plugin).
15
+
16
+ The pic plugin uses whichever of the two your terminal supports.
17
+
18
+ You can utilize 'inkscape' if you want to display svgs as graphics on your
19
+ terminal, or include them in the PDF output.
14
20
 
15
21
  The PDF output (chimp -o pdf) uses the DejaVu Sans Mono font if it is
16
22
  installed. Otherwise Courier is used, which lacks some characters (e.g. box
data/README.md CHANGED
@@ -17,11 +17,17 @@ features need external programs, which have to be installed separately (all are
17
17
  available in the usual linux distributions and homebrew):
18
18
 
19
19
  * ``figlet``: for the figlet plugin.
20
- * ``img2sixel`` (from libsixel): for the sixel plugin, i.e. pictures in the terminal.
21
- Your terminal also needs sixel support. On linux a VTE based terminal with
22
- sixel enabled works well, e.g. Black Box
23
- (https://flathub.org/apps/com.raggesilver.BlackBox), where sixel has to be
24
- switched on in the preferences.
20
+ * Pictures in the terminal need a terminal that supports either sixel or the
21
+ kitty graphics protocol. The pic plugin finds out which one your terminal
22
+ has and uses it, so you only need the program for that one:
23
+ * ``img2sixel`` (from libsixel): for sixel (the sixel plugin). On linux a
24
+ VTE based terminal with sixel enabled works well, e.g. Black Box
25
+ (https://flathub.org/apps/com.raggesilver.BlackBox), where sixel has to be
26
+ switched on in the preferences.
27
+ * ``magick`` (ImageMagick 7): for the kitty graphics protocol (the kitty
28
+ plugin), e.g. in kitty (https://sw.kovidgoyal.net/kitty/), Ghostty
29
+ (https://ghostty.org) or WezTerm (https://wezterm.org). Pictures are sent
30
+ through the terminal, so this also works via ssh.
25
31
  * ``inkscape``: for svg pictures, in the terminal as well as in the PDF output.
26
32
  * DejaVu Sans Mono font: for the PDF output. If it is not installed, Courier is
27
33
  used, which lacks some characters (e.g. box drawing).
@@ -51,6 +57,11 @@ their own center parameter.
51
57
 
52
58
  Everything else is in plugins. The following plugins are existing for now:
53
59
 
60
+ * Pic: display graphics in the terminal, with whatever the terminal supports
61
+ (kitty graphics protocol or sixel, kitty if both, nothing if neither):
62
+ `` ```pic,20 name.png``. This is the one to use, it takes the same
63
+ parameters as Sixel (see below). If the detection is wrong, set
64
+ ``CHIMP_PIC`` to ``kitty``, ``sixel`` or ``none``.
54
65
  * Sixel: display graphics in the terminal: `` ```sixel,20 name.png``.
55
66
  * The parameter 20 denotes the size in characters.
56
67
  * You can add right or center as an additional parameter to align the
@@ -62,6 +73,8 @@ Everything else is in plugins. The following plugins are existing for now:
62
73
  picture instead of beneath. Combined with +++ the next picture replaces the
63
74
  current one, which allows for simple animations (see
64
75
  examples/sixel_svg.2.txt).
76
+ * Kitty: the same as Sixel, but with the kitty graphics protocol:
77
+ `` ```kitty,20 name.png``. All parameters of the Sixel plugin work.
65
78
  * Figlet: display fancy ascii text: `` ```figlet FANCY_TEXT``.
66
79
  * You can add right or center as a parameter to align the fancy text.
67
80
  * If the fancy text is right aligned, normal text is added on the left of the
data/chimp.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "cheap-impression-presenter"
3
- s.version = "1.1.3"
3
+ s.version = "1.2.1"
4
4
  s.platform = Gem::Platform::RUBY
5
5
  s.license = "GPL-3.0-or-later"
6
6
  s.summary = "CHIMP - Make a cheap impression. Present via terminal."
data/lib/output/screen.rb CHANGED
@@ -4,7 +4,18 @@ require 'io/console'
4
4
 
5
5
  module Window #{{{
6
6
  class WinchError < Exception; end
7
+
8
+ def self::sync_begin()
9
+ $stdout << "\e[?2026h"
10
+ $stdout.flush
11
+ end
12
+ def self::sync_end()
13
+ $stdout << "\e[?2026l"
14
+ $stdout.flush
15
+ end
16
+
7
17
  def self::init()
18
+ self::sync_begin
8
19
  self::clear
9
20
  $stdout << "\e[?25l"
10
21
  $stdout.flush
@@ -17,10 +28,11 @@ module Window #{{{
17
28
  self::clear
18
29
  self::set_pos 0, 0
19
30
  $stdout << "\e[?25h"
20
- $stdout.flush
31
+ self::sync_end
21
32
  nil
22
33
  end
23
34
  def self::getch()
35
+ self::sync_end
24
36
  number = nil
25
37
  loop do
26
38
  ch = $stdin.getch
@@ -49,6 +61,8 @@ module Window #{{{
49
61
  end
50
62
  end
51
63
  end
64
+ ensure
65
+ self::sync_begin
52
66
  end
53
67
  def self::lines()
54
68
  TTY::Screen.lines
@@ -56,7 +70,13 @@ module Window #{{{
56
70
  def self::columns()
57
71
  TTY::Screen.columns
58
72
  end
73
+ #### how often the screen was cleared; plugins check if what they
74
+ #### drew is still there
75
+ def self::cleared()
76
+ @cleared || 0
77
+ end
59
78
  def self::clear()
79
+ @cleared = cleared + 1
60
80
  $stdout << "\e[2J"
61
81
  $stdout.flush
62
82
  self
@@ -216,11 +236,12 @@ module Chimp
216
236
  if tag.ttype == "P_INCREMENTAL"
217
237
  ### erase only what this step has drawn (pictures next to it stay), then wait at the end of the previous step again
218
238
  step = tree[c.open].userdata
219
- step[:drawn].each do |x1,y1,x2,y2|
239
+ step[:drawn].each do |x1,y1,x2,y2,erase|
220
240
  y1.upto(y2) do |y|
221
241
  @screen.set_pos x1, y
222
242
  @screen.print ' ' * (x2-x1+1)
223
243
  end
244
+ erase.call if erase
224
245
  end
225
246
  @screen.set_pos step[:x], step[:y]
226
247
  raise TagMoveEvent, pos
@@ -246,13 +267,15 @@ module Chimp
246
267
  eval('Chimp::Plugin::' + data[:name].upcase).new.prepare(data[:what],data[:parameters],data[:additional])
247
268
  end
248
269
 
249
- #### plugins may return the area they drew as [x1,y1,x2,y2], otherwise the whole lines they printed on count
270
+ #### plugins may return the area they drew as [x1,y1,x2,y2],
271
+ #### otherwise the whole lines they printed on count an
272
+ #### optional fifth element is called to erase, e.g., kitty pics
250
273
  def process(data)
251
274
  require File::dirname(__FILE__) + "/../plugins/#{data[:name]}.rb"
252
275
  area = eval('Chimp::Plugin::' + data[:name].upcase).new.process(data[:what],data[:parameters],@screen,data[:additional])
253
276
  return unless @drawn
254
277
  x, y = @screen.get_pos
255
- @drawn << (area.is_a?(Array) && area.length == 4 ? area : [1, @y, @screen.columns, y])
278
+ @drawn << (area.is_a?(Array) && [4, 5].include?(area.length) ? area : [1, @y, @screen.columns, y])
256
279
  @x, @y = x, y
257
280
  end
258
281
  private :process
@@ -0,0 +1,117 @@
1
+ require 'fileutils'
2
+ require 'base64'
3
+ require 'io/console'
4
+
5
+ module Chimp
6
+ module Plugin
7
+ class KITTY < Base
8
+ @@placed = {} # [x,y] => [id, width, screen clears so far, what it replaced], the pictures on the screen
9
+ #### pixel size of a character cell: from the terminal if it knows, else 10x21 as for sixel and the pdf
10
+ def cell_size
11
+ rows, cols, xpix, ypix = [0, 0, 0, 0].pack('S4').then { |buf| $stdout.ioctl(0x5413, buf); buf.unpack('S4') } # TIOCGWINSZ
12
+ return [xpix / cols, ypix / rows] if xpix > 0 && ypix > 0
13
+ [10, 21]
14
+ rescue StandardError
15
+ [10, 21]
16
+ end
17
+
18
+ # converted images are cached in .PRESENTATIONNAME/ next to the presentation
19
+ def cache_file(what,width,fname)
20
+ dir = File.join(File.dirname(fname),'.' + File.basename(fname,'.*'))
21
+ File.join(dir,"#{what.gsub('/','_')}.#{width}.kitty.png")
22
+ end
23
+
24
+ #### kitty only takes png. the terminal scales it to the width, so it does not depend on the zoom
25
+ #### (which would convert everything again for each zoom). as for sixel 10 pixels per character,
26
+ #### and 5 bits per color, which keeps it small (it goes through the terminal, maybe via ssh)
27
+ def png(what,width,fname)
28
+ src = File.join(File.dirname(fname),what)
29
+ pixels = width * 10
30
+ cache = cache_file(what,width,fname)
31
+ if File.exist?(cache) && File.exist?(src) && File.mtime(cache) >= File.mtime(src)
32
+ return File.binread(cache)
33
+ end
34
+ convert = if what =~ /\.svg$/
35
+ "inkscape -D -d 300 --export-type=png #{src} -o - | magick - -resize #{pixels}x -depth 5 png:-"
36
+ else
37
+ "magick #{src} -resize #{pixels}x -depth 5 png:-"
38
+ end
39
+ result = `#{convert}`
40
+ if $?.success? && !result.empty?
41
+ FileUtils.mkdir_p(File.dirname(cache))
42
+ File.binwrite(cache,result)
43
+ end
44
+ result
45
+ end
46
+
47
+ def prepare(what,parameters,additional)
48
+ return if parameters[0] !~ /\d/
49
+ png(what,parameters[0].to_i,additional[:fname])
50
+ end
51
+
52
+ def process(what,parameters,screen,additional)
53
+ if parameters[0] !~ /\d/
54
+ screen.print 'Use ```kitty,NUM with NUM beeing the width if the picture in characters.'
55
+ return
56
+ end
57
+
58
+ restore = parameters.include?('animate') || parameters.include?('float')
59
+ width = parameters[0].to_i
60
+ len = screen.columns
61
+ pos = screen.get_pos
62
+ x, y = pos
63
+ ### move instead of printing spaces, spaces would erase a picture already on this line
64
+ if parameters.include? 'right'
65
+ x += len-width
66
+ elsif parameters.include? 'center'
67
+ x += (len-width)/2
68
+ end
69
+ screen.set_pos x, y
70
+ if screen.respond_to?(:image) # pdf output
71
+ screen.image what, width, additional[:fname]
72
+ _, bottom = screen.get_pos
73
+ last = bottom
74
+ erase = nil
75
+ else
76
+ data = png(what,width,additional[:fname])
77
+ return if data.empty?
78
+ ### the terminal scales the png to the width, which says how many lines it covers
79
+ w, h = data[16,8].unpack('NN')
80
+ cw, ch = cell_size
81
+ bottom = y + (width * cw * h / (w * ch).to_f).ceil
82
+ ### bottom is the line after the picture, erasing it would erase what is there (e.g. the footer)
83
+ last = bottom - 1
84
+ id = rand(1...2**31)
85
+ ### a picture drawn at the same place as another one replaces it (e.g. for animations). only its placement
86
+ ### goes, the terminal keeps the data so going back can show it again. clearing the screen (next slide)
87
+ ### removes all pictures, so whatever was placed before that is not there to replace.
88
+ covered = @@placed[[x, y]]
89
+ covered = nil unless covered && covered[2] == screen.cleared
90
+ ### all chunks in one write, a flush per chunk stutters, q=2 keeps the terminal from answering
91
+ chunks = Base64.strict_encode64(data).scan(/.{1,4096}/)
92
+ screen.print (covered ? "\e_Ga=d,d=i,i=#{covered[0]},q=2\e\\" : '') + chunks.each_with_index.map { |chunk,i|
93
+ keys = i == 0 ? "a=T,f=100,i=#{id},c=#{width},C=1,q=2," : ''
94
+ "\e_G#{keys}m=#{i < chunks.length-1 ? 1 : 0};#{chunk}\e\\"
95
+ }.join
96
+ @@placed[[x, y]] = [id, width, screen.cleared, covered]
97
+ ### pictures are not part of the text, printing spaces does not erase them. bring back what it replaced.
98
+ erase = lambda do
99
+ screen.print "\e_Ga=d,d=I,i=#{id},q=2\e\\"
100
+ if covered
101
+ screen.set_pos x, y
102
+ screen.print "\e_Ga=p,i=#{covered[0]},c=#{covered[1]},C=1,q=2\e\\"
103
+ end
104
+ @@placed[[x, y]] = covered
105
+ end
106
+ end
107
+ if restore
108
+ screen.set_pos *pos
109
+ else
110
+ screen.set_pos 0, bottom
111
+ end
112
+ ### the area the picture covers, so going back can erase exactly that
113
+ [x, y, x+width-1, last, erase].compact
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,59 @@
1
+ require 'io/console'
2
+ require_relative 'sixel'
3
+ require_relative 'kitty'
4
+
5
+ module Chimp
6
+ module Plugin
7
+ class PIC < Base
8
+ #### ask the terminal once: a kitty graphics query, then a device attributes query (4 means sixel),
9
+ #### which every terminal answers, so we know when to stop waiting for the kitty answer
10
+ def detect
11
+ return ENV['CHIMP_PIC'].to_sym if %w{kitty sixel none}.include?(ENV['CHIMP_PIC'])
12
+ return :none unless $stdin.tty? && $stdout.tty?
13
+ res = ''
14
+ $stdin.raw do
15
+ $stdout << "\e_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\e\\\e[c"
16
+ $stdout.flush
17
+ while IO.select([$stdin], nil, nil, 1) && (c = $stdin.getc)
18
+ res << c
19
+ break if res =~ /\e\[\?[\d;]*c/
20
+ end
21
+ end
22
+ if res.include?("\e_Gi=31;OK")
23
+ :kitty
24
+ elsif res =~ /\e\[\?([\d;]*)c/ && $1.split(';').include?('4')
25
+ :sixel
26
+ else
27
+ :none
28
+ end
29
+ rescue StandardError
30
+ :none
31
+ end
32
+
33
+ def graphics
34
+ @@graphics ||= detect
35
+ end
36
+
37
+ def delegate(screen=nil)
38
+ ### the pdf does not care, both plugins hand the picture to it
39
+ return SIXEL.new if screen.respond_to?(:image)
40
+ case graphics
41
+ when :kitty then KITTY.new
42
+ when :sixel then SIXEL.new
43
+ end
44
+ end
45
+
46
+ def prepare(what,parameters,additional)
47
+ delegate&.prepare(what,parameters,additional)
48
+ end
49
+
50
+ def process(what,parameters,screen,additional)
51
+ if parameters[0] !~ /\d/
52
+ screen.print 'Use ```pic,NUM with NUM beeing the width if the picture in characters.'
53
+ return
54
+ end
55
+ delegate(screen)&.process(what,parameters,screen,additional)
56
+ end
57
+ end
58
+ end
59
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cheap-impression-presenter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juergen eTM Mangler
@@ -72,7 +72,9 @@ files:
72
72
  - lib/output/pdf.rb
73
73
  - lib/output/screen.rb
74
74
  - lib/plugins/figlet.rb
75
+ - lib/plugins/kitty.rb
75
76
  - lib/plugins/lnums.rb
77
+ - lib/plugins/pic.rb
76
78
  - lib/plugins/sixel.rb
77
79
  - tools/chimp
78
80
  homepage: https://github.com/etm/chimp