Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong sizes on high resolution screens #12

Open
tarsius opened this issue Feb 25, 2021 · 44 comments
Open

Wrong sizes on high resolution screens #12

tarsius opened this issue Feb 25, 2021 · 44 comments

Comments

@tarsius
Copy link
Contributor

tarsius commented Feb 25, 2021

The math seems to be off on high resolution screens, 3840x2160 in my case. I believe I have also tried this on a 2560x1440 screen without any issues, but it has been a while since I had that hooked up, so I am not quite sure anymore.

20210226-00:44:00

Emacs does some weird calling for high resolutions. Again, I don't remember any details but for my moody package I got the create-image to stop calling by some unknown number by telling it to scale by 1 instead, using (create-image ... :scale 1).

Note that it's not just the font size that is off, there also appear some pixels to be missing at the bottom of images.

@rougier
Copy link
Owner

rougier commented Feb 27, 2021

Thanks for the report. For the weird calling for high resolution, do you know if this is related to the difference between actual scrren resolution vs system resolution? Also, on your screenshot, what is the font size of text?

@rougier
Copy link
Owner

rougier commented Feb 27, 2021

Just added :scale 1 to the svg image but since I cannot reproduce the bug, it's hard to tell if it has any effect. I also tried changing my system resolution (OSX) and it's still working as expected. What are the values (window-font-width) and (window-font-height)?

@tarsius
Copy link
Contributor Author

tarsius commented Mar 1, 2021

do you know if this is related to the difference between actual scrren resolution vs system resolution?

I don't know. I am using the monitors native resolution.

Just added :scale 1 to the svg image but since I cannot reproduce the bug, it's hard to tell if it has any effect.

I already tried that. It doesn't seem to do anything.

The only documentation I could find about this is in create-image's doc-string:

If the property `:scale' is not given and the
display has a high resolution (more exactly, when the average width of a
character in the default font is more than 10 pixels), the image is
automatically scaled up in proportion to the default font.
(list (window-font-width)
      (window-font-height))
=> (13 27)

@rougier
Copy link
Owner

rougier commented Mar 1, 2021

Could you evaluate

(let* ((w (window-font-width))
       (h (window-font-height))
       (svg (svg-create w h)))
  (svg-rectangle svg 0 0 w h :stroke "black" :fill "none")
  (svg-text svg "A"
            :x           0
            :y           (- h 4)
            :font-family "Roboto Mono Emacs Regular"
            :font-size   14
            :fill        "black")
  (insert-image (svg-image svg :scale 1 :ascent 'center)))

Replacing the font-family and font size with yours. After evaluating the SVG and type "A" just next to the svg image in order to compare SVG text size vs emacs text size?

@tarsius
Copy link
Contributor Author

tarsius commented Mar 1, 2021

Replacing the font-family and font size with yours.

How does one determine the font size? (face-attribute 'default :height) returns 158, which isn't in the same ballpark as 14.

@tarsius
Copy link
Contributor Author

tarsius commented Mar 1, 2021

Anyway, I think the value is 16, because I have set Emacs.font: Source Code Pro-16 in .Xresources. With that evaluating the above code inserts something invisible that has the correct proportions (i.e. the visual effect is the same as just inserting a plain old space).

@rougier
Copy link
Owner

rougier commented Mar 1, 2021

The size is expressed in 1/10th of point hence 158 is 16. If you can't seen the letter, you can :y 0 instead of :y (- h 4)

@tarsius
Copy link
Contributor Author

tarsius commented Mar 2, 2021

I've figured it out but it will be a few days until I get around to a pull-request.

@jamesnvc
Copy link

If I can contribute to this: I seem to be seeing the same problem on a high-resolution screen, with X set to 144 DPI. Using the test code above, I need to bump the font-size up to 19 to look approximately the same size as a normally-typed A, while my actual font size is 8 (which is not nearly as tiny as it would seem, thanks to the high DPI).

I also note that if I omit the font-size line in the code above, then it does draw as the correct size.

@rougier
Copy link
Owner

rougier commented Apr 30, 2021

You mean font-size in the svg-textpart?

@jamesnvc
Copy link

You mean font-size in the svg-textpart?

Yessir

@deb75
Copy link

deb75 commented May 21, 2021

Hi,

Just tried on windows 10. My screen is hidpi and I can barely see the text within the box

@rougier
Copy link
Owner

rougier commented May 21, 2021

We're trying to debug it. Can you try code at #14 (comment) (and post in the same thread)?

@fstamour
Copy link

fstamour commented Sep 7, 2021

I'm having the same issue, here's how it looks in org-mode:
image

And with the snippet (which I tweaked) you asked to evaluate, in elisp-mode :
image

With the same snippet, but in emacs-lisp-mode, it does insert something, but it looks to be the wrong size and it's either white-on-white or too small to be seen: Ok, SVGs are only displayed when the major-mode is a text-mode.

I'm on Windows, with Emacs 27.2 a resolution of 2560x1440 and no scaling. Also, I must point out that my emacs configuration is pretty empty at the moment, so it is unlikely it's caused by a conflict with another package or configuration

@rougier
Copy link
Owner

rougier commented Sep 20, 2021

Sorry for late answer. Can you try to remove the :scale 1.0 in the svg-image ?

@rougier
Copy link
Owner

rougier commented Sep 20, 2021

Also, can you have a look at #14 (comment) (maybe best to continue discussion on this PR actually)

@fstamour
Copy link

Here, I did some test (I didn't look at the PR yet).

(save-excursion
  (forward-paragraph)
  (progn ;; Delete til end of file
    (delete-region (point) (point-max)))
  (cl-loop
   for font-family in (list "Roboto Mono Emacs Regular" "Roboto Mono" (face-attribute 'default :family)) do
   (cl-loop
    for font-size in (list 14 (face-attribute 'default :height)) do
    (let* ((canvas-scale 8.0)
	   (w (* canvas-scale (window-font-width)))
	   (h (* canvas-scale (window-font-height)))
	   (svg (svg-create w h)))
      (svg-rectangle svg 0 0 w h :stroke "black" :fill "none")
      (svg-text svg "A"
		:x           0
		:y           (- h 4)
		:font-family "Roboto Mono Emacs Regular"
		:font-size   font-size
		:fill        "black")
      (insert "\n")
      (insert "A")
      (insert-image (svg-image svg :scale 1 :ascent 'center))
      (insert-image (svg-image svg :ascent 'center))
      (insert "\t" font-family " - " (format "%s" font-size))))))
(face-attribute 'default :family) ;; => "Courier New"
(face-attribute 'default :height) ;; => 98

image

@fstamour
Copy link

Ok, @rougier I took a look at the comment you linked and I added the code next to what I tried, it work very well:

image

The whole shebang
(save-excursion
  (forward-paragraph)
  (progn ;; Delete til end of file
    (delete-region (point) (point-max)))
  (cl-loop
   for font-family in (list ;; "Roboto Mono Emacs Regular"
		       "Roboto Mono"
		       (face-attribute 'default :family))
   do
   (cl-loop
    for font-size in (list 14
			   (face-attribute 'default :height)
			   (elt (query-font (font-at (point-min))) 3))
    do
    (let* ((canvas-scale (+ 0.5 (/ font-size 14)))
	   (w (* canvas-scale (window-font-width)))
	   (h (* canvas-scale (window-font-height)))
	   (svg (svg-create w h)))
      (svg-rectangle svg 0 0 w h :stroke "black" :fill "none")
      (svg-text svg "A"
		:x           0
		:y           (- h 4)
		:font-family "Roboto Mono Emacs Regular"
		:font-size   font-size
		:fill        "black")
      (insert "\n")
      (insert "A")
      (insert-image (svg-image svg :scale 1 :ascent 'center))
      (insert-image (svg-image svg :ascent 'center))
      (insert "\t" font-family " - " (format "%s" font-size) " ")
      (let* ((text "Hello guys!")
	     (font       (query-font (font-at (point-min))))
	     (font-size  (elt font 2))
	     (family     (face-attribute 'default :family))
	     (descent    (elt font 4))
	     (ascent     (elt font 5))
	     (svg-height (+ ascent descent))
	     (char-width (elt font 7))
	     (svg-width  (* char-width (length text)))
	     (svg        (svg-create svg-width svg-height)))
	(svg-rectangle svg 0 0 svg-width svg-height :stroke "black" :fill "none")
	(svg-text svg text
		  :fill "red"
		  :stroke-width 0
		  :font-family family
		  :font-weight "300"
		  :font-size font-size
		  :x 0
		  :y descent)
	(insert-image (svg-image svg :ascent 'center)))
      ))))
(face-attribute 'default :family) ;; => "Courier New"
(face-attribute 'default :height) ;; => 98
(font-at (point)) ;; =>  #<font-object "-outline-Fira Mono-normal-normal-normal-mono-13-*-*-*-c-*-iso8859-1">

@rougier
Copy link
Owner

rougier commented Oct 4, 2021

Thanks for these tests. The last version seems better but the baseline seems a bit off.

@deb75
Copy link

deb75 commented Apr 3, 2022

Hello,

I come back to this thread because I still have this issue.

My configuration is emacs master from a couple of weeks on windows 11 and on a hidpi screen (3000x2000). The default display zoom is 250%.

Here is an org file without ``svg-tag-mode` :

emacs1

Then Alt X svg-tag-mode gives :

emacs2

The svg are sensibly bigger than the text.

I digged a little in svg-tag-make, looking for a scale option as an example, but did not find anything useful.

Because images are svg, I am quite convinced that there should exist an easy way to rescale images. For example, if you are a math-preview user, there is an option to make the svg bigger or smaller.

I would love to use svg-tag-mode more extensively. How could I fix this issue ?

Regards

EDIT : it happens only with a hidpi screen with a zoom applied. With another screen, svg sizes are correct

@deb75
Copy link

deb75 commented Apr 5, 2022

Any hints ?

@rougier
Copy link
Owner

rougier commented Apr 8, 2022

Where does the zoom comes from exactly ? From outside emacs?

@deb75
Copy link

deb75 commented Apr 9, 2022

Yes, this is a zoom applied by windows 11.

By tweaking some parameters in svg-lib functions, I managed to get something better, not yet usable though.
It seems that the scale parameter is ignored.

This issue definitely comes from the screen zoom. With another computer (same emacs config) and another screen, which does not need zooming, the text and its svg counter part are equivalent in size and appearance.

I do not remember the tweaks but I will let you know as soon as I have time.

Regards

@rougier
Copy link
Owner

rougier commented Apr 11, 2022

It might be possible to retrieve the magnification factor from inside emacs but I'm not sure how. Maybe through DPI computation. See also https://emacs.stackexchange.com/questions/28390/quickly-adjusting-text-to-dpi-changes

@deb75
Copy link

deb75 commented Apr 13, 2022

Yes, but then, how to use it ? as an argument to svg-tag-make ?

I will try do debug that soon.

Regards

@rougier
Copy link
Owner

rougier commented Apr 21, 2022

Not sure how to use it, but most probably you can use the zoom factor for char-height and char-width.

@deb75
Copy link

deb75 commented Jun 19, 2022

Hi,

I was able to correct my issue by manually modifying the font-size and height parameters which are given to svg-lib-tag function.

This is only a workaround. I plan to uncomment the scale parameter in svg-lib-tag and
define a default scale value which will manually adjust the font size (character width and height) and the svg height.

Regards

@rougier
Copy link
Owner

rougier commented Jun 21, 2022

Yes, but the idea is to have all of these calculations to be automated. It seems to be a reccuring problem though. Each time we solve one case, a new one pops out... Best would be to understand the origin of the problem or to find a parameter we could use.

@deb75
Copy link

deb75 commented Aug 3, 2022

I finally got it working by modifying the svg-lib-tag function :

(defun svg-lib-tag (label &optional style &rest args)
  "Create an image displaying LABEL in a rounded box using given STYLE
and style elements ARGS."

  (let* ((default svg-lib-style-default)
         (style (if style (apply #'svg-lib-style nil style) default))
         (style (if args  (apply #'svg-lib-style style args) style))

         (foreground  (plist-get style :foreground))
         (background  (plist-get style :background))

         (crop-left   (plist-get style :crop-left))
         (crop-right  (plist-get style :crop-right))

         (alignment   (plist-get style :alignment))
         (stroke      (plist-get style :stroke))
         (width       (plist-get style :width))
         (height      (plist-get style :height))
         (radius      (plist-get style :radius))
         ;; (scale       (plist-get style :scale))
         (margin      (plist-get style :margin))
         (padding     (plist-get style :padding))
         (font-size   (plist-get style :font-size))
         (font-family (plist-get style :font-family))
         (font-weight (plist-get style :font-weight))

         (txt-char-width  (plist-get style :txt-char-width))
         (txt-char-height (plist-get style :txt-char-height))

         (txt-char-height (if line-spacing
                              (+ txt-char-height line-spacing)
                          txt-char-height))
         (font-info       (font-info (format "%s-%d" font-family font-size)))
         (font-size       (aref font-info 2)) ;; redefine font-size
         (ascent          (aref font-info 8))
         (tag-char-width  (aref font-info 11))
         ;; (tag-char-height (aref font-info 3))
         (tag-width       (* width (* (+ (length label) padding) txt-char-width)))
         (tag-height      (* txt-char-height height))

         (svg-width       (+ tag-width (* margin txt-char-width width)))
         (svg-height      tag-height)

         (tag-x  (* (- svg-width tag-width)  alignment))
         (text-x (+ tag-x (/ (- tag-width (* (length label) tag-char-width)) 2)))
         (text-y ascent)

         (tag-x      (if crop-left  (- tag-x     txt-char-width) tag-x))
         (tag-width  (if crop-left  (+ tag-width txt-char-width) tag-width))
         (text-x     (if crop-left  (- text-x (/ stroke 2)) text-x))
         (tag-width  (if crop-right (+ tag-width txt-char-width) tag-width))
         (text-x     (if crop-right (+ text-x (/ stroke 2)) text-x))

         (svg (svg-create svg-width svg-height)))

    (if (>= stroke 0.25)
        (svg-rectangle svg tag-x 0 tag-width tag-height
                           :fill foreground :rx radius))
    (svg-rectangle svg (+ tag-x (/ stroke 2.0)) (/ stroke 2.0)
                       (- tag-width stroke) (- tag-height stroke)
                       :fill background :rx (- radius (/ stroke 2.0)))
    (svg-text svg label
              :font-family font-family :font-weight font-weight  :font-size font-size
              :fill foreground :x text-x :y  text-y)
    (svg-lib--image svg :ascent 'center)))

where I introduced txt-char-width and txt-char-height. Those appears to be badly set by respectively window-font-width and window-font-height functions.

I also uncommented the width parameter which acts like the height one.

Then, to get a svg with correct size appearance, I have to call svg-lib-tag as follows :

(svg-lib-tag "TODO" nil :height 0.5 :width 0.5 :font-size 8

Regards

@rougier
Copy link
Owner

rougier commented Aug 8, 2022

The 0.5 is because of your desktop magnification?

@TimotheeMathieu
Copy link

Hi,

just a small comment to say that the solution described by @deb75 did not to work for me as is. Instead I tweaked (in a very hackish way I am sure) svg-lib-tag with a scaling of 0.3.
Maybe this can help someone having the same problem.

The code
(defun svg-lib-tag (label &optional style &rest args)
  "Create an image displaying LABEL in a rounded box using given STYLE
and style elements ARGS."

  (let* ((default svg-lib-style-default)
         (my-scale 0.3)
         (style (if style (apply #'svg-lib-style nil style) default))
         (style (if args  (apply #'svg-lib-style style args) style))

         (foreground  (plist-get style :foreground))
         (background  (plist-get style :background))

         (crop-left   (plist-get style :crop-left))
         (crop-right  (plist-get style :crop-right))

         (alignment   (plist-get style :alignment))
         (stroke      (plist-get style :stroke))
         ;; (width       (plist-get style :width))
         (height      (plist-get style :height))
         (radius      (plist-get style :radius))
         ;; (scale       (plist-get style :scale))
         (margin      (plist-get style :margin))
         (padding     (plist-get style :padding))
         (font-size   (plist-get style :font-size))
         (font-family (plist-get style :font-family))
         (font-weight (plist-get style :font-weight))

         (txt-char-width  (window-font-width))
         (txt-char-height (window-font-height))
         (txt-char-height (if line-spacing
                              (+ txt-char-height line-spacing)
                            txt-char-height))
         (font-info       (font-info (format "%s-%d" font-family font-size)))
         (font-size       (aref font-info 2)) ;; redefine font-size
         (ascent          (aref font-info 8))
         (tag-char-width  (aref font-info 11))
         ;; (tag-char-height (aref font-info 3))
         (tag-width       (* (+ (length label) padding) txt-char-width))
         (tag-height      (* txt-char-height height))
         
         
         (svg-width       (+ tag-width (* margin txt-char-width)))
         (svg-height      tag-height)
         (svg-ascent      (plist-get style :ascent))
         
         ;;(stroke (* stroke my-scale))
         (ascent (* ascent my-scale))
         
         
         (tag-x  (* (- svg-width tag-width)  alignment))
         (text-x (+ tag-x (/ (- tag-width (* (length label) tag-char-width)) 2)))
         (text-y ascent)


         (tag-x      (if crop-left  (- tag-x     txt-char-width) tag-x))
         (tag-width  (if crop-left  (+ tag-width txt-char-width) tag-width))
         (text-x     (if crop-left  (- text-x (/ stroke 2)) text-x))
         (tag-width  (if crop-right (+ tag-width txt-char-width) tag-width))
         (text-x     (if crop-right (+ text-x (/ stroke 2)) text-x))

         (svg-width (* svg-width my-scale))
         (svg-height (* svg-height my-scale))

         (svg (svg-create svg-width svg-height))
         (font-size (* font-size my-scale))
         (tag-width (* tag-width my-scale))
         (tag-height (* tag-height my-scale))

         (text-x (* text-x my-scale))
         (radius (* radius my-scale))
         (tag-x (* tag-x my-scale))
         )

         

    (when (>= stroke 0.25)
      (svg-rectangle svg tag-x 0 tag-width tag-height
                     :fill foreground :rx radius))
    (svg-rectangle svg (+ tag-x (/ stroke 2.0)) (/ stroke 2.0)
                       (- tag-width stroke) (- tag-height stroke)
                       :fill background :rx (- radius (/ stroke 2.0)))
    (svg-text svg label
              :font-family font-family :font-weight font-weight  :font-size font-size
              :fill foreground :x text-x :y  text-y)
    (svg-lib--image svg :ascent svg-ascent)))

This worked for me. And yes the 0.3 in the code is due to the zoom of my hidpi screen. I am on linux and I use roughly a x3 zoom.

@rougier
Copy link
Owner

rougier commented Dec 5, 2022

Thanks for the report. Do you know of a way to get that factor from inside emacs?

@TimotheeMathieu
Copy link

TimotheeMathieu commented Dec 6, 2022

I didn't, but from one of the previous discussion there is this https://emacs.stackexchange.com/a/44930/37788 and using the my-dpi function described here, I got the value 283.358724043255 .

The real dpi (which represents the screen zoom from what I understand) is set to 288 for me using xrandr at the beginning of my X session (hence the around x3 zoom mentioned above which corresponds to dpi/100).

@rougier
Copy link
Owner

rougier commented Dec 19, 2022

But what is the relation with the 0.3 scaling you're using ? Is there a default dpi somewhere that we need to take into account?

@TimotheeMathieu
Copy link

TimotheeMathieu commented Dec 19, 2022

By default Xorg set dpi to 96 (ref https://wiki.archlinux.org/title/xorg#Display_size_and_DPI) , so my 288 / 96 gives me the x3 zoom.

I don't know how windows does it, I also don't know about Wayland.

@rougier
Copy link
Owner

rougier commented Dec 20, 2022

Can you check if changing the OS dpi make your formula consistent?

@TimotheeMathieu
Copy link

Yes, here is with dpi 288 and svg-lib my-scale 0.33:
image
and here is the exact same text with dpi 150 and svg-lib my-scale 0.64:
image

This seems to be Ok from what I can tell the formula works to have svg scaled like the text.

@rougier
Copy link
Owner

rougier commented Dec 22, 2022

Thanks. Can you post here the function to get the scale such I can test it on my setup?

@TimotheeMathieu
Copy link

Yes, here it is, with the result from my high dpi computer

#+begin_src emacs-lisp
(defun my-scale (&optional frame)
  "Get the Scale of FRAME (or current if nil), with convention that default dpi is 96."
  (cl-flet ((pyth (lambda (w h)
                    (sqrt (+ (* w w)
                             (* h h)))))
            (mm2in (lambda (mm)
                     (/ mm 25.4)))) ;; one inch is 2.54 cm
    (let* ((atts (frame-monitor-attributes frame))
           (pix-w (cl-fourth (assoc 'geometry atts)))
           (pix-h (cl-fifth (assoc 'geometry atts)))
           (pix-d (pyth pix-w pix-h))
           (mm-w (cl-second (assoc 'mm-size atts)))
           (mm-h (cl-third (assoc 'mm-size atts)))
           (mm-d (pyth mm-w mm-h)))
      (/ (/ pix-d (mm2in mm-d)) 96) ;; by default screen is set to 96 dpi with xrandr
      )))
(my-scale)
#+end_src

#+RESULTS:
: 2.9516533754505727

@rougier
Copy link
Owner

rougier commented Dec 26, 2022

And I get 1.3754182138787545 on my system which is wrong since I do not need a scale. If I replace 96 with (org--get-display-dpi) it seems to be working. Does that work for you too?

(defun org--get-display-dpi ()
  "Get the DPI of the display.
The function assumes that the display has the same pixel width in
the horizontal and vertical directions."
  (if (display-graphic-p)
      (round (/ (display-pixel-height)
		(/ (display-mm-height) 25.4)))
    (error "Attempt to calculate the dpi of a non-graphic display")))

@TimotheeMathieu
Copy link

TimotheeMathieu commented Dec 26, 2022

For me, the (org--get-display-dpi) should not replace the 96, it replaces my-dpi, its value is 289 for me, so using this function I get the zoom with

(defun my-scale (&optional frame)
  "Get the Scale of FRAME (or current if nil), with convention that default dpi is 96."
  (/ (org--get-display-dpi) 96))

which results in 3 for me (this is in fact more precise than the dpi function proposed before).

@rougier
Copy link
Owner

rougier commented Dec 26, 2022

We thus need to find what is the equivalent of this 96 dpi default for all systems.

@TimotheeMathieu
Copy link

I am guessing you are on Mac OS since according to Wikipedia Mac OS default to 72 dpi which should explain the value you gave above. Wikipedia also says that Windows default to 96 (same as Linux). Maybe detecting the OS would be sufficient ? Plus a user override in case it fails.

@rougier
Copy link
Owner

rougier commented Dec 26, 2022

Even with 72, the scale is wrong in my case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants