unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Alan Third <alan@idiocy.org>
To: Paul Eggert <eggert@cs.ucla.edu>
Cc: Glenn Morris <rgm@gnu.org>, Lars Ingebrigtsen <larsi@gnus.org>,
	emacs-devel@gnu.org
Subject: Re: Linking to ImageMagick by default
Date: Mon, 10 Dec 2018 22:09:44 +0000	[thread overview]
Message-ID: <20181210220944.GA4793@breton.holly.idiocy.org> (raw)
In-Reply-To: <fcb9e4e8-c09a-2124-b1fe-444f4a87efed@cs.ucla.edu>

[-- Attachment #1: Type: text/plain, Size: 1888 bytes --]

On Sat, Dec 08, 2018 at 01:24:13PM -0800, Paul Eggert wrote:
> Alan Third wrote:
> > In case anyone cares, I looked into this and XRender would do the
> > trick. I had a look at how to go about it, but as usual with X stuff
> > it looks a fair bit more complicated than with NS (and Windows), and I
> > don’t have a good X environment to play about in.
> 
> I have an X environment (and a Wayland one too); could you please post any
> code you wrote, if you think the idea is worth a try?

The attached appears to somewhat work (at least on my incredibly slow
atom laptop). It’s not really workable in its current form. It’s slow
because it has to load the image each time due to the way image
caching works. I think there are a number of other places we may need
to replace XCopyArea. It doesn’t handle the case where XRender isn’t
available.

Nor with animated gifs in X. They’re fine in NS... ¯\_(ツ)_/¯

It also doesn’t play nice with imagemagick, so make sure to build
--without-imagemagick.

If we want to go with this method I’ll have to rewrite some of the
image handling code. At the moment we create one ‘struct image’ per
lisp image spec, and store the image in the image cache, but this
means if the same image is displayed twice at two different sizes we
load it twice and store it twice. OTOH, it’s the resized version
that’s stored, so that might save memory if we assume people are
mostly shrinking images.

What I’ve done in the attached would work better if we only loaded the
image once and didn’t tie it to an image spec, so we’d only keep one
(full size) copy in memory, and just resize it on demand. I’m unsure
how we’d go about detangling the image data from the image spec.

It may be possible to use XRender (and NSImage resizing) when we load
the image, and therefore work in the same way we do at the moment.
-- 
Alan Third

[-- Attachment #2: 0001-Scaling-PoC.patch --]
[-- Type: text/plain, Size: 7953 bytes --]

From e1969beea284022ab721b452a43736b49cf74ce3 Mon Sep 17 00:00:00 2001
From: Alan Third <alan@idiocy.org>
Date: Mon, 10 Dec 2018 19:43:08 +0000
Subject: [PATCH] Scaling PoC

---
 lisp/image.el    |  2 --
 src/dispextern.h |  7 +++++++
 src/image.c      | 51 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/nsimage.m    |  2 +-
 src/nsterm.m     |  7 ++++---
 src/xterm.c      | 48 +++++++++++++++++++++++++++++++++++++--------
 6 files changed, 103 insertions(+), 14 deletions(-)

diff --git a/lisp/image.el b/lisp/image.el
index 74a23046e9..8989fceefd 100644
--- a/lisp/image.el
+++ b/lisp/image.el
@@ -982,8 +982,6 @@ image--get-image
     image))
 
 (defun image--get-imagemagick-and-warn ()
-  (unless (or (fboundp 'imagemagick-types) (featurep 'ns))
-    (error "Cannot rescale images without ImageMagick support"))
   (let ((image (image--get-image)))
     (image-flush image)
     (when (fboundp 'imagemagick-types)
diff --git a/src/dispextern.h b/src/dispextern.h
index 4cd017603d..490cc10c6c 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2987,6 +2987,13 @@ struct image
   /* Width and height of the image.  */
   int width, height;
 
+  /* Width and height of the image data.  */
+  int actual_width, actual_height;
+
+  /* The scaling factor between the actual image data and the
+     output.  */
+  double scale;
+
   /* These values are used for the rectangles displayed for images
      that can't be loaded.  */
 #define DEFAULT_IMAGE_WIDTH 30
diff --git a/src/image.c b/src/image.c
index 633d66e7a7..8bda88a6ce 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1748,6 +1748,55 @@ postprocess_image (struct frame *f, struct image *img)
 }
 
 
+static void
+set_image_size (struct image *img, Lisp_Object spec)
+{
+  Lisp_Object value;
+  int width = INT_MAX, height = INT_MAX;
+  double scale = 1;
+
+  img->actual_width = img->width;
+  img->actual_height = img->height;
+
+  value = image_spec_value (spec, QCscale, NULL);
+  if (NUMBERP (value))
+    scale = XFLOATINT (value);
+
+  /* Calculate the maximum width and height.  */
+  value = image_spec_value (spec, QCmax_width, NULL);
+  if (FIXNATP (value))
+    width = XFIXNAT (value);
+
+  value = image_spec_value (spec, QCmax_height, NULL);
+  if (FIXNATP (value))
+    height = XFIXNAT (value);
+
+  value = image_spec_value (spec, QCwidth, NULL);
+  if (FIXNATP (value))
+    width = min (XFIXNAT (value) * scale, width);
+
+  value = image_spec_value (spec, QCheight, NULL);
+  if (FIXNATP (value))
+    height = min (XFIXNAT (value) * scale, height);
+
+  /* Calculate the final scaling factor.  */
+  if (img->width * scale > width)
+    scale = (double) img->width / width;
+
+  if (img->height * scale > height)
+    scale = (double) img->height / height;
+
+  /* Set the final sizes.  We always maintain the aspect ratio.  */
+  if (scale != 1)
+    {
+      img->width *= scale;
+      img->height *= scale;
+    }
+
+  img->scale = scale;
+}
+
+
 /* Return the id of image with Lisp specification SPEC on frame F.
    SPEC must be a valid Lisp image specification (see valid_image_p).  */
 
@@ -1803,6 +1852,8 @@ lookup_image (struct frame *f, Lisp_Object spec)
 	  Lisp_Object ascent, margin, relief, bg;
 	  int relief_bound;
 
+          set_image_size (img, spec);
+
 	  ascent = image_spec_value (spec, QCascent, NULL);
 	  if (FIXNUMP (ascent))
 	    img->ascent = XFIXNAT (ascent);
diff --git a/src/nsimage.m b/src/nsimage.m
index 0ae1b88edd..cc3aceae69 100644
--- a/src/nsimage.m
+++ b/src/nsimage.m
@@ -126,7 +126,7 @@ Updated by Christian Limpach (chris@nice.ch)
       eImg = temp;
     }
 
-  [eImg setSizeFromSpec:XCDR (img->spec)];
+  //[eImg setSizeFromSpec:XCDR (img->spec)];
 
   size = [eImg size];
   img->width = size.width;
diff --git a/src/nsterm.m b/src/nsterm.m
index 6c285f0abb..db357a9623 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -3828,6 +3828,7 @@ Function modeled after x_draw_glyph_string_box ().
   NSRect br;
   struct face *face;
   NSColor *tdCol;
+  double scale = s->img->scale;
 
   NSTRACE ("ns_dumpglyphs_image");
 
@@ -3877,9 +3878,9 @@ Function modeled after x_draw_glyph_string_box ().
     {
 #ifdef NS_IMPL_COCOA
       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
-      NSRect ir = NSMakeRect (s->slice.x,
-                              s->img->height - s->slice.y - s->slice.height,
-                              s->slice.width, s->slice.height);
+      NSRect ir = NSMakeRect (s->slice.x / scale,
+                              (s->img->height - s->slice.y - s->slice.height) / scale,
+                              s->slice.width / scale , s->slice.height / scale);
       [img drawInRect: dr
              fromRect: ir
              operation: NSCompositingOperationSourceOver
diff --git a/src/xterm.c b/src/xterm.c
index 3a7e31e712..f3d0af4177 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -136,6 +136,9 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include <X11/XKBlib.h>
 #endif
 
+#include <X11/extensions/Xrender.h>
+#include <X11/extensions/Xcomposite.h>
+
 /* Default to using XIM if available.  */
 #ifdef USE_XIM
 bool use_xim = true;
@@ -2970,6 +2973,39 @@ x_draw_glyph_string_box (struct glyph_string *s)
 }
 
 
+static void
+x_composite_image (struct glyph_string *s, Pixmap dest,
+                   int srcX, int srcY, int dstX, int dstY,
+                   int width, int height)
+{
+  Picture source, destination;
+  XRenderPictFormat *default_format, *source_format;
+  XRenderPictureAttributes source_attr, dest_attr;
+
+  double scale = s->img->scale;
+  XTransform tmat = {{{XDoubleToFixed (1), XDoubleToFixed (0), XDoubleToFixed (0)},
+                      {XDoubleToFixed (0), XDoubleToFixed (1), XDoubleToFixed (0)},
+                      {XDoubleToFixed (0), XDoubleToFixed (0), XDoubleToFixed (scale)}}};
+
+  default_format = XRenderFindVisualFormat (s->display, DefaultVisual (s->display, 0));
+  source_format = XRenderFindStandardFormat (s->display, PictStandardRGB24);
+
+  source = XRenderCreatePicture (s->display, s->img->pixmap, source_format, 0, &source_attr);
+  destination = XRenderCreatePicture (s->display, dest, default_format, 0, &dest_attr);
+
+  XRenderSetPictureTransform (s->display, source, &tmat);
+
+  XRenderComposite (s->display, PictOpOver, source, None, destination,
+                    srcX*scale, srcY*scale,
+                    0, 0,
+                    dstX, dstY,
+                    width, height);
+
+  XRenderFreePicture (s->display, source);
+  XRenderFreePicture (s->display, destination);
+}
+
+
 /* Draw foreground of image glyph string S.  */
 
 static void
@@ -3018,10 +3054,8 @@ x_draw_image_foreground (struct glyph_string *s)
 	  image_rect.width = s->slice.width;
 	  image_rect.height = s->slice.height;
 	  if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
-            XCopyArea (s->display, s->img->pixmap,
-                       FRAME_X_DRAWABLE (s->f), s->gc,
-		       s->slice.x + r.x - x, s->slice.y + r.y - y,
-		       r.width, r.height, r.x, r.y);
+            x_composite_image (s, FRAME_X_DRAWABLE (s->f), s->slice.x + r.x - x, s->slice.y + r.y - y,
+                               r.x, r.y, r.width, r.height);
 	}
       else
 	{
@@ -3033,10 +3067,8 @@ x_draw_image_foreground (struct glyph_string *s)
 	  image_rect.width = s->slice.width;
 	  image_rect.height = s->slice.height;
 	  if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
-            XCopyArea (s->display, s->img->pixmap,
-                       FRAME_X_DRAWABLE (s->f), s->gc,
-		       s->slice.x + r.x - x, s->slice.y + r.y - y,
-		       r.width, r.height, r.x, r.y);
+            x_composite_image (s, FRAME_X_DRAWABLE (s->f), s->slice.x + r.x - x, s->slice.y + r.y - y,
+                               r.x, r.y, r.width, r.height);
 
 	  /* When the image has a mask, we can expect that at
 	     least part of a mouse highlight or a block cursor will
-- 
2.19.1


  reply	other threads:[~2018-12-10 22:09 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-02  1:33 Linking to ImageMagick by default Glenn Morris
2018-12-02 18:15 ` Paul Eggert
2018-12-05 13:30 ` Lars Ingebrigtsen
2018-12-05 15:28   ` Stefan Monnier
2018-12-06 11:06     ` Lars Ingebrigtsen
2018-12-05 17:24   ` Glenn Morris
2018-12-05 17:27     ` Lars Ingebrigtsen
2018-12-05 18:27     ` Daniel Pittman
2018-12-05 18:38       ` Lars Ingebrigtsen
2018-12-05 19:31     ` joakim
2018-12-05 22:39   ` Alan Third
2018-12-08 18:38     ` Alan Third
2018-12-08 21:24       ` Paul Eggert
2018-12-10 22:09         ` Alan Third [this message]
2018-12-19 16:03           ` Alan Third
2018-12-19 16:36             ` Eli Zaretskii
2018-12-19 16:45               ` Joseph Garvin
2018-12-27 15:06                 ` Alan Third
2018-12-27 13:11               ` Alan Third
2018-12-27 16:05                 ` Eli Zaretskii
2018-12-27 20:37                   ` Juri Linkov
2018-12-28  8:12                 ` Eli Zaretskii
2018-12-28 21:21                   ` Alan Third
2018-12-29  6:56                     ` Eli Zaretskii
2018-12-29 21:31                       ` Juri Linkov
2018-12-30 12:47                       ` Alan Third
2019-01-01 21:47                         ` [PATCH] Add native image scaling Alan Third
2019-01-02 16:11                           ` Eli Zaretskii
2019-01-02 21:12                             ` [PATCH v2] Add native image scaling (bug#33587) Alan Third
2019-01-04 14:31                               ` Eli Zaretskii
2019-01-04 19:09                                 ` Alan Third
2019-01-04 20:21                                   ` Eli Zaretskii
2019-01-04 22:45                                     ` Alan Third
2019-01-10 19:42                                       ` Alan Third
2019-01-10 19:50                                         ` Eli Zaretskii
2019-01-10 23:40                                         ` Paul Eggert
2019-01-06 16:26                                   ` Eli Zaretskii
2019-01-05 21:30                               ` Track mouse drags over an image (was: Add native image scaling) Roland Winkler
2019-01-08 18:20                                 ` Track mouse drags over an image Stefan Monnier
2019-01-11  4:55                                   ` Roland Winkler
2019-01-11 16:23                                     ` Stefan Monnier
2018-12-09 11:34       ` Linking to ImageMagick by default Elias Mårtenson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181210220944.GA4793@breton.holly.idiocy.org \
    --to=alan@idiocy.org \
    --cc=eggert@cs.ucla.edu \
    --cc=emacs-devel@gnu.org \
    --cc=larsi@gnus.org \
    --cc=rgm@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).