hpjansson / chafa

📺🗿 Terminal graphics for the 21st century.
https://hpjansson.org/chafa/
GNU Lesser General Public License v3.0
2.75k stars 57 forks source link

`yoffset` option for images like w3m? #164

Open quincynyan opened 10 months ago

quincynyan commented 10 months ago

I am using chafa together with neofetch, but the image outputted is printed at the top of the terminal, i want it around 50 pixels moved down. This can be done with the --yoffset 50 in w3m, but can't find something similar in chafa. Maybe like some sort of padding above the image? When I just run chafa image.png, I want some space between the current line of the command (where i typed and entered the command) and the top of the image by some amount of pixels specified by me.

hpjansson commented 10 months ago

Hi, thanks for bringing it up. I need a little more information, so I can figure out if/how this idea could apply more generally.

It would be great to have a screenshot of how it looks in Neofetch. Is the problem actually that it's misaligned there, or is it important to have the spacing when you run chafa standalone from the command-line too?

quincynyan commented 10 months ago

https://cdn.nekonyan.fun/Peek_2023-09-09_10-22.gif

hpjansson commented 10 months ago

Thanks, that explains the request perfectly.

The good news is that chafa will get more ways to position the image in the next release. See #140 and #146. It should be able to do what you want.

The bad news is that --yoffset is actually an argument to neofetch, which calls chafa like this:

chafa --stretch --size="$((width / font_width))x$((height / font_height))" "$image"

There's no positioning information there, so it would be necessary to patch Neofetch to pass it on to Chafa. And unfortunately, its developer seems to be on hiatus still. Might be possible to get traction for it in one of the forks, though.

hpjansson commented 6 months ago

I just released version 1.14.0. It has the new options --view-size and --align, which can be used to produce vertical spacing. I chose to use relative positioning instead of absolute, since it simultaneously addresses other use cases.

You can add a one-line vertical offset like this:

chafa image.jpg --view-size 20x10 --size 20x9 --align bottom

Unfortunately there's nothing I can do about Neofetch directly. Hope it's useful anyway!

quincynyan commented 6 months ago

Those are nice new features! I'm writing my own version of neofetch and want to replicate this behavior:

image

hpjansson commented 6 months ago

Pixel adjustments are possible with the new smolscale - we could even support cropping if the image is partially outside the viewport, or adjustments in 1/256 fractional pixel increments (but then it'd get blurrier). I'll have a think about how this could fit with the existing options.

We're actually already doing pixel offsets when the image is slightly smaller than the view -- but you can't control the offsets precisely. I.e. --align center will position it at sub-cell offsets.

quincynyan commented 6 months ago

I'm adding some text beside and below the image, something like the text wrapping around the image. So pixel offsets would be more useful than the align option in such cases.

AnonymouX47 commented 6 months ago

If I may chime in...

@quincynyan I'm curious, why would column/row offsets not be okay (or even better)?

quincynyan commented 6 months ago

@AnonymouX47 I can already kinda implement that behavior bu moving the cursor to wherever I want on the terminal scree and the running chafa. For example, printf '\e[2J\e[H' to clear the screen and move the cursor to the top left. I can then manually print \n or spaces to move the displayed image left or down from the top left, then finally call chafa when the cursor is in the position I want. It's basically the same as column/line offset.


The feature I want is something similar to w3mimgdisplay or kitty where you can run kitty +kitten icat --align left --place "$((width/font_width))x$((height/font_height))@${xoffset}x${yoffset}" "$image"

This moves the image by specific pixels from the current cursor position.

AnonymouX47 commented 6 months ago

I guess I should rephrase my question... Why aren't row and column offsets sufficient? Or Why do you need exact pixel offsets?

Side note: Using CUP (CSI row ; col H) or CUD (CSI Ps B) and CUF (CSI Ps F) sequences would probably be better if you later choose to go the row/column route, since you already clear the screen.

hpjansson commented 6 months ago

@quincynyan Does it have to be absolute offsets? Would it be enough if the current --align center,center centered using pixel offsets, for instance?

quincynyan commented 6 months ago

@AnonymouX47 Sorry I'm late, I've been busy with something for the past couple of days.

I'm making a bash script CLI app which allows the user to position where their image will be displayed (and also choose which display backend they want to use). This is through the --xoffset and --yoffset options. Of course, I could make the options only take in the number of columns/rows, but I've already made it say they take in pixel values, and have implemented w3m and kitty image backends to use pixel offsets. I could change them so that they are number rows/columns, and multiply by the resolution/number of pixels in height/width then pass it to w3m or kitty, but something like a 4px offset from the top of the terminal looks way better than an entire row offset from the top when display an image. 0px is too little and 1 row looks like a too empty gap above the image.

quincynyan commented 6 months ago

@hpjansson I already know the widths and heights of the image, and so maybe what I can do is create an empty space/canvas of (width+xoffset) x (height+yoffset), then --align the image to be printed in bottom right of the given space/canvas. Is that possible? Again, I'm also going to be printing around (right and bottom) the image, but using space padding that's calculated using the (width+xoffset) x (height+yoffset) and the image stays on "top" of that strings of spaces.

AnonymouX47 commented 6 months ago

@AnonymouX47 Sorry I'm late, I've been busy with something for the past couple of days.

I'm making a bash script CLI app which allows the user to position where their image will be displayed (and also choose which display backend they want to use). This is through the --xoffset and --yoffset options. Of course, I could make the options only take in the number of columns/rows, but I've already made it say they take in pixel values, and have implemented w3m and kitty image backends to use pixel offsets. I could change them so that they are number rows/columns, and multiply by the resolution/number of pixels in height/width then pass it to w3m or kitty, but something like a 4px offset from the top of the terminal looks way better than an entire row offset from the top when display an image. 0px is too little and 1 row looks like a too empty gap above the image.

Hmm... I see.

quincynyan commented 6 months ago

Again, it's not a requirement, it's just a feature request. If not possible, I'll try to reverse engineer how w3m does it and maybe port it to my app. The problem is I don't really know C language so it's hard reading the source code lmao

AnonymouX47 commented 6 months ago

One important thing to note is, only the Kitty graphics protocol supports pixel offsets for image placements. For the record, w3mimgdisplay doesn't actually display images within the TE, it uses overlay/floating windows that have no chrome/decoration.

Anyways, like @hpjansson mentioned, it's possible to mimick the behaviour... I would imagine by compositing the original image (after being appropriately scaled; not source image) onto the lower-right region of a transparent canvas of size image_width + x_offset by image_height + y_offset.

The only issues I can think of at the moment are:

  1. Such image placements must not be cell-bound in size (which I believe chafa, the library, curently uses for kitty and iterm protocols). Otherwise, it counters the whole point of the offsets.
  2. Some TEs, such as Konsole, do not support sixel transparency but replace with a solid color.
  3. For the iterm protocol (not sure about sixels), the transparent portion of the placed image (used to mimick the offset) would typically replace text content in most TEs... which isn't typically expected behaviour for an offset.
  4. How would this apply to the symbols format?
quincynyan commented 5 months ago

The reason I created this issue was to resolve this issue:

https://cdn.nekonyan.fun/Peek_2023-09-09_10-22.gif

I know the author is on hiatus and isn't currently accepting any pull requests, but I can fork my own version of it and fix it.

Here is the code for w3m:

printf '%b\n%s;\n%s\n' "0;1;$xoffset;$yoffset;$width;$width;;;;;$tmpfile.$format" 3 4 | /usr/lib/w3m/w3mimgdisplay &>/dev/null

Here is the code for kitty:

kitty +kitten icat --align left --place "$((width/font_width))x$((height/font_height))@${xoffset}x${yoffset}" "$image"

Here is the code for chafa:

chafa --stretch --size="$((width / font_width))x$((height / font_height))" "$image"

As hp mentioned, there is no information passed about offsets there. So how would the offsets information be passed on to chafa so that it renders the image correctly just like it does in w3m and kitty? I've implemented both w3m and kitty in my fork, but don't know how to implement chafa. Again, I'm measuring the offsets starting from the current position of the cursor after clearing the screen and moving the cursor to the top left.