unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Image resizing and rotation on NS port without imagemagick
@ 2017-10-08 20:38 Alan Third
  2017-10-08 20:53 ` Lars Ingebrigtsen
  2017-10-11 18:27 ` Charles A. Roelli
  0 siblings, 2 replies; 5+ messages in thread
From: Alan Third @ 2017-10-08 20:38 UTC (permalink / raw)
  To: Emacs-Devel devel

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

It’s always kind of bugged me that I need imagemagick to do image
resizing when Cocoa and GNUstep support it natively, so I’ve finally
got round to implementing it.

It seems to work fine. Any comments are welcome.

NOTE: if you have libjpg, libpng, or whatever installed, configure
includes them and emacs will use them preferentially over the built‐in
EmacsImage stuff, so you may need to use

    --without-png --without-gif --without-jpeg

I imagine there’s a way to switch the default to not use them when
compiling --with-ns?
-- 
Alan Third

[-- Attachment #2: 0001-Add-image-resizing-and-rotation-to-NS-port.patch --]
[-- Type: text/plain, Size: 6487 bytes --]

From 58351a5899ae2f6c040e48fb6852a3cd96a72401 Mon Sep 17 00:00:00 2001
From: Alan Third <alan@idiocy.org>
Date: Sun, 8 Oct 2017 11:08:16 +0100
Subject: [PATCH] Add image resizing and rotation to NS port

* lisp/image.el (image--get-imagemagick-and-warn): Bypass imagemagick
check when using NS.
* src/nsimage.m (ns_load_image): Add rotation and resizing
functionality. Move the getMetaData call to before the resize/rotation
so it returns correct metadata.
(EmacsImage::setSizeFromSpec, EmacsImage::rotate): New functions.
* src/nsterm.h (EmacsImage): Add new function prototypes.
(NSCompositingOperationCopy): Add define to older equivalent for
GNUstep and pre-10.12 macOS.
---
 lisp/image.el |   5 ++-
 src/nsimage.m | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/nsterm.h  |   3 ++
 3 files changed, 120 insertions(+), 4 deletions(-)

diff --git a/lisp/image.el b/lisp/image.el
index 1d0776180b..f20eeb6c16 100644
--- a/lisp/image.el
+++ b/lisp/image.el
@@ -976,11 +976,12 @@ image--get-image
     image))
 
 (defun image--get-imagemagick-and-warn ()
-  (unless (fboundp 'imagemagick-types)
+  (unless (or (fboundp 'imagemagick-types) (featurep 'ns))
     (error "Can't rescale images without ImageMagick support"))
   (let ((image (image--get-image)))
     (image-flush image)
-    (plist-put (cdr image) :type 'imagemagick)
+    (when (fboundp 'imagemagick-types)
+      (plist-put (cdr image) :type 'imagemagick))
     image))
 
 (defun image--change-size (factor)
diff --git a/src/nsimage.m b/src/nsimage.m
index 9d45b063af..52e3bae05f 100644
--- a/src/nsimage.m
+++ b/src/nsimage.m
@@ -76,8 +76,9 @@ Updated by Christian Limpach (chris@nice.ch)
 {
   EmacsImage *eImg = nil;
   NSSize size;
-  Lisp_Object lisp_index;
+  Lisp_Object lisp_index, lisp_rotation;
   unsigned int index;
+  double rotation;
 
   NSTRACE ("ns_load_image");
 
@@ -86,6 +87,9 @@ Updated by Christian Limpach (chris@nice.ch)
   lisp_index = Fplist_get (XCDR (img->spec), QCindex);
   index = INTEGERP (lisp_index) ? XFASTINT (lisp_index) : 0;
 
+  lisp_rotation = Fplist_get (XCDR (img->spec), QCrotation);
+  rotation = NUMBERP (lisp_rotation) ? XFLOATINT (lisp_rotation) : 0;
+
   if (STRINGP (spec_file))
     {
       eImg = [EmacsImage allocInitFromFile: spec_file];
@@ -113,6 +117,17 @@ Updated by Christian Limpach (chris@nice.ch)
       return 0;
     }
 
+  img->lisp_data = [eImg getMetadata];
+
+  if (rotation != 0)
+    {
+      EmacsImage *temp = [eImg rotate:rotation];
+      [eImg release];
+      eImg = temp;
+    }
+
+  [eImg setSizeFromSpec:XCDR (img->spec)];
+
   size = [eImg size];
   img->width = size.width;
   img->height = size.height;
@@ -120,7 +135,6 @@ Updated by Christian Limpach (chris@nice.ch)
   /* 4) set img->pixmap = emacsimage */
   img->pixmap = eImg;
 
-  img->lisp_data = [eImg getMetadata];
   return 1;
 }
 
@@ -510,4 +524,102 @@ - (BOOL)setFrame: (unsigned int) index
   return YES;
 }
 
+- (void)setSizeFromSpec: (Lisp_Object) spec
+{
+  NSSize size = [self size];
+  Lisp_Object value;
+  double scale = 1, aspect = size.width / size.height;
+  double width = -1, height = -1, max_width = -1, max_height = -1;
+
+  value = Fplist_get (spec, QCscale);
+  if (NUMBERP (value))
+    scale = XFLOATINT (value) ;
+
+  value = Fplist_get (spec, QCmax_width);
+  if (NUMBERP (value))
+    max_width = XFLOATINT (value);
+
+  value = Fplist_get (spec, QCmax_height);
+  if (NUMBERP (value))
+    max_height = XFLOATINT (value);
+
+  value = Fplist_get (spec, QCwidth);
+  if (NUMBERP (value))
+    {
+      width = XFLOATINT (value) * scale;
+      /* :width overrides :max-width. */
+      max_width = -1;
+    }
+
+  value = Fplist_get (spec, QCheight);
+  if (NUMBERP (value))
+    {
+      height = XFLOATINT (value) * scale;
+      /* :height overrides :max-height. */
+      max_height = -1;
+    }
+
+  if (width <= 0 && height <= 0)
+    {
+      width = size.width * scale;
+      height = size.height * scale;
+    }
+  else if (width > 0 && height <= 0)
+      height = width / aspect;
+  else if (height > 0 && width <= 0)
+      width = height * aspect;
+
+  if (max_width > 0 && width > max_width)
+    {
+      width = max_width;
+      height = max_width / aspect;
+    }
+
+  if (max_height > 0 && height > max_height)
+    {
+      height = max_height;
+      width = max_height * aspect;
+    }
+
+  [self setSize:NSMakeSize(width, height)];
+}
+
+- (instancetype)rotate: (double)rotation
+{
+  EmacsImage *new_image;
+  NSPoint new_origin;
+  NSSize new_size, size = [self size];
+  NSRect rect = { NSZeroPoint, [self size] };
+
+  /* Create a bezier path of the outline of the image and do the
+   * rotation on it.  */
+  NSBezierPath *bounds_path = [NSBezierPath bezierPathWithRect:rect];
+  NSAffineTransform *transform = [NSAffineTransform transform];
+  [transform rotateByDegrees: rotation * -1];
+  [bounds_path transformUsingAffineTransform:transform];
+
+  /* Now we can find out how large the rotated image needs to be.  */
+  new_size = [bounds_path bounds].size;
+  new_image = [[EmacsImage alloc] initWithSize:new_size];
+
+  new_origin = NSMakePoint((new_size.width - size.width)/2,
+                           (new_size.height - size.height)/2);
+
+  [new_image lockFocus];
+
+  /* Create the final transform.  */
+  transform = [NSAffineTransform transform];
+  [transform translateXBy:new_size.width/2 yBy:new_size.height/2];
+  [transform rotateByDegrees: rotation * -1];
+  [transform translateXBy:-new_size.width/2 yBy:-new_size.height/2];
+
+  [transform concat];
+  [self drawAtPoint:new_origin fromRect:NSZeroRect
+          operation:NSCompositingOperationCopy fraction:1];
+
+  [new_image unlockFocus];
+
+  return new_image;
+}
+
 @end
diff --git a/src/nsterm.h b/src/nsterm.h
index de96e0dbcb..c81bf5fb63 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -646,6 +646,8 @@ typedef id instancetype;
 - (NSColor *)stippleMask;
 - (Lisp_Object)getMetadata;
 - (BOOL)setFrame: (unsigned int) index;
+- (void)setSizeFromSpec: (Lisp_Object) spec;
+- (instancetype)rotate: (double)rotation;
 @end
 
 
@@ -1306,6 +1308,7 @@ extern char gnustep_base_version[];  /* version tracking */
 #define NSWindowStyleMaskUtilityWindow     NSUtilityWindowMask
 #define NSAlertStyleCritical               NSCriticalAlertStyle
 #define NSControlSizeRegular               NSRegularControlSize
+#define NSCompositingOperationCopy         NSCompositeCopy
 
 /* And adds NSWindowStyleMask. */
 #ifdef __OBJC__
-- 
2.14.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2017-10-11 19:17 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-10-08 20:38 Image resizing and rotation on NS port without imagemagick Alan Third
2017-10-08 20:53 ` Lars Ingebrigtsen
2017-10-08 22:01   ` Alan Third
2017-10-11 18:27 ` Charles A. Roelli
2017-10-11 19:17   ` Alan Third

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).