From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Alan Third Newsgroups: gmane.emacs.devel Subject: Image resizing and rotation on NS port without imagemagick Date: Sun, 8 Oct 2017 21:38:22 +0100 Message-ID: <20171008203822.GA22846@breton.holly.idiocy.org> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="jRHKVT23PllUwdXP" Content-Transfer-Encoding: 8bit X-Trace: blaine.gmane.org 1507495158 7299 195.159.176.226 (8 Oct 2017 20:39:18 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Sun, 8 Oct 2017 20:39:18 +0000 (UTC) User-Agent: Mutt/1.9.0 (2017-09-02) To: Emacs-Devel devel Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sun Oct 08 22:39:11 2017 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1e1ILs-0000aV-FC for ged-emacs-devel@m.gmane.org; Sun, 08 Oct 2017 22:39:08 +0200 Original-Received: from localhost ([::1]:55062 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e1ILx-0003q0-TC for ged-emacs-devel@m.gmane.org; Sun, 08 Oct 2017 16:39:13 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:59923) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e1ILE-0003pt-CI for emacs-devel@gnu.org; Sun, 08 Oct 2017 16:38:29 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e1ILC-0000Rv-NQ for emacs-devel@gnu.org; Sun, 08 Oct 2017 16:38:28 -0400 Original-Received: from mail-wm0-x22a.google.com ([2a00:1450:400c:c09::22a]:51218) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1e1ILC-0000RV-C1 for emacs-devel@gnu.org; Sun, 08 Oct 2017 16:38:26 -0400 Original-Received: by mail-wm0-x22a.google.com with SMTP id f4so18622329wme.0 for ; Sun, 08 Oct 2017 13:38:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20161025; h=sender:date:from:to:subject:message-id:mime-version :content-disposition:content-transfer-encoding:user-agent; bh=xtd+4g0wgt5k25303gUwgrSAl+ilpX5z17QrCcyxV4c=; b=pINBxca+ei9CCcydxxJU/gw3ER+z0fRjMgadG9POTRxLo2tQdpeh87n6Odcz+8U7+b lfqOiZHnj0mpCC3HHi531M1TSZHaeJC0jUoSLj1QFKyEC2uauzYtQuIKRVC18aVpRrVG 7+ZCYwHRI8FLr7sO58CeTqfAzWWRF9CL9AXJ8aVxbjHxVEOqj8nrFz8kSzy44InynQeO BhHUQfr8Y1aQFPYpg5W8cdUJCk/ovc6wj13DCh9bqulIy6sLZUnctOd9ATSmAxJJbJBh L7NIBmdAta+kV9gklFIDOYslo//JSpCI1Hw/Jnp8+sTyOwUkkqpf4O70UKnKn7JepwzE K4Hw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:subject:message-id :mime-version:content-disposition:content-transfer-encoding :user-agent; bh=xtd+4g0wgt5k25303gUwgrSAl+ilpX5z17QrCcyxV4c=; b=YJ47lOTG7D7gibC6MO1nowsCSPwrnjVVVJCIW8WovYXbPrLeE5jEJ36cC/YUds35KR TexksavBs+vyQx8bhMKjq/u4qBEuN6k7vbOhCctZFiWvGhZrjBKhwQI7UQTWxtNX3q+A BDTqtpahWblhytPfnhYjrc3BGT+R1M9K6rwng46+oyNhSYmP6EOVwvqWeMz8Z6JUjR22 vXEt+T7DbnCjFuDxikMNwCICzdm2v2WMqJ+oNQV6n+nrNyF8zgFlJmkeVXqxZQggJdRK HwZSI+H/2KUNHSi8yzpFC4tDapElbcAPGsrcktOWubtlVwuiOkGfXVJcfVhf5RCjqPcU pmsw== X-Gm-Message-State: AMCzsaW9M0jCyL1gemMM4eobwClcfuFiA8SBpWgEiPryKe709z1A8ACq zEPbLwxwBUZZXlmpwRstcDLJTXbW X-Google-Smtp-Source: AOwi7QDBFti/fzoOz9IkJtvgaIZG16XSRwTqUIcpSElvBoSIcqAzpIxoP+VXtK5Zu3CQJE7r53SWfw== X-Received: by 10.223.196.199 with SMTP id o7mr7257489wrf.119.1507495104825; Sun, 08 Oct 2017 13:38:24 -0700 (PDT) Original-Received: from breton.holly.idiocy.org (ip6-2001-08b0-03f8-8129-7ce7-3aeb-01e4-c435.holly.idiocy.org. [2001:8b0:3f8:8129:7ce7:3aeb:1e4:c435]) by smtp.gmail.com with ESMTPSA id f11sm12688849wra.79.2017.10.08.13.38.23 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 08 Oct 2017 13:38:24 -0700 (PDT) Content-Disposition: inline X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:400c:c09::22a X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:219270 Archived-At: --jRHKVT23PllUwdXP Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit 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 --jRHKVT23PllUwdXP Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0001-Add-image-resizing-and-rotation-to-NS-port.patch" >From 58351a5899ae2f6c040e48fb6852a3cd96a72401 Mon Sep 17 00:00:00 2001 From: Alan Third 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 --jRHKVT23PllUwdXP--