From d33cc0ff06f761a1919c9c7508d8c3ffe88364ad Mon Sep 17 00:00:00 2001 From: mark-dawn Date: Thu, 22 Feb 2018 05:23:46 +0100 Subject: Unstretched Image Previews Implemented a way to obtain unstretched image previews Fixed wording in ranger.pod --- doc/ranger.pod | 3 +-- ranger/config/rc.conf | 2 +- ranger/ext/img_display.py | 39 ++++++++++++++++++--------------------- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/doc/ranger.pod b/doc/ranger.pod index 887f704d..46ca920e 100644 --- a/doc/ranger.pod +++ b/doc/ranger.pod @@ -244,8 +244,7 @@ To enable this feature, set the option C to urxvt-full. =head3 kitty This only works on Kitty. It requires PIL (or pillow) to work. -It is able to automatically work over network, -by switching to a slower transfer method. +Allows remote image previews, for example in an ssh session. To enable this feature, set the option C to kitty. diff --git a/ranger/config/rc.conf b/ranger/config/rc.conf index 305143c1..165e049b 100644 --- a/ranger/config/rc.conf +++ b/ranger/config/rc.conf @@ -102,7 +102,7 @@ set preview_images false # Preview images in full color using kitty image protocol. # Requires python PIL or pillow library. # If ranger does not share the local filesystem with kitty -# the transfer method is switched to encoding the whole image in +# the transfer method is switched to encode the whole image in # the protocol that, while slower, allows remote previews, # for example during an ssh session. # Tmux support is untested. diff --git a/ranger/ext/img_display.py b/ranger/ext/img_display.py index 387d61a3..925a4054 100644 --- a/ranger/ext/img_display.py +++ b/ranger/ext/img_display.py @@ -506,6 +506,7 @@ class KittyImageDisplayer(ImageDisplayer): # to init in _late_init() self.backend = None self.stream = None + self.pix_row, self.pix_col = (0, 0) def _late_init(self): # automatic check if we share the filesystem using a dummy file @@ -542,9 +543,14 @@ class KittyImageDisplayer(ImageDisplayer): # TODO: implement a wrapper class for Imagemagick process to # replicate the functionality we use from im + # get dimensions of a cell in pixels + ret = fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, + struct.pack('HHHH', 0, 0, 0, 0)) + n_cols, n_rows, x_px_tot, y_px_tot = struct.unpack('HHHH', ret) + self.pix_row, self.pix_col = x_px_tot / n_rows, y_px_tot / n_cols self.needs_late_init = False - def draw(self, path, start_x, start_y, width, height): # pylint: disable=too-many-locals + def draw(self, path, start_x, start_y, width, height): self.image_id += 1 # dictionary to store the command arguments for kitty # a is the display command, with T going for immediate output @@ -557,23 +563,16 @@ class KittyImageDisplayer(ImageDisplayer): self._late_init() image = self.backend.open(path) - # since kitty streches the image to fill the view box - # we need to resize the box to not get distortion - mismatch_ratio = (image.width / image.height) / (width * 0.5 / height) - if mismatch_ratio > 1.05: - new_h = height / mismatch_ratio - start_y += int((height - new_h) // 2) - height = int(new_h) - elif mismatch_ratio < 0.95: - new_w = width * mismatch_ratio - start_x += int((width - new_w) // 2) - width = int(new_w) - - # resize image to a smaller size. Ideally this should be - # image = self._resize_max_area(image, (), self.backend.LANCZOS) + box = (width * self.pix_row, height * self.pix_col) + + if image.width > box[0] or image.height > box[1]: + scale = min(box[0] / image.width, box[1] / image.height) + image = image.resize((int(scale * image.width), int(scale * image.height)), + self.backend.LANCZOS) + start_x += ((box[0] - image.width) // 2) // self.pix_row + start_y += ((box[1] - image.height) // 2) // self.pix_col if self.stream: - image = self._resize_max_area(image, (480 * 960), self.backend.LANCZOS) # encode the whole image as base64 # TODO: implement z compression # to possibly increase resolution in sent image @@ -584,8 +583,7 @@ class KittyImageDisplayer(ImageDisplayer): # s, v: size of the image to recompose the flattened data # c, r: size in cells of the viewbox cmds.update({'t': 'd', 'f': len(image.getbands()) * 8, - 's': image.width, 'v': image.height, - 'c': width, 'r': height}) + 's': image.width, 'v': image.height, }) payload = base64.standard_b64encode( bytearray().join(map(bytes, image.getdata()))) else: @@ -594,14 +592,13 @@ class KittyImageDisplayer(ImageDisplayer): # f: size of a pixel fragment (100 just mean that the file is png encoded, # the only format except raw RGB(A) bitmap that kitty understand) # c, r: size in cells of the viewbox - cmds.update({'t': 't', 'f': 100, - 'c': width, 'r': height}) + cmds.update({'t': 't', 'f': 100, }) with NamedTemporaryFile(prefix='rgr_thumb_', suffix='.png', delete=False) as tmpf: image.save(tmpf, format='png', compress_level=0) self.temp_paths.append(tmpf.name) payload = base64.standard_b64encode(tmpf.name.encode(self.fsenc)) - with temporarily_moved_cursor(start_y, start_x): + with temporarily_moved_cursor(int(start_y), int(start_x)): for cmd_str in self._format_cmd_str(cmds, payload=payload): self.stdbout.write(cmd_str) # catch kitty answer before the escape codes corrupt the console -- cgit 1.4.1-2-gfad0