unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* imagemagic in image-mode and image-dired-thumbnail-mode?
@ 2013-07-14  7:25 Vitalie Spinu
  2013-07-14  8:32 ` joakim
  0 siblings, 1 reply; 55+ messages in thread
From: Vitalie Spinu @ 2013-07-14  7:25 UTC (permalink / raw)
  To: emacs-devel


Hello, 

For a new process-output-image-manipulation project I was looking for a
generic image mode. Surprisingly, it looks like none of the existing
modes is flexible/customizable/feature rich enough to be used as a
prototype for such a project.
 
Particularly, an essential feature for image scaling, imagemagic, is
still not supported by basic image modes. Image-dired-thumbnail-mode has
no idea of imagemagic at all.  Image-mode cannot open imagemagic types
as image-toggle-display-image hardcodes image type:

╭──────── #616 ─ lisp/image-mode.el ──
│ 	 (type (image-type file-or-data nil data-p))
╰──────── #616 ─

Is there a hidden reason why image scaling is not yet implemented?

   ;; Not yet implemented.
   ;; (defvar image-transform-minor-mode-map
   ;;   (let ((map (make-sparse-keymap)))
   ;;     ;; (define-key map  [(control ?+)] 'image-scale-in)
   ;;     ;; (define-key map  [(control ?-)] 'image-scale-out)
   ;;     ;; (define-key map  [(control ?=)] 'image-scale-none)
   ;;     ;; (define-key map "c f h" 'image-scale-fit-height)
   ;;     ;; (define-key map "c ]" 'image-rotate-right)
   ;;     map)
   ;;   "Minor mode keymap `image-transform-mode'.")


I naturally wonder if there should be a global user custom variable
like:

   (defcustom image-view-type (and (image-type-available-p 'imagemagick)
                                   'imagemagick))

with all image modes taking it into account?

On a related note, wouldn't image-mode be better off if implemented on
top of some image-thumbnail-mode? Or maybe better, shouldn't image-mode
support multiple images per buffer, and then other modes like
image-dired-thumbnail-mode to derive from it?

    Vitalie




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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-14  7:25 imagemagic in image-mode and image-dired-thumbnail-mode? Vitalie Spinu
@ 2013-07-14  8:32 ` joakim
  2013-07-14 11:48   ` Vitalie Spinu
  2013-07-14 18:33   ` Glenn Morris
  0 siblings, 2 replies; 55+ messages in thread
From: joakim @ 2013-07-14  8:32 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: emacs-devel

Vitalie Spinu <spinuvit@gmail.com> writes:

> Hello, 
>
> For a new process-output-image-manipulation project I was looking for a
> generic image mode. Surprisingly, it looks like none of the existing
> modes is flexible/customizable/feature rich enough to be used as a
> prototype for such a project.
>  
> Particularly, an essential feature for image scaling, imagemagic, is
> still not supported by basic image modes. Image-dired-thumbnail-mode has
> no idea of imagemagic at all.  Image-mode cannot open imagemagic types
> as image-toggle-display-image hardcodes image type:
>
> ╭──────── #616 ─ lisp/image-mode.el ──
> │ 	 (type (image-type file-or-data nil data-p))
> ╰──────── #616 ─
>
> Is there a hidden reason why image scaling is not yet implemented?
>
>    ;; Not yet implemented.
>    ;; (defvar image-transform-minor-mode-map
>    ;;   (let ((map (make-sparse-keymap)))
>    ;;     ;; (define-key map  [(control ?+)] 'image-scale-in)
>    ;;     ;; (define-key map  [(control ?-)] 'image-scale-out)
>    ;;     ;; (define-key map  [(control ?=)] 'image-scale-none)
>    ;;     ;; (define-key map "c f h" 'image-scale-fit-height)
>    ;;     ;; (define-key map "c ]" 'image-rotate-right)
>    ;;     map)
>    ;;   "Minor mode keymap `image-transform-mode'.")
>

I worked on scaling support for image mode when I worked on the original ImageMagik patch.
However, I didnt have time to finish the support. The above keymap was
probably written by someone else, have a look in the log.

At any rate, as I recall, there are no reasons not to implement scaling
support in image mode, Someone(TM) just needs to invest some energy. It
shouldnt even be very hard.

>
> I naturally wonder if there should be a global user custom variable
> like:
>
>    (defcustom image-view-type (and (image-type-available-p 'imagemagick)
>                                    'imagemagick))
>
> with all image modes taking it into account?
>
> On a related note, wouldn't image-mode be better off if implemented on
> top of some image-thumbnail-mode? Or maybe better, shouldn't image-mode
> support multiple images per buffer, and then other modes like
> image-dired-thumbnail-mode to derive from it?
>
>     Vitalie
>
>

-- 
Joakim Verona



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-14  8:32 ` joakim
@ 2013-07-14 11:48   ` Vitalie Spinu
  2013-07-14 12:40     ` joakim
  2013-07-14 12:42     ` Lars Magne Ingebrigtsen
  2013-07-14 18:33   ` Glenn Morris
  1 sibling, 2 replies; 55+ messages in thread
From: Vitalie Spinu @ 2013-07-14 11:48 UTC (permalink / raw)
  To: joakim; +Cc: emacs-devel

 >> joakim@verona.se
 >> on Sun, 14 Jul 2013 10:32:50 +0200 wrote:

[...]


 > At any rate, as I recall, there are no reasons not to implement scaling
 > support in image mode, Someone(TM) just needs to invest some energy. It
 > shouldnt even be very hard.

 >> 
 >> I naturally wonder if there should be a global user custom variable
 >> like:
 >> 
 >> (defcustom image-view-type (and (image-type-available-p 'imagemagick)
 >> 'imagemagick))
 >> 

How about this one? Would it ever make sense to use libjpeg or libpng if
imagemagick support is available? If not, then image-mode and
image-dired can use imagemagick whenever present and no custom var is
necessary.

    Vitalie



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-14 11:48   ` Vitalie Spinu
@ 2013-07-14 12:40     ` joakim
  2013-07-14 13:01       ` Vitalie Spinu
  2013-07-14 12:42     ` Lars Magne Ingebrigtsen
  1 sibling, 1 reply; 55+ messages in thread
From: joakim @ 2013-07-14 12:40 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: emacs-devel

Vitalie Spinu <spinuvit@gmail.com> writes:

>  >> joakim@verona.se
>  >> on Sun, 14 Jul 2013 10:32:50 +0200 wrote:
>
> [...]
>
>
>  > At any rate, as I recall, there are no reasons not to implement scaling
>  > support in image mode, Someone(TM) just needs to invest some energy. It
>  > shouldnt even be very hard.
>
>  >> 
>  >> I naturally wonder if there should be a global user custom variable
>  >> like:
>  >> 
>  >> (defcustom image-view-type (and (image-type-available-p 'imagemagick)
>  >> 'imagemagick))
>  >> 
>
> How about this one? Would it ever make sense to use libjpeg or libpng if
> imagemagick support is available? If not, then image-mode and
> image-dired can use imagemagick whenever present and no custom var is
> necessary.

Imagemagick handles a lot of file formats, and sometimes you want
another library to have higher priority. Thats what
imagemagick-enabled-types and imagemagick-types-inhibit is for.

The code above wont work because (image-type-available-p 'imagemagick),
'imagemagick is not an image type, its a feature that provides image
types.




>
>     Vitalie
>

-- 
Joakim Verona



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-14 11:48   ` Vitalie Spinu
  2013-07-14 12:40     ` joakim
@ 2013-07-14 12:42     ` Lars Magne Ingebrigtsen
  2013-07-14 18:21       ` Glenn Morris
  1 sibling, 1 reply; 55+ messages in thread
From: Lars Magne Ingebrigtsen @ 2013-07-14 12:42 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: joakim, emacs-devel

Vitalie Spinu <spinuvit@gmail.com> writes:

> How about this one? Would it ever make sense to use libjpeg or libpng if
> imagemagick support is available? If not, then image-mode and
> image-dired can use imagemagick whenever present and no custom var is
> necessary.

That's what shr does, but I think `create-image' should default to
imagemagick if TYPE is nil and imagemagick is available.  There isn't
much reason to prefer using the other decoders, since most (all?) of the
features provided by the other formats is also provided by imagemagick.

-- 
(domestic pets only, the antidote for overdose, milk.)
  bloggy blog http://lars.ingebrigtsen.no/



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-14 12:40     ` joakim
@ 2013-07-14 13:01       ` Vitalie Spinu
  0 siblings, 0 replies; 55+ messages in thread
From: Vitalie Spinu @ 2013-07-14 13:01 UTC (permalink / raw)
  To: joakim; +Cc: emacs-devel

 >> joakim@verona.se
 >> on Sun, 14 Jul 2013 14:40:37 +0200 wrote:

[...]


 > The code above wont work because (image-type-available-p 'imagemagick),
 > 'imagemagick is not an image type, its a feature that provides image
 > types.

Well, all image handling code accepts 'imagemagic as type argument, so
it works to some extent.

As Lars pointed out, the main issue is that create-image, when called
with nil, figures the file type and defaults to a different decoder than
'imagemagic. And currently there is no way to configure this behavior.

It could be `image-create-force-imagemagic`, or whatever. 

    Vitalie



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-14 12:42     ` Lars Magne Ingebrigtsen
@ 2013-07-14 18:21       ` Glenn Morris
  2013-07-14 19:50         ` Lars Magne Ingebrigtsen
  0 siblings, 1 reply; 55+ messages in thread
From: Glenn Morris @ 2013-07-14 18:21 UTC (permalink / raw)
  To: Lars Magne Ingebrigtsen; +Cc: Vitalie Spinu, joakim, emacs-devel

Lars Magne Ingebrigtsen wrote:

>> How about this one? Would it ever make sense to use libjpeg or libpng if
>> imagemagick support is available? If not, then image-mode and
>> image-dired can use imagemagick whenever present and no custom var is
>> necessary.
>
> That's what shr does, but I think `create-image' should default to
> imagemagick if TYPE is nil and imagemagick is available.  There isn't
> much reason to prefer using the other decoders, since most (all?) of the
> features provided by the other formats is also provided by imagemagick.

I've seen (unanswered) crash reports related to ImageMagick. Eg

http://debbugs.gnu.org/cgi/bugreport.cgi?bug=8341
http://debbugs.gnu.org/cgi/bugreport.cgi?bug=11701
http://debbugs.gnu.org/cgi/bugreport.cgi?bug=11831

And as you know, ImageMagick support for animated/multi-frame images is
broken
http://debbugs.gnu.org/cgi/bugreport.cgi?bug=7978

And likewise for metadata in general
http://debbugs.gnu.org/cgi/pkgreport.cgi?include=subject%3Amagick;package=emacs


And no-one seems interested in working on any of these issues, so IMO we
should stick with the more tested image libraries as default for the
formats that they handle.




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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-14  8:32 ` joakim
  2013-07-14 11:48   ` Vitalie Spinu
@ 2013-07-14 18:33   ` Glenn Morris
  2013-07-14 19:17     ` joakim
  1 sibling, 1 reply; 55+ messages in thread
From: Glenn Morris @ 2013-07-14 18:33 UTC (permalink / raw)
  To: joakim; +Cc: Vitalie Spinu, emacs-devel

joakim@verona.se wrote:

>> Is there a hidden reason why image scaling is not yet implemented?
>>
>>    ;; Not yet implemented.
>>    ;; (defvar image-transform-minor-mode-map
>>    ;;   (let ((map (make-sparse-keymap)))
>>    ;;     ;; (define-key map  [(control ?+)] 'image-scale-in)
>>    ;;     ;; (define-key map  [(control ?-)] 'image-scale-out)
>>    ;;     ;; (define-key map  [(control ?=)] 'image-scale-none)
>>    ;;     ;; (define-key map "c f h" 'image-scale-fit-height)
>>    ;;     ;; (define-key map "c ]" 'image-rotate-right)
>>    ;;     map)
>>    ;;   "Minor mode keymap `image-transform-mode'.")
>>
>
> I worked on scaling support for image mode when I worked on the
> original ImageMagik patch. However, I didnt have time to finish the
> support. The above keymap was probably written by someone else, have a
> look in the log.

No, you wrote it.

http://lists.gnu.org/archive/html/emacs-diffs/2010-08/msg00213.html

It's a shame this stuff was never finished. Do you have time to do it
now?



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-14 18:33   ` Glenn Morris
@ 2013-07-14 19:17     ` joakim
  2013-07-15 10:51       ` Vitalie Spinu
  0 siblings, 1 reply; 55+ messages in thread
From: joakim @ 2013-07-14 19:17 UTC (permalink / raw)
  To: Glenn Morris; +Cc: Vitalie Spinu, emacs-devel

Glenn Morris <rgm@gnu.org> writes:

> joakim@verona.se wrote:
>
>>> Is there a hidden reason why image scaling is not yet implemented?
>>>
>>>    ;; Not yet implemented.
>>>    ;; (defvar image-transform-minor-mode-map
>>>    ;;   (let ((map (make-sparse-keymap)))
>>>    ;;     ;; (define-key map  [(control ?+)] 'image-scale-in)
>>>    ;;     ;; (define-key map  [(control ?-)] 'image-scale-out)
>>>    ;;     ;; (define-key map  [(control ?=)] 'image-scale-none)
>>>    ;;     ;; (define-key map "c f h" 'image-scale-fit-height)
>>>    ;;     ;; (define-key map "c ]" 'image-rotate-right)
>>>    ;;     map)
>>>    ;;   "Minor mode keymap `image-transform-mode'.")
>>>
>>
>> I worked on scaling support for image mode when I worked on the
>> original ImageMagik patch. However, I didnt have time to finish the
>> support. The above keymap was probably written by someone else, have a
>> look in the log.
>
> No, you wrote it.

Interesting.

> http://lists.gnu.org/archive/html/emacs-diffs/2010-08/msg00213.html
>
> It's a shame this stuff was never finished. Do you have time to do it
> now?

Not really, but I can try uncommenting that code and see what
happens. Perhaps I even wrote some notes for myself somewhere...

-- 
Joakim Verona



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-14 18:21       ` Glenn Morris
@ 2013-07-14 19:50         ` Lars Magne Ingebrigtsen
  2013-07-14 20:06           ` Eli Zaretskii
  0 siblings, 1 reply; 55+ messages in thread
From: Lars Magne Ingebrigtsen @ 2013-07-14 19:50 UTC (permalink / raw)
  To: Glenn Morris; +Cc: Vitalie Spinu, joakim, emacs-devel

Glenn Morris <rgm@gnu.org> writes:

> I've seen (unanswered) crash reports related to ImageMagick. Eg
>
> http://debbugs.gnu.org/cgi/bugreport.cgi?bug=8341
> http://debbugs.gnu.org/cgi/bugreport.cgi?bug=11701

Well, those are PDF-related, and PDF is on the list of stuff imagemagick
shouldn't handle.

> http://debbugs.gnu.org/cgi/bugreport.cgi?bug=11831

Man, that's a bad bug report.  Impossible to reproduce.

> And as you know, ImageMagick support for animated/multi-frame images is
> broken
> http://debbugs.gnu.org/cgi/bugreport.cgi?bug=7978

Yup.

> And likewise for metadata in general
> http://debbugs.gnu.org/cgi/pkgreport.cgi?include=subject%3Amagick;package=emacs
>
> And no-one seems interested in working on any of these issues, so IMO we
> should stick with the more tested image libraries as default for the
> formats that they handle.

But since the other formats don't do scaling, they're aren't very
user-friendly.  Nobody wants to look at a tiny corner of a picture.
(Except under special circumstances.)  The default of all the Emacs
image-viewing modes should be to rescale down to the frame or window
size.  And only imagemagick does that.

But, yes, it's problematic that nobody has stepped up to the plate in
chasing down imagemagick bugs lately.

-- 
(domestic pets only, the antidote for overdose, milk.)
  bloggy blog http://lars.ingebrigtsen.no/



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-14 19:50         ` Lars Magne Ingebrigtsen
@ 2013-07-14 20:06           ` Eli Zaretskii
  2013-07-14 20:11             ` Lars Magne Ingebrigtsen
                               ` (2 more replies)
  0 siblings, 3 replies; 55+ messages in thread
From: Eli Zaretskii @ 2013-07-14 20:06 UTC (permalink / raw)
  To: Lars Magne Ingebrigtsen; +Cc: spinuvit, joakim, emacs-devel

> From: Lars Magne Ingebrigtsen <larsi@gnus.org>
> Date: Sun, 14 Jul 2013 21:50:42 +0200
> Cc: Vitalie Spinu <spinuvit@gmail.com>, joakim@verona.se, emacs-devel@gnu.org
> 
> But since the other formats don't do scaling, they're aren't very
> user-friendly.  Nobody wants to look at a tiny corner of a picture.
> (Except under special circumstances.)  The default of all the Emacs
> image-viewing modes should be to rescale down to the frame or window
> size.  And only imagemagick does that.

How about taking out the ImageMagick code that does the scaling and
rolling it into Emacs?  How hard can that be?

Or maybe there's some other library out there that we could use to
roll our own image scaling code.  I don't believe for a moment that
ImageMagick is the only one that is able to pull that.

Point is, if the main reason to want ImageMagick is that we want
scaled images, why not have _just_ scaled images, and leave
ImageMagick to its enthusiasts?



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-14 20:06           ` Eli Zaretskii
@ 2013-07-14 20:11             ` Lars Magne Ingebrigtsen
  2013-07-14 22:00             ` Vitalie Spinu
  2013-07-15  4:15             ` Stephen J. Turnbull
  2 siblings, 0 replies; 55+ messages in thread
From: Lars Magne Ingebrigtsen @ 2013-07-14 20:11 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: spinuvit, joakim, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

> How about taking out the ImageMagick code that does the scaling and
> rolling it into Emacs?  How hard can that be?

That's a good point.  All the image format functions end up with putting
the decoded image data...  somewhere, don't they?

If we had a good image rescaling function in Emacs, then they could all
call that function after decoding the image data.

Perhaps gnulib has an image scaling function?  :-)

-- 
(domestic pets only, the antidote for overdose, milk.)
  bloggy blog http://lars.ingebrigtsen.no/



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-14 20:06           ` Eli Zaretskii
  2013-07-14 20:11             ` Lars Magne Ingebrigtsen
@ 2013-07-14 22:00             ` Vitalie Spinu
  2013-07-15  4:38               ` Eli Zaretskii
  2013-07-15  4:15             ` Stephen J. Turnbull
  2 siblings, 1 reply; 55+ messages in thread
From: Vitalie Spinu @ 2013-07-14 22:00 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Lars Magne Ingebrigtsen, joakim, emacs-devel

 >> Eli Zaretskii <eliz@gnu.org>
 >> on Sun, 14 Jul 2013 23:06:38 +0300 wrote:

[...]


 > Point is, if the main reason to want ImageMagick is that we want
 > scaled images, why not have _just_ scaled images, and leave
 > ImageMagick to its enthusiasts?

ImageMagick is very good with transparency. From what I can see standard
decoders don't handle it at all. Isn't it good to have one tool and
delegate all the work to it?

    Vitalie



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-14 20:06           ` Eli Zaretskii
  2013-07-14 20:11             ` Lars Magne Ingebrigtsen
  2013-07-14 22:00             ` Vitalie Spinu
@ 2013-07-15  4:15             ` Stephen J. Turnbull
  2013-07-15  4:46               ` Eli Zaretskii
  2 siblings, 1 reply; 55+ messages in thread
From: Stephen J. Turnbull @ 2013-07-15  4:15 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Lars Magne Ingebrigtsen, spinuvit, joakim, emacs-devel

Eli Zaretskii writes:

 > How about taking out the ImageMagick code that does the scaling and
 > rolling it into Emacs?  How hard can that be?
 > 
 > Or maybe there's some other library out there that we could use to
 > roll our own image scaling code.  I don't believe for a moment that
 > ImageMagick is the only one that is able to pull that.

Eli, are you proposing to do the work yourself?  If not, ImageMagick
(or GraphicsMagick, which has the goal of being more stable, dunno if
it succeeds) are plausible strategies for getting more features for
less Emacs code, and probably less work.  (There were some other
candidates such as imlib, but I haven't followed graphics libraries
for over ten years.)

XEmacs did try the same strategy with ImageMagick and abandoned it
(too unstable, too many undocumented crashers) -- but that was over
ten years ago.  Surely ImageMagick has improved over the years.  Note
also that the decision to abandon was made by the guy who implemented
in the first place.

If the current Lisp protection from the PDF crashes isn't good enough,
add a filter at the C level so Lisp *can't* pass PDFs to ImageMagick
(or tell the ImageMagick advocates it will be removed or deprecated if
they don't, which IMO is a reasonable condition, although I probably
wouldn't require it myself).

The other issues (handling of advanced features like multi-image GIFs
<spit/>) probably aren't really bugs, but rather simply
unimplemented.  I have to wonder how important those are....



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-14 22:00             ` Vitalie Spinu
@ 2013-07-15  4:38               ` Eli Zaretskii
  0 siblings, 0 replies; 55+ messages in thread
From: Eli Zaretskii @ 2013-07-15  4:38 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: larsi, joakim, emacs-devel

> From: Vitalie Spinu <spinuvit@gmail.com>
> Cc: Lars Magne Ingebrigtsen <larsi@gnus.org>,  joakim@verona.se,  emacs-devel@gnu.org
> Date: Mon, 15 Jul 2013 00:00:16 +0200
> 
>  > Point is, if the main reason to want ImageMagick is that we want
>  > scaled images, why not have _just_ scaled images, and leave
>  > ImageMagick to its enthusiasts?
> 
> ImageMagick is very good with transparency. From what I can see standard
> decoders don't handle it at all. Isn't it good to have one tool and
> delegate all the work to it?

It's good if it works.  Evidently, it doesn't in this case.



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-15  4:15             ` Stephen J. Turnbull
@ 2013-07-15  4:46               ` Eli Zaretskii
  2013-07-15  5:45                 ` Stephen J. Turnbull
  0 siblings, 1 reply; 55+ messages in thread
From: Eli Zaretskii @ 2013-07-15  4:46 UTC (permalink / raw)
  To: Stephen J. Turnbull; +Cc: larsi, spinuvit, joakim, emacs-devel

> From: "Stephen J. Turnbull" <stephen@xemacs.org>
> Cc: Lars Magne Ingebrigtsen <larsi@gnus.org>,
>     spinuvit@gmail.com,
>     joakim@verona.se,
>     emacs-devel@gnu.org
> Date: Mon, 15 Jul 2013 13:15:21 +0900
> 
> Eli Zaretskii writes:
> 
>  > How about taking out the ImageMagick code that does the scaling and
>  > rolling it into Emacs?  How hard can that be?
>  > 
>  > Or maybe there's some other library out there that we could use to
>  > roll our own image scaling code.  I don't believe for a moment that
>  > ImageMagick is the only one that is able to pull that.
> 
> Eli, are you proposing to do the work yourself?

You know very well that if I did, I would not be speaking here, but
instead coding and committing.

> If not, ImageMagick (or GraphicsMagick, which has the goal of being
> more stable, dunno if it succeeds) are plausible strategies for
> getting more features for less Emacs code, and probably less work.

I don't disagree with the principle, but the results are evidently not
very satisfactory.

> XEmacs did try the same strategy with ImageMagick and abandoned it
> (too unstable, too many undocumented crashers) -- but that was over
> ten years ago.  Surely ImageMagick has improved over the years.

Evidently, the improvement is not enough, see the rest of this thread.

> The other issues (handling of advanced features like multi-image GIFs
> <spit/>) probably aren't really bugs, but rather simply
> unimplemented.  I have to wonder how important those are....

You didn't mention scaling, which seems to be the trigger for this
thread.



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-15  4:46               ` Eli Zaretskii
@ 2013-07-15  5:45                 ` Stephen J. Turnbull
  2013-07-15 10:39                   ` Óscar Fuentes
  2013-07-15 15:50                   ` Eli Zaretskii
  0 siblings, 2 replies; 55+ messages in thread
From: Stephen J. Turnbull @ 2013-07-15  5:45 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: larsi, spinuvit, joakim, emacs-devel

Eli Zaretskii writes:

 > > Eli, are you proposing to do the work yourself?
 > 
 > You know very well that if I did, I would not be speaking here, but
 > instead coding and committing.

Really?  Given several people who are interested in this feature
although unable to do significant work on it at the moment?  I didn't
realize you were an advocate of "last commit wins". ;-)

 > I don't disagree with the principle, but the results are evidently not
 > very satisfactory.

Image libraries suck, that's part of life.  How many PNG crashes and
GIF crashes have been fixed upstream?  How many of these libraries
have undocumented restrictions on arguments or image formats that
people have had to guess at over the years?  How many more of those
undocumented restrictions will have to be deduced in order to add
features like scaling, one at a time?  I don't know the details, but I
can tell you that over the last ten years, as far as those affecting
XEmacs go, the answers are "lots", "all of them", and "dunno, but past
experience doesn't allow me to be optimistic".

One advantage to using a higher level API such as ImageMagick's is
that somebody else takes care of that.  Assuming they do it well, of
course.  The PDF crash is one strike against ImageMagick, of course,
but PDF is hard.  So hard that Adobe wontfixes crashers in Acrobat
they themselves confirm (of course, only in cases where Adobe software
happens not to produce the dangerous expressions).  One was so bad it
sometimes blue-screened NT.

 > > XEmacs did try the same strategy with ImageMagick and abandoned it
 > > (too unstable, too many undocumented crashers) -- but that was over
 > > ten years ago.  Surely ImageMagick has improved over the years.
 > 
 > Evidently, the improvement is not enough, see the rest of this
 > thread.

AFAICS, there are serious bugs in PDF handling.  Screw you very much,
Adobe.  What else can we say about that?  If Emacs wants to use a
different library "just for PDF", that sounds reasonable to me.  But
that's an issue with PDF in general, not really one with ImageMagick.
AFAIK, no matter what PDF library you use[1], Adobe's next release is
a loaded gun at your head.

With respect to the other issues that remain, as I wrote before, I
suspect that they are mostly cases where somebody in a hurry to commit
something cool didn't bother with the full ImageMagick API and left
other cool features unimplemented.  That's life in a project with no
formal review process.

 > You didn't mention scaling, which seems to be the trigger for this
 > thread.

Other people mentioned it, so I didn't think I needed to. :-)

Footnotes: 
[1]  Among the more-or-less standalone libraries.  I imagine the ones
used by KDE and GNOME are pretty stable but bring in huge dependencies.




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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-15  5:45                 ` Stephen J. Turnbull
@ 2013-07-15 10:39                   ` Óscar Fuentes
  2013-08-02 15:32                     ` Steinar Bang
  2013-07-15 15:50                   ` Eli Zaretskii
  1 sibling, 1 reply; 55+ messages in thread
From: Óscar Fuentes @ 2013-07-15 10:39 UTC (permalink / raw)
  To: emacs-devel

"Stephen J. Turnbull" <stephen@xemacs.org> writes:

> Footnotes: 
> [1]  Among the more-or-less standalone libraries.  I imagine the ones
> used by KDE and GNOME are pretty stable but bring in huge dependencies.

The official KDE PDF viewer (Okular) uses libpoppler, which comes from
xpdf. In my not extensive experience, it works well. Its dependency set
is small (freetype and image libraries, mostly.)

There is also mupdf [2] which is used by the viewer I use on Windows and
it works well too. Its set of dependencies looks very reasonable [3].

[1] poppler.freedesktop.org/
[2] http://www.mupdf.com/
[3] http://git.ghostscript.com/?p=mupdf.git;a=blob_plain;f=.gitmodules;hb=HEAD





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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-14 19:17     ` joakim
@ 2013-07-15 10:51       ` Vitalie Spinu
  2013-07-16 15:57         ` Glenn Morris
  2013-07-16 21:26         ` Stefan Monnier
  0 siblings, 2 replies; 55+ messages in thread
From: Vitalie Spinu @ 2013-07-15 10:51 UTC (permalink / raw)
  To: joakim; +Cc: emacs-devel



I am wiling to propose a series of patches to image.el and image-mode.el
in order to implement scaling, transform functionality and auto-fit to
image window. From what I see it will be quite an extensive change. So I
ask before doing anything.

First of all there is no image universal api for transforms. The
functions image-transform-XXX in image-mode are very image-mode specific
and all operate by side effects and rely on (many) global variables and
image-toggle-display-image function (the core of image-mode).

So the proposal is to rewrite all those transform functions into a
consistent image transform api and move them into image.el. Then add
interactive transformation commands to image-mode.el, iimage.el,
image-dired.el, gnus etc that will rely on those.

The api could be pushed further by implementing a generic transform map,
and then make all image modes to use it for images at point.

Of course all the above will work only with imagemagick support.

    Vitalie


 >> joakim@verona.se
 >> on Sun, 14 Jul 2013 21:17:21 +0200 wrote:

 > Glenn Morris <rgm@gnu.org> writes:
 >> joakim@verona.se wrote:
 >> 
 >>>> Is there a hidden reason why image scaling is not yet implemented?
 >>>> 
 >>>> ;; Not yet implemented.
 >>>> ;; (defvar image-transform-minor-mode-map
 >>>> ;;   (let ((map (make-sparse-keymap)))
 >>>> ;;     ;; (define-key map  [(control ?+)] 'image-scale-in)
 >>>> ;;     ;; (define-key map  [(control ?-)] 'image-scale-out)
 >>>> ;;     ;; (define-key map  [(control ?=)] 'image-scale-none)
 >>>> ;;     ;; (define-key map "c f h" 'image-scale-fit-height)
 >>>> ;;     ;; (define-key map "c ]" 'image-rotate-right)
 >>>> ;;     map)
 >>>> ;;   "Minor mode keymap `image-transform-mode'.")
 >>>> 
 >>> 
 >>> I worked on scaling support for image mode when I worked on the
 >>> original ImageMagik patch. However, I didnt have time to finish the
 >>> support. The above keymap was probably written by someone else, have a
 >>> look in the log.
 >> 
 >> No, you wrote it.

 > Interesting.

 >> http://lists.gnu.org/archive/html/emacs-diffs/2010-08/msg00213.html>
 >> It's a shame this stuff was never finished. Do you have time to do it
 >> now?

 > Not really, but I can try uncommenting that code and see what
 > happens. Perhaps I even wrote some notes for myself somewhere...



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-15  5:45                 ` Stephen J. Turnbull
  2013-07-15 10:39                   ` Óscar Fuentes
@ 2013-07-15 15:50                   ` Eli Zaretskii
  1 sibling, 0 replies; 55+ messages in thread
From: Eli Zaretskii @ 2013-07-15 15:50 UTC (permalink / raw)
  To: Stephen J. Turnbull; +Cc: larsi, spinuvit, joakim, emacs-devel

> From: "Stephen J. Turnbull" <stephen@xemacs.org>
> Cc: larsi@gnus.org,
>     spinuvit@gmail.com,
>     joakim@verona.se,
>     emacs-devel@gnu.org
> Date: Mon, 15 Jul 2013 14:45:26 +0900
> 
> Eli Zaretskii writes:
> 
>  > > Eli, are you proposing to do the work yourself?
>  > 
>  > You know very well that if I did, I would not be speaking here, but
>  > instead coding and committing.
> 
> Really?  Given several people who are interested in this feature
> although unable to do significant work on it at the moment?  I didn't
> realize you were an advocate of "last commit wins". ;-)

Last commit always wins.

>  > I don't disagree with the principle, but the results are evidently not
>  > very satisfactory.
> 
> Image libraries suck, that's part of life.  How many PNG crashes and
> GIF crashes have been fixed upstream?  How many of these libraries
> have undocumented restrictions on arguments or image formats that
> people have had to guess at over the years?  How many more of those
> undocumented restrictions will have to be deduced in order to add
> features like scaling, one at a time?  I don't know the details, but I
> can tell you that over the last ten years, as far as those affecting
> XEmacs go, the answers are "lots", "all of them", and "dunno, but past
> experience doesn't allow me to be optimistic".

As a matter of fact, my experience with image libraries used by Emacs
is very positive.  I don't think I ever had any crash related to that.

>  > You didn't mention scaling, which seems to be the trigger for this
>  > thread.
> 
> Other people mentioned it, so I didn't think I needed to. :-)

OK, but that's the gist of this thread, IMO.  Scaling is an important
feature needed by eww and whatnot, so we should try to have a stable
implementation, one way or another.



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-15 10:51       ` Vitalie Spinu
@ 2013-07-16 15:57         ` Glenn Morris
  2013-07-16 21:26         ` Stefan Monnier
  1 sibling, 0 replies; 55+ messages in thread
From: Glenn Morris @ 2013-07-16 15:57 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: joakim, emacs-devel

Vitalie Spinu wrote:

> I am wiling to propose a series of patches to image.el and image-mode.el
> in order to implement scaling, transform functionality and auto-fit to
> image window. From what I see it will be quite an extensive change. So I
> ask before doing anything.
>
> First of all there is no image universal api for transforms. The
> functions image-transform-XXX in image-mode are very image-mode specific
> and all operate by side effects and rely on (many) global variables and
> image-toggle-display-image function (the core of image-mode).
>
> So the proposal is to rewrite all those transform functions into a
> consistent image transform api and move them into image.el.

FWIW, that sounds good to me.



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-15 10:51       ` Vitalie Spinu
  2013-07-16 15:57         ` Glenn Morris
@ 2013-07-16 21:26         ` Stefan Monnier
  2013-07-17  7:29           ` Vitalie Spinu
  1 sibling, 1 reply; 55+ messages in thread
From: Stefan Monnier @ 2013-07-16 21:26 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: joakim, emacs-devel

> So the proposal is to rewrite all those transform functions into a
> consistent image transform api and move them into image.el. Then add
> interactive transformation commands to image-mode.el, iimage.el,
> image-dired.el, gnus etc that will rely on those.

That sounds good.

> Of course all the above will work only with imagemagick support.

Actually, I wonder if it can't be made to work for non-imagemagick
images: by operating on image-specs, it should be possible to make the
code do things like "extract the filename, pass the file to `convert'
and create a new image-spec for that temp file", while on imagemagick
images it would just fiddle with the paramters like :height.


        Stefan



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-16 21:26         ` Stefan Monnier
@ 2013-07-17  7:29           ` Vitalie Spinu
  2013-07-17 15:51             ` Vitalie Spinu
  0 siblings, 1 reply; 55+ messages in thread
From: Vitalie Spinu @ 2013-07-17  7:29 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: joakim, emacs-devel

 >> Stefan Monnier <monnier@IRO.UMontreal.CA>
 >> on Tue, 16 Jul 2013 17:26:45 -0400 wrote:

 >> So the proposal is to rewrite all those transform functions into a
 >> consistent image transform api and move them into image.el. Then add
 >> interactive transformation commands to image-mode.el, iimage.el,
 >> image-dired.el, gnus etc that will rely on those.

 > That sounds good.

 >> Of course all the above will work only with imagemagick support.

 > Actually, I wonder if it can't be made to work for non-imagemagick
 > images: by operating on image-specs, it should be possible to make the
 > code do things like "extract the filename, pass the file to `convert'
 > and create a new image-spec for that temp file", while on imagemagick
 > images it would just fiddle with the paramters like :height.

Yes, this is how image-dired-thumbnail-mode works. It comes to
bookkeeping original file metadata which could be done in the image data
structure itself. 

The transform api and manipulation UI is almost finished. I will post it
later today. What I am doing right now is converting the image to
imagemagick type whenever user requests a transformation of any
sort. This works very well with the drawback that the image is loaded
twice once as original type and then as imagemagick. I don't feel any
difference in speed of conversion though.

To avoid this, I have create-image-prefer-type which can take
'imagemagick or nil. In the future it can be extended to other
back-ends, if any. This variable takes effect only when create-image is
called with no explicit TYPE argument. Is this a right approach?

   
Vitalie



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-17  7:29           ` Vitalie Spinu
@ 2013-07-17 15:51             ` Vitalie Spinu
  2013-07-18  8:47               ` Lars Magne Ingebrigtsen
  2013-07-18 23:22               ` image-transform.el and image-mode.el rewrite Vitalie Spinu
  0 siblings, 2 replies; 55+ messages in thread
From: Vitalie Spinu @ 2013-07-17 15:51 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: joakim, emacs-devel

 >> Vitalie Spinu <spinuvit@gmail.com>
 >> on Wed, 17 Jul 2013 09:29:12 +0200 wrote:

[...]


 > To avoid this, I have create-image-prefer-type which can take
 > 'imagemagick or nil. In the future it can be extended to other
 > back-ends, if any. This variable takes effect only when create-image is
 > called with no explicit TYPE argument. Is this a right approach?

I got a better idea after seeing convert specs:
http://www.imagemagick.org/script/convert.php

Just try which backend fits the requested conversion in turn:

   (defcustom image-transform-backends '(imagemagick convert)
     "Backends to try out in turn for image transformation.
   
   For `imagemagick', `image-transform' will try to use internal
   Emacs ImageMagick support. For `convert' use external ImageMagick
   \"convert\" utility to produce a transformed temporary image
   file.
   
   If Emacs was not compiled with ImageMagick support `imagemagic'
   backend is ignored."
     :group 'image
     :type '(repeat symbol))





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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-17 15:51             ` Vitalie Spinu
@ 2013-07-18  8:47               ` Lars Magne Ingebrigtsen
  2013-07-18 22:27                 ` Vitalie Spinu
  2013-07-22 20:17                 ` Vitalie Spinu
  2013-07-18 23:22               ` image-transform.el and image-mode.el rewrite Vitalie Spinu
  1 sibling, 2 replies; 55+ messages in thread
From: Lars Magne Ingebrigtsen @ 2013-07-18  8:47 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: Stefan Monnier, joakim, emacs-devel

Vitalie Spinu <spinuvit@gmail.com> writes:

>    For `imagemagick', `image-transform' will try to use internal
>    Emacs ImageMagick support. For `convert' use external ImageMagick
>    \"convert\" utility to produce a transformed temporary image
>    file.

If you want to avoid temporary file management, you can "convert" with
output to a buffer, and then just call `create-image' on the buffer
contents.

It'll be slower, but I haven't measured how much slower. 

-- 
(domestic pets only, the antidote for overdose, milk.)
  bloggy blog http://lars.ingebrigtsen.no/



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-18  8:47               ` Lars Magne Ingebrigtsen
@ 2013-07-18 22:27                 ` Vitalie Spinu
  2013-07-19  9:22                   ` Stefan Monnier
  2013-07-22 20:17                 ` Vitalie Spinu
  1 sibling, 1 reply; 55+ messages in thread
From: Vitalie Spinu @ 2013-07-18 22:27 UTC (permalink / raw)
  To: Lars Magne Ingebrigtsen; +Cc: Stefan Monnier, joakim, emacs-devel

 >> Lars Magne Ingebrigtsen <larsi@gnus.org>
 >> on Thu, 18 Jul 2013 10:47:15 +0200 wrote:

 > Vitalie Spinu <spinuvit@gmail.com> writes:
 >> For `imagemagick', `image-transform' will try to use internal
 >> Emacs ImageMagick support. For `convert' use external ImageMagick
 >> \"convert\" utility to produce a transformed temporary image
 >> file.

 > If you want to avoid temporary file management, you can "convert" with
 > output to a buffer, and then just call `create-image' on the buffer
 > contents.

 > It'll be slower, but I haven't measured how much slower. 

A big complication with temp files is that you have to track and clean
unused once, and I don't see a clean way of achieving this as yet.

On the other hand, the user might requests several transforms in a
sequence, so you will have to store to the file to pass it further to
'convert' anyhow. It might also better work on remotes as the file is
stored on remote machine.

For batch transforms, like thumbnail creation, it would be much faster
to get it done all at once bypassing emacs altogether. So I would stick
with temp files for time being.

    Vitalie



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

* image-transform.el and image-mode.el rewrite
  2013-07-17 15:51             ` Vitalie Spinu
  2013-07-18  8:47               ` Lars Magne Ingebrigtsen
@ 2013-07-18 23:22               ` Vitalie Spinu
  2013-07-19 11:52                 ` Wolfgang Jenkner
  2013-07-22 20:37                 ` Glenn Morris
  1 sibling, 2 replies; 55+ messages in thread
From: Vitalie Spinu @ 2013-07-18 23:22 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: joakim, emacs-devel

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


I attach a working version of the rewrite. 

New image-transform.el with transform api and UI. I rewrote some parts
of image-mode, most interestingly by adding image-mode-auto-resize,
which see. More work should be done - namespace cleanup; n/p/g should
not reset the mode as it messes up user local setting and makes deriving
modes dificult; support for multiple images per page etc.

New keys in image-mode:

   +               image-scale-adjust
   -               image-scale-adjust
   0               image-scale-adjust
   =               image-scale-adjust
   B               image-change-background
   [               image-rotate-left
   ]               image-rotate-right
   o               image-rotate
   r               Prefix Command
   
   r f             image-fit-to-window
   r h             image-fit-to-window-height
   r s             image-stretch-to-window
   r w             image-fit-to-window-width
   
   T               image-mode-show-thumbnails

r stands for resize. A better fit wold be f but that one is already
bound to image-next-frame for multi-frame images.

Currently only internal imagemagick backend is implemented for things
that are exposed at elisp level (:width :height :background
:rotation). Convert backend will come latter. To illustrate the API try:

   (setq tt (create-image "/path/to/foo.png"))
   
   (image-transform tt :scale 200) ;in %,  imagemagick convention
   (image-transform tt :scale 25)

   (insert-image (image-transform (copy-list tt) :resize '(500 . 500)))
   (insert-image (image-transform (copy-list tt) :resize 200))
   
   (insert-image (image-transform (copy-list tt) :resize 'fit-width))
   (insert-image (image-transform (copy-list tt) :resize 'fit-height))
   (insert-image (image-transform (copy-list tt) :resize 'fit))
   (insert-image (image-transform (copy-list tt) :resize 'fit-stretch))
   (insert-image (image-transform (copy-list tt) :resize 'fit-if-large))
   (insert-image (image-transform (copy-list tt) :resize 'fit :rotate 45))
   (insert-image (image-transform (copy-list tt) :resize 'fit-height :rotate 60))

   (insert-image (image-transform (copy-list tt) :background "pink"))


I have changed insert-image to take an additional argument MAP to hook a
transform keymap as local text-properties keymap for the image. With the
following you should get all the transform keys listed above to work on
the inserted image:
   
   (insert-image (image-transform (copy-list tt) :resize 'fit)
                 nil nil nil image-transform-map)

Would be nice if insert-image would hook a transform map by
default. Then all modes that use insert-image can automatically provide
transformations. But I couldn't think of a handy prefix for this map.
   
I will be out for a week and will resume when I am back. In meanwhile
suggestions are welcome.

    Vitalie


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: image.diff --]
[-- Type: text/x-diff, Size: 92008 bytes --]

diff --git a/lisp/image-mode.el b/lisp/image-mode.el
index 30dfd04..deeac68 100644
--- a/lisp/image-mode.el
+++ b/lisp/image-mode.el
@@ -39,7 +39,47 @@
 ;;; Code:
 
 (require 'image)
-(eval-when-compile (require 'cl-lib))
+(require 'image-transform)
+;; (eval-when-compile (require 'cl-lib))
+
+(defgroup image-mode ()
+  "Support for visiting image files."
+  :group 'multimedia)
+
+(defcustom image-mode-auto-resize 'fit-if-large
+  "The image resize default.
+
+Can be:
+ - a number, giving a proportional scaling of the image.
+ - a cons, giving the actual size (w x h) in pixels.
+ - a symbol:
+   *`fit' - maximally scale IMAGE to fit into window
+   *`fit-if-large' - like `fit', but only when image is larger than window
+   *`fit-height' - fit the image to window height
+   *`fit-width' - fit the image to window width
+   *`fit-stretch' - stretch the image to fit to both height and
+    width of the window"
+  :type '(choice
+          (const :tag "no resize" nil)
+          (number :tag "scale")
+          (cons :tag "size (w . h)" number number)
+          (const :tag "fit" fit)
+          (const :tag "fit if large" fit-if-large)
+          (const :tag "fit height" fit-height)
+          (const :tag "fit width" fit-width)
+          (const :tag "fit stretch" fit-stretch))
+  :group 'image-mode
+  :version "24.4")
+
+;; This one is not customizable
+(defvar image-mode-auto-rotate nil
+  "Default rotation angle for the image.
+Nil means no rotation.")
+
+(defcustom image-mode-show-cursor t
+  "Non-nil if the cursor should be shown in image-mode"
+  :group 'image-mode
+  :type 'boolean)
 
 ;;; Image mode window-info management.
 
@@ -58,15 +98,15 @@ otherwise it defaults to t, used for times when the buffer is not displayed."
          (setq window
                (if (eq (current-buffer) (window-buffer)) (selected-window) t)))
         ((eq window t))
-	((not (windowp window))
-	 (error "Not a window: %s" window)))
+        ((not (windowp window))
+         (error "Not a window: %s" window)))
   (when cleanup
     (setq image-mode-winprops-alist
-  	  (delq nil (mapcar (lambda (winprop)
-			      (let ((w (car-safe winprop)))
-				(if (or (not (windowp w)) (window-live-p w))
-				    winprop)))
-  			    image-mode-winprops-alist))))
+          (delq nil (mapcar (lambda (winprop)
+                              (let ((w (car-safe winprop)))
+                                (if (or (not (windowp w)) (window-live-p w))
+                                    winprop)))
+                            image-mode-winprops-alist))))
   (let ((winprops (assq window image-mode-winprops-alist)))
     ;; For new windows, set defaults from the latest.
     (if winprops
@@ -112,23 +152,18 @@ otherwise it defaults to t, used for times when the buffer is not displayed."
            (hscroll (image-mode-window-get 'hscroll winprops))
            (vscroll (image-mode-window-get 'vscroll winprops)))
       (when (image-get-display-property) ;Only do it if we display an image!
-	(if hscroll (set-window-hscroll (selected-window) hscroll))
-	(if vscroll (set-window-vscroll (selected-window) vscroll))))))
+        (if hscroll (set-window-hscroll (selected-window) hscroll))
+        (if vscroll (set-window-vscroll (selected-window) vscroll))))))
 
 (defun image-mode-setup-winprops ()
   ;; Record current scroll settings.
   (unless (listp image-mode-winprops-alist)
     (setq image-mode-winprops-alist nil))
   (add-hook 'window-configuration-change-hook
- 	    'image-mode-reapply-winprops nil t))
+            'image-mode-reapply-winprops nil t))
 
 ;;; Image scrolling functions
 
-(defun image-get-display-property ()
-  (get-char-property (point-min) 'display
-                     ;; There might be different images for different displays.
-                     (if (eq (window-buffer) (current-buffer))
-                         (selected-window))))
 
 (declare-function image-size "image.c" (spec &optional pixels frame))
 
@@ -146,31 +181,31 @@ but not `slice', return the `image-size' of the specified image."
   (if (eq (car spec) 'image)
       (image-size spec pixels frame)
     (let ((image (assoc 'image spec))
-	  (slice (assoc 'slice spec)))
+          (slice (assoc 'slice spec)))
       (cond ((and image slice)
-	     (if pixels
-		 (cons (nth 3 slice) (nth 4 slice))
-	       (cons (/ (float (nth 3 slice)) (frame-char-width frame))
-		     (/ (float (nth 4 slice)) (frame-char-height frame)))))
-	    (image
-	     (image-size image pixels frame))
-	    (t
-	     (error "Invalid image specification: %s" spec))))))
+             (if pixels
+                 (cons (nth 3 slice) (nth 4 slice))
+               (cons (/ (float (nth 3 slice)) (frame-char-width frame))
+                     (/ (float (nth 4 slice)) (frame-char-height frame)))))
+            (image
+             (image-size image pixels frame))
+            (t
+             (error "Invalid image specification: %s" spec))))))
 
 (defun image-forward-hscroll (&optional n)
   "Scroll image in current window to the left by N character widths.
 Stop if the right edge of the image is reached."
   (interactive "p")
   (cond ((= n 0) nil)
-	((< n 0)
-	 (image-set-window-hscroll (max 0 (+ (window-hscroll) n))))
-	(t
-	 (let* ((image (image-get-display-property))
-		(edges (window-inside-edges))
-		(win-width (- (nth 2 edges) (nth 0 edges)))
-		(img-width (ceiling (car (image-display-size image)))))
-	   (image-set-window-hscroll (min (max 0 (- img-width win-width))
-					  (+ n (window-hscroll))))))))
+        ((< n 0)
+         (image-set-window-hscroll (max 0 (+ (window-hscroll) n))))
+        (t
+         (let* ((image (image-get-display-property))
+                (edges (window-inside-edges))
+                (win-width (- (nth 2 edges) (nth 0 edges)))
+                (img-width (ceiling (car (image-display-size image)))))
+           (image-set-window-hscroll (min (max 0 (- img-width win-width))
+                                          (+ n (window-hscroll))))))))
 
 (defun image-backward-hscroll (&optional n)
   "Scroll image in current window to the right by N character widths.
@@ -183,15 +218,15 @@ Stop if the left edge of the image is reached."
 Stop if the bottom edge of the image is reached."
   (interactive "p")
   (cond ((= n 0) nil)
-	((< n 0)
-	 (image-set-window-vscroll (max 0 (+ (window-vscroll) n))))
-	(t
-	 (let* ((image (image-get-display-property))
-		(edges (window-inside-edges))
-		(win-height (- (nth 3 edges) (nth 1 edges)))
-		(img-height (ceiling (cdr (image-display-size image)))))
-	   (image-set-window-vscroll (min (max 0 (- img-height win-height))
-					  (+ n (window-vscroll))))))))
+        ((< n 0)
+         (image-set-window-vscroll (max 0 (+ (window-vscroll) n))))
+        (t
+         (let* ((image (image-get-display-property))
+                (edges (window-inside-edges))
+                (win-height (- (nth 3 edges) (nth 1 edges)))
+                (img-height (ceiling (cdr (image-display-size image)))))
+           (image-set-window-vscroll (min (max 0 (- img-height win-height))
+                                          (+ n (window-vscroll))))))))
 
 (defun image-previous-line (&optional n)
   "Scroll image in current window downward by N lines.
@@ -209,16 +244,16 @@ If ARG is the atom `-', scroll downward by nearly full screen.
 When calling from a program, supply as argument a number, nil, or `-'."
   (interactive "P")
   (cond ((null n)
-	 (let* ((edges (window-inside-edges))
-		(win-height (- (nth 3 edges) (nth 1 edges))))
-	   (image-next-line
-	    (max 0 (- win-height next-screen-context-lines)))))
-	((eq n '-)
-	 (let* ((edges (window-inside-edges))
-		(win-height (- (nth 3 edges) (nth 1 edges))))
-	   (image-next-line
-	    (min 0 (- next-screen-context-lines win-height)))))
-	(t (image-next-line (prefix-numeric-value n)))))
+         (let* ((edges (window-inside-edges))
+                (win-height (- (nth 3 edges) (nth 1 edges))))
+           (image-next-line
+            (max 0 (- win-height next-screen-context-lines)))))
+        ((eq n '-)
+         (let* ((edges (window-inside-edges))
+                (win-height (- (nth 3 edges) (nth 1 edges))))
+           (image-next-line
+            (min 0 (- next-screen-context-lines win-height)))))
+        (t (image-next-line (prefix-numeric-value n)))))
 
 (defun image-scroll-down (&optional n)
   "Scroll image in current window downward by N lines.
@@ -230,16 +265,16 @@ If ARG is the atom `-', scroll upward by nearly full screen.
 When calling from a program, supply as argument a number, nil, or `-'."
   (interactive "P")
   (cond ((null n)
-	 (let* ((edges (window-inside-edges))
-		(win-height (- (nth 3 edges) (nth 1 edges))))
-	   (image-next-line
-	    (min 0 (- next-screen-context-lines win-height)))))
-	((eq n '-)
-	 (let* ((edges (window-inside-edges))
-		(win-height (- (nth 3 edges) (nth 1 edges))))
-	   (image-next-line
-	    (max 0 (- win-height next-screen-context-lines)))))
-	(t (image-next-line (- (prefix-numeric-value n))))))
+         (let* ((edges (window-inside-edges))
+                (win-height (- (nth 3 edges) (nth 1 edges))))
+           (image-next-line
+            (min 0 (- next-screen-context-lines win-height)))))
+        ((eq n '-)
+         (let* ((edges (window-inside-edges))
+                (win-height (- (nth 3 edges) (nth 1 edges))))
+           (image-next-line
+            (max 0 (- win-height next-screen-context-lines)))))
+        (t (image-next-line (- (prefix-numeric-value n))))))
 
 (defun image-bol (arg)
   "Scroll horizontally to the left edge of the image in the current window.
@@ -260,9 +295,9 @@ stopping if the top or bottom edge of the image is reached."
        (/= (setq arg (prefix-numeric-value arg)) 1)
        (image-next-line (- arg 1)))
   (let* ((image (image-get-display-property))
-	 (edges (window-inside-edges))
-	 (win-width (- (nth 2 edges) (nth 0 edges)))
-	 (img-width (ceiling (car (image-display-size image)))))
+         (edges (window-inside-edges))
+         (win-width (- (nth 2 edges) (nth 0 edges)))
+         (img-width (ceiling (car (image-display-size image)))))
     (image-set-window-hscroll (max 0 (- img-width win-width)))))
 
 (defun image-bob ()
@@ -275,11 +310,11 @@ stopping if the top or bottom edge of the image is reached."
   "Scroll to the bottom-right corner of the image in the current window."
   (interactive)
   (let* ((image (image-get-display-property))
-	 (edges (window-inside-edges))
-	 (win-width (- (nth 2 edges) (nth 0 edges)))
-	 (img-width (ceiling (car (image-display-size image))))
-	 (win-height (- (nth 3 edges) (nth 1 edges)))
-	 (img-height (ceiling (cdr (image-display-size image)))))
+         (edges (window-inside-edges))
+         (win-width (- (nth 2 edges) (nth 0 edges)))
+         (img-width (ceiling (car (image-display-size image))))
+         (win-height (- (nth 3 edges) (nth 1 edges)))
+         (img-height (ceiling (cdr (image-display-size image)))))
     (image-set-window-hscroll (max 0 (- img-width win-width)))
     (image-set-window-vscroll (max 0 (- img-height win-height)))))
 
@@ -298,37 +333,37 @@ call."
   (let* ((buffer (current-buffer))
          (display (image-get-display-property))
          (size (image-display-size display))
-	 (saved (frame-parameter frame 'image-mode-saved-params))
-	 (window-configuration (current-window-configuration frame))
-	 (width  (frame-width  frame))
-	 (height (frame-height frame)))
+         (saved (frame-parameter frame 'image-mode-saved-params))
+         (window-configuration (current-window-configuration frame))
+         (width  (frame-width  frame))
+         (height (frame-height frame)))
     (with-selected-frame (or frame (selected-frame))
       (if (and toggle saved
-	       (= (caar saved) width)
-	       (= (cdar saved) height))
-	  (progn
-	    (set-frame-width  frame (car (nth 1 saved)))
-	    (set-frame-height frame (cdr (nth 1 saved)))
-	    (set-window-configuration (nth 2 saved))
-	    (set-frame-parameter frame 'image-mode-saved-params nil))
-	(delete-other-windows)
-	(switch-to-buffer buffer t t)
-	(let* ((edges (window-inside-edges))
-	       (inner-width  (- (nth 2 edges) (nth 0 edges)))
-	       (inner-height (- (nth 3 edges) (nth 1 edges))))
-	  (set-frame-width  frame (+ (ceiling (car size))
-				     width (- inner-width)))
-	  (set-frame-height frame (+ (ceiling (cdr size))
-				     height (- inner-height)))
-	  ;; The frame size after the above `set-frame-*' calls may
-	  ;; differ from what we specified, due to window manager
-	  ;; interference.  We have to call `frame-width' and
-	  ;; `frame-height' to get the actual results.
-	  (set-frame-parameter frame 'image-mode-saved-params
-			       (list (cons (frame-width)
-					   (frame-height))
-				     (cons width height)
-				     window-configuration)))))))
+               (= (caar saved) width)
+               (= (cdar saved) height))
+          (progn
+            (set-frame-width  frame (car (nth 1 saved)))
+            (set-frame-height frame (cdr (nth 1 saved)))
+            (set-window-configuration (nth 2 saved))
+            (set-frame-parameter frame 'image-mode-saved-params nil))
+        (delete-other-windows)
+        (switch-to-buffer buffer t t)
+        (let* ((edges (window-inside-edges))
+               (inner-width  (- (nth 2 edges) (nth 0 edges)))
+               (inner-height (- (nth 3 edges) (nth 1 edges))))
+          (set-frame-width  frame (+ (ceiling (car size))
+                                     width (- inner-width)))
+          (set-frame-height frame (+ (ceiling (cdr size))
+                                     height (- inner-height)))
+          ;; The frame size after the above `set-frame-*' calls may
+          ;; differ from what we specified, due to window manager
+          ;; interference.  We have to call `frame-width' and
+          ;; `frame-height' to get the actual results.
+          (set-frame-parameter frame 'image-mode-saved-params
+                               (list (cons (frame-width)
+                                           (frame-height))
+                                     (cons width height)
+                                     window-configuration)))))))
 
 ;;; Image Mode setup
 
@@ -349,6 +384,7 @@ call."
     (define-key map (kbd "S-SPC")     'image-scroll-down)
     (define-key map (kbd "DEL")       'image-scroll-down)
     (define-key map (kbd "RET")       'image-toggle-animation)
+    (define-key map "T" 'image-mode-show-thumbnails)
     (define-key map "F" 'image-goto-frame)
     (define-key map "f" 'image-next-frame)
     (define-key map "b" 'image-previous-frame)
@@ -370,59 +406,68 @@ call."
     (define-key map [remap end-of-buffer] 'image-eob)
     (easy-menu-define image-mode-menu map "Menu for Image mode."
       '("Image"
-	["Show as Text" image-toggle-display :active t
-	 :help "Show image as text"]
-	"--"
-	["Fit Frame to Image" image-mode-fit-frame :active t
-	 :help "Resize frame to match image"]
-	["Fit to Window Height" image-transform-fit-to-height
-	 :visible (eq image-type 'imagemagick)
-	 :help "Resize image to match the window height"]
-	["Fit to Window Width" image-transform-fit-to-width
-	 :visible (eq image-type 'imagemagick)
-	 :help "Resize image to match the window width"]
-	["Rotate Image..." image-transform-set-rotation
-	 :visible (eq image-type 'imagemagick)
-	 :help "Rotate the image"]
-	"--"
-	["Show Thumbnails"
-	 (lambda ()
-	   (interactive)
-	   (image-dired default-directory))
-	 :active default-directory
-	 :help "Show thumbnails for all images in this directory"]
-	["Next Image" image-next-file :active buffer-file-name
+        ["Show as Text" image-toggle-display
+         :active t
+         :help "Show image as text"]
+        "--"
+        ["Fit Frame to Image" image-mode-fit-frame
+         :active t
+         :help "Resize frame to match image"]
+        ["Fit into Window" image-fit-to-window
+         :visible (eq image-type 'imagemagick)
+         :help "Maximally resize image to fit into window"]
+        ["Fit to Window Height" image-fit-to-window-height
+         :visible (eq image-type 'imagemagick)
+         :help "Resize image to match the window height"]
+        ["Fit to Window Width" image-fit-to-window-width
+         :visible (eq image-type 'imagemagick)
+         :help "Resize image to match the window width"]
+        ["Rotate Image..." image-rotate
+         :visible (eq image-type 'imagemagick)]
+        ["Rotate Image Right" image-rotate-right
+         :visible (eq image-type 'imagemagick)]
+        ["Rotate Image Left" image-rotate-left
+         :visible (eq image-type 'imagemagick)]
+        ["Change Image Background..." image-change-background
+         :visible (eq image-type 'imagemagick)]
+        "--"
+        ["Show Thumbnails" image-mode-show-thumbnails
+         :active default-directory
+         :help "Show thumbnails for all images in this directory"]
+        ["Next Image" image-next-file :active buffer-file-name
          :help "Move to next image in this directory"]
-	["Previous Image" image-previous-file :active buffer-file-name
+        ["Previous Image" image-previous-file :active buffer-file-name
          :help "Move to previous image in this directory"]
-	"--"
-	["Animate Image" image-toggle-animation :style toggle
-	 :selected (let ((image (image-get-display-property)))
-		     (and image (image-animate-timer image)))
-	 :active image-multi-frame
+        "--"
+        ["Animate Image" image-toggle-animation :style toggle
+         :selected (let ((image (image-get-display-property)))
+                     (and image (image-animate-timer image)))
+         :active image-multi-frame
          :help "Toggle image animation"]
-	["Loop Animation"
-	 (lambda () (interactive)
-	   (setq image-animate-loop (not image-animate-loop))
-	   ;; FIXME this is a hacky way to make it affect a currently
-	   ;; animating image.
-	   (when (let ((image (image-get-display-property)))
-		   (and image (image-animate-timer image)))
-	     (image-toggle-animation)
-	     (image-toggle-animation)))
-	 :style toggle :selected image-animate-loop
-	 :active image-multi-frame
+        ["Loop Animation"
+         (lambda () (interactive)
+           (setq image-animate-loop (not image-animate-loop))
+           ;; FIXME this is a hacky way to make it affect a currently
+           ;; animating image.
+           (when (let ((image (image-get-display-property)))
+                   (and image (image-animate-timer image)))
+             (image-toggle-animation)
+             (image-toggle-animation)))
+         :style toggle :selected image-animate-loop
+         :active image-multi-frame
          :help "Animate images once, or forever?"]
-	["Next Frame" image-next-frame :active image-multi-frame
-	 :help "Show the next frame of this image"]
-	["Previous Frame" image-previous-frame :active image-multi-frame
-	 :help "Show the previous frame of this image"]
-	["Goto Frame..." image-goto-frame :active image-multi-frame
-	 :help "Show a specific frame of this image"]
-	))
+        ["Next Frame" image-next-frame :active image-multi-frame
+         :help "Show the next frame of this image"]
+        ["Previous Frame" image-previous-frame :active image-multi-frame
+         :help "Show the previous frame of this image"]
+        ["Goto Frame..." image-goto-frame :active image-multi-frame
+         :help "Show a specific frame of this image"]
+        ))
     map)
   "Mode keymap for `image-mode'.")
 
+(image--add-transform-keys image-mode-map)
+
 (defvar image-minor-mode-map
   (let ((map (make-sparse-keymap)))
     (define-key map "\C-c\C-c" 'image-toggle-display)
@@ -437,72 +482,79 @@ call."
 (defun image-mode ()
   "Major mode for image files.
 You can use \\<image-mode-map>\\[image-toggle-display]
-to toggle between display as an image and display as text."
+to toggle between display as an image and display as text.
+
+\\{image-mode-map\}"
   (interactive)
   (condition-case err
       (progn
-	(unless (display-images-p)
-	  (error "Display does not support images"))
-
-	(kill-all-local-variables)
-	(setq major-mode 'image-mode)
-
-	(if (not (image-get-display-property))
-	    (progn
-	      (image-toggle-display-image)
-	      ;; If attempt to display the image fails.
-	      (if (not (image-get-display-property))
-		  (error "Invalid image")))
-	  ;; Set next vars when image is already displayed but local
-	  ;; variables were cleared by kill-all-local-variables
-	  (setq cursor-type nil truncate-lines t
-		image-type (plist-get (cdr (image-get-display-property)) :type)))
-
-	(setq mode-name (if image-type (format "Image[%s]" image-type) "Image"))
-	(use-local-map image-mode-map)
-
-	;; Use our own bookmarking function for images.
-	(setq-local bookmark-make-record-function
+        (unless (display-images-p)
+          (error "Display does not support images"))
+
+        (kill-all-local-variables)
+        (setq major-mode 'image-mode)
+
+        (if (not (image-get-display-property))
+            (progn
+              (image-toggle-display-image)
+              ;; If attempt to display the image fails.
+              (if (not (image-get-display-property))
+                  (error "Invalid image")))
+          ;; Set next vars when image is already displayed but local
+          ;; variables were cleared by kill-all-local-variables
+          (setq cursor-type nil truncate-lines t
+                image-type (plist-get (cdr (image-get-display-property)) :type)))
+
+        (setq mode-name (if image-type (format "Image[%s]" image-type) "Image"))
+        (use-local-map image-mode-map)
+
+        ;; Use our own bookmarking function for images.
+        (setq-local bookmark-make-record-function
                     #'image-bookmark-make-record)
 
-	;; Keep track of [vh]scroll when switching buffers
-	(image-mode-setup-winprops)
-
-	(add-hook 'change-major-mode-hook 'image-toggle-display-text nil t)
-	(add-hook 'after-revert-hook 'image-after-revert-hook nil t)
-	(run-mode-hooks 'image-mode-hook)
-	(let ((image (image-get-display-property))
-	      (msg1 (substitute-command-keys
-		     "Type \\[image-toggle-display] to view the image as "))
-	      animated)
-	  (cond
-	   ((null image)
-	    (message "%s" (concat msg1 "an image.")))
-	   ((setq animated (image-multi-frame-p image))
-	    (setq image-multi-frame t
-		  mode-line-process
-		  `(:eval
-		    (concat " "
-			    (propertize
-			     (format "[%s/%s]"
-				     (1+ (image-current-frame ',image))
-				     ,(car animated))
-			     'help-echo "Frames
+        ;; Keep track of [vh]scroll when switching buffers
+        (image-mode-setup-winprops)
+
+        ;; fixme: should be rewritten whiteout actually re-installing
+        ;; the mode, user vars are lost + deriving modes is difficult
+        (set (make-local-variable 'revert-buffer-function)
+             'image-mode-revert-buffer-function)
+
+        (add-hook 'change-major-mode-hook 'image-toggle-display-text nil t)
+        (add-hook 'after-revert-hook 'image-after-revert-hook nil t)
+        (run-mode-hooks 'image-mode-hook)
+        (let ((image (image-get-display-property))
+              (msg1 (substitute-command-keys
+                     "Type \\[image-toggle-display] to view the image as "))
+              animated)
+          (cond
+           ((null image)
+            (message "%s" (concat msg1 "an image.")))
+           ((setq animated (image-multi-frame-p image))
+            (setq image-multi-frame t
+                  mode-line-process
+                  `(:eval
+                    (concat " "
+                            (propertize
+                             (format "[%s/%s]"
+                                     (1+ (image-current-frame ',image))
+                                     ,(car animated))
+                             'help-echo "Frames
 mouse-1: Next frame
 mouse-3: Previous frame"
-			     'mouse-face 'mode-line-highlight
-			     'local-map
-			     '(keymap
-			       (mode-line
-				keymap
-				(down-mouse-1 . image-next-frame)
-				(down-mouse-3 . image-previous-frame)))))))
-	    (message "%s"
-		     (concat msg1 "text.  This image has multiple frames.")))
-;;;			     (substitute-command-keys
-;;;			      "\\[image-toggle-animation] to animate."))))
-	   (t
-	    (message "%s" (concat msg1 "text."))))))
+                             'mouse-face 'mode-line-highlight
+                             'local-map
+                             '(keymap
+                               (mode-line
+                                keymap
+                                (down-mouse-1 . image-next-frame)
+                                (down-mouse-3 . image-previous-frame)))))))
+            (message "%s"
+                     (concat msg1 "text.  This image has multiple frames.")))
+;;;                          (substitute-command-keys
+;;;                           "\\[image-toggle-animation] to animate."))))
+           (t
+            (message "%s" (concat msg1 "text."))))))
 
     (error
      (image-mode-as-text)
@@ -510,6 +562,11 @@ mouse-3: Previous frame"
       (if (called-interactively-p 'any) 'error 'message)
       "Cannot display image: %s" (cdr err)))))
 
+(defun image-mode-revert-buffer-function (ignore noconfirm)
+  ;; don't ask on reversion
+  (let ((revert-buffer-function nil))
+    (revert-buffer ignore t)))
+
 ;;;###autoload
 (define-minor-mode image-minor-mode
   "Toggle Image minor mode in this buffer.
@@ -544,25 +601,25 @@ on these modes."
   ;; image-mode-as-text = normal-mode + image-minor-mode
   (let ((previous-image-type image-type)) ; preserve `image-type'
     (if image-mode-previous-major-mode
-	;; Restore previous major mode that was already found by this
-	;; function and cached in `image-mode-previous-major-mode'
-	(funcall image-mode-previous-major-mode)
+        ;; Restore previous major mode that was already found by this
+        ;; function and cached in `image-mode-previous-major-mode'
+        (funcall image-mode-previous-major-mode)
       (let ((auto-mode-alist
-	     (delq nil (mapcar
-			(lambda (elt)
-			  (unless (memq (or (car-safe (cdr elt)) (cdr elt))
-					'(image-mode image-mode-maybe image-mode-as-text))
-			    elt))
-			auto-mode-alist)))
-	    (magic-fallback-mode-alist
-	     (delq nil (mapcar
-			(lambda (elt)
-			  (unless (memq (or (car-safe (cdr elt)) (cdr elt))
-					'(image-mode image-mode-maybe image-mode-as-text))
-			    elt))
-			magic-fallback-mode-alist))))
-	(normal-mode)
-	(setq-local image-mode-previous-major-mode major-mode)))
+             (delq nil (mapcar
+                        (lambda (elt)
+                          (unless (memq (or (car-safe (cdr elt)) (cdr elt))
+                                        '(image-mode image-mode-maybe image-mode-as-text))
+                            elt))
+                        auto-mode-alist)))
+            (magic-fallback-mode-alist
+             (delq nil (mapcar
+                        (lambda (elt)
+                          (unless (memq (or (car-safe (cdr elt)) (cdr elt))
+                                        '(image-mode image-mode-maybe image-mode-as-text))
+                            elt))
+                        magic-fallback-mode-alist))))
+        (normal-mode)
+        (setq-local image-mode-previous-major-mode major-mode)))
     ;; Restore `image-type' after `kill-all-local-variables' in `normal-mode'.
     (setq image-type previous-image-type)
     ;; Enable image minor mode with `C-c C-c'.
@@ -570,10 +627,10 @@ on these modes."
     ;; Show the image file as text.
     (image-toggle-display-text)
     (message "%s" (concat
-		   (substitute-command-keys
-		    "Type \\[image-toggle-display] to view the image as ")
-		   (if (image-get-display-property)
-		       "text" "an image") "."))))
+                   (substitute-command-keys
+                    "Type \\[image-toggle-display] to view the image as ")
+                   (if (image-get-display-property)
+                       "text" "an image") "."))))
 
 (define-obsolete-function-alias 'image-mode-maybe 'image-mode "23.2")
 
@@ -581,14 +638,20 @@ on these modes."
   "Show the image file as text.
 Remove text properties that display the image."
   (let ((inhibit-read-only t)
-	(buffer-undo-list t)
-	(modified (buffer-modified-p)))
+        (buffer-undo-list t)
+        (modified (buffer-modified-p)))
     (remove-list-of-text-properties (point-min) (point-max)
-				    '(display read-nonsticky ;; intangible
-					      read-only front-sticky))
+                                    '(display read-nonsticky ;; intangible
+                                              read-only front-sticky))
     (set-buffer-modified-p modified)
     (if (called-interactively-p 'any)
-	(message "Repeat this command to go back to displaying the image"))))
+        (message "Repeat this command to go back to displaying the image"))))
+
+(defun image-mode-show-thumbnails ()
+  "Show thumbnails alongside dired buffer.
+Based on `image-dired'"
+  (interactive)
+  (image-dired default-directory))
 
 (defvar archive-superior-buffer)
 (defvar tar-superior-buffer)
@@ -601,56 +664,67 @@ was inserted."
   (unless (derived-mode-p 'image-mode)
     (error "The buffer is not in Image mode"))
   (let* ((filename (buffer-file-name))
-	 (data-p (not (and filename
-			   (file-readable-p filename)
-			   (not (file-remote-p filename))
-			   (not (buffer-modified-p))
-			   (not (and (boundp 'archive-superior-buffer)
-				     archive-superior-buffer))
-			   (not (and (boundp 'tar-superior-buffer)
-				     tar-superior-buffer)))))
-	 (file-or-data (if data-p
-			   (string-make-unibyte
-			    (buffer-substring-no-properties (point-min) (point-max)))
-			 filename))
-	 (type (image-type file-or-data nil data-p))
-	 (image (create-image file-or-data type data-p))
-	 (inhibit-read-only t)
-	 (buffer-undo-list t)
-	 (modified (buffer-modified-p))
-	 props)
+         (data-p (not (and filename
+                           (file-readable-p filename)
+                           (not (file-remote-p filename))
+                           (not (buffer-modified-p))
+                           (not (and (boundp 'archive-superior-buffer)
+                                     archive-superior-buffer))
+                           (not (and (boundp 'tar-superior-buffer)
+                                     tar-superior-buffer)))))
+         (file-or-data (if data-p
+                           (string-make-unibyte
+                            (buffer-substring-no-properties (point-min) (point-max)))
+                         filename))
+         (image (create-image file-or-data nil data-p))
+         (type (plist-get (cdr image) :type))
+         ;; (type (image-type file-or-data nil data-p))
+         (inhibit-read-only t)
+         (buffer-undo-list t)
+         (modified (buffer-modified-p))
+         props)
 
     ;; Discard any stale image data before looking it up again.
     (image-flush image)
-    (setq image (append image (image-transform-properties image)))
+    (setq image (image-transform-interactive image
+                                             :resize image-mode-auto-resize
+                                             :rotate image-mode-auto-rotate))
     (setq props
-	  `(display ,image
-		    ;; intangible ,image
-		    rear-nonsticky (display) ;; intangible
-		    read-only t front-sticky (read-only)))
+          `(display ,image
+                    ;; intangible ,image
+                    rear-nonsticky (display) ;; intangible
+                    read-only t front-sticky (read-only)))
 
     (let ((buffer-file-truename nil)) ; avoid changing dir mtime by lock_file
       (add-text-properties (point-min) (point-max) props)
       (restore-buffer-modified-p modified))
     ;; Inhibit the cursor when the buffer contains only an image,
     ;; because cursors look very strange on top of images.
-    (setq cursor-type nil)
+
+    ;; VS[16-07-2013]: It is a blinking box around image. Not a big
+    ;; deal. It is way more important to distinguish active
+    ;; buffer/image. In the future we will have multiple images per
+    ;; buffer. Will need to activate it anyhow.
+
+    (unless image-mode-show-cursor
+      (setq cursor-type nil))
+
     ;; This just makes the arrow displayed in the right fringe
     ;; area look correct when the image is wider than the window.
     (setq truncate-lines t)
     ;; Disable adding a newline at the end of the image file when it
     ;; is written with, e.g., C-x C-w.
     (if (coding-system-equal (coding-system-base buffer-file-coding-system)
-			     'no-conversion)
-	(setq-local find-file-literally t))
+                             'no-conversion)
+        (setq-local find-file-literally t))
     ;; Allow navigation of large images.
     (setq-local auto-hscroll-mode nil)
     (setq image-type type)
     (if (eq major-mode 'image-mode)
-	(setq mode-name (format "Image[%s]" type)))
-    (image-transform-check-size)
+        (setq mode-name (format "Image[%s]" type)))
+    ;; (image--transform-check-size)
     (if (called-interactively-p 'any)
-	(message "Repeat this command to go back to displaying the file as text"))))
+        (message "Repeat this command to go back to displaying the file as text"))))
 
 (defun image-toggle-display ()
   "Toggle between image and text display.
@@ -685,7 +759,7 @@ If `image-animate-loop' is non-nil, animation loops forever.
 Otherwise it plays once, then stops."
   (interactive)
   (let ((image (image-get-display-property))
-	animation)
+        animation)
     (cond
      ((null image)
       (error "No image is present"))
@@ -693,15 +767,15 @@ Otherwise it plays once, then stops."
       (message "No image animation."))
      (t
       (let ((timer (image-animate-timer image)))
-	(if timer
-	    (cancel-timer timer)
-	  (let ((index (plist-get (cdr image) :index)))
-	    ;; If we're at the end, restart.
-	    (and index
-		 (>= index (1- (car animation)))
-		 (setq index nil))
-	    (image-animate image index
-			   (if image-animate-loop t)))))))))
+        (if timer
+            (cancel-timer timer)
+          (let ((index (plist-get (cdr image) :index)))
+            ;; If we're at the end, restart.
+            (and index
+                 (>= index (1- (car animation)))
+                 (setq index nil))
+            (image-animate image index
+                           (if image-animate-loop t)))))))))
 
 (defun image-goto-frame (n &optional relative)
   "Show frame N of a multi-frame image.
@@ -709,7 +783,7 @@ Optional argument OFFSET non-nil means interpret N as relative to the
 current frame.  Frames are indexed from 1."
   (interactive
    (list (or current-prefix-arg
-	     (read-number "Show frame number: "))))
+             (read-number "Show frame number: "))))
   (let ((image (image-get-display-property)))
     (cond
      ((null image)
@@ -718,9 +792,9 @@ current frame.  Frames are indexed from 1."
       (message "No image animation."))
      (t
       (image-show-frame image
-			(if relative
-			    (+ n (image-current-frame image))
-			  (1- n)))))))
+                        (if relative
+                            (+ n (image-current-frame image))
+                          (1- n)))))))
 
 (defun image-next-frame (&optional n)
   "Switch to the next frame of a multi-frame image.
@@ -752,13 +826,13 @@ replacing the current Image mode buffer."
   (unless buffer-file-name
     (error "The current image is not associated with a file"))
   (let* ((file (file-name-nondirectory buffer-file-name))
-	 (images (image-mode--images-in-directory file))
-	 (idx 0))
+         (images (image-mode--images-in-directory file))
+         (idx 0))
     (catch 'image-visit-next-file
       (dolist (f images)
-	(if (string= f file)
-	    (throw 'image-visit-next-file (1+ idx)))
-	(setq idx (1+ idx))))
+        (if (string= f file)
+            (throw 'image-visit-next-file (1+ idx)))
+        (setq idx (1+ idx))))
     (setq idx (mod (+ idx (or n 1)) (length images)))
     (find-alternate-file (nth idx images))))
 
@@ -774,8 +848,8 @@ replacing the current Image mode buffer."
 
 (defun image-mode--images-in-directory (file)
   (let* ((dir (file-name-directory buffer-file-name))
-	 (files (directory-files dir nil
-				 (image-file-name-regexp) t)))
+         (files (directory-files dir nil
+                                 (image-file-name-regexp) t)))
     ;; Add the current file to the list of images if necessary, in
     ;; case it does not match `image-file-name-regexp'.
     (unless (member file files)
@@ -791,8 +865,8 @@ replacing the current Image mode buffer."
 
 (defun image-bookmark-make-record ()
   `(,@(bookmark-make-record-default nil 'no-context 0)
-      (image-type . ,image-type)
-      (handler    . image-bookmark-jump)))
+    (image-type . ,image-type)
+    (handler    . image-bookmark-jump)))
 
 ;;;###autoload
 (defun image-bookmark-jump (bmk)
@@ -801,228 +875,7 @@ replacing the current Image mode buffer."
   (prog1 (bookmark-default-handler bmk)
     (when (not (string= image-type (bookmark-prop-get bmk 'image-type)))
       (image-toggle-display))))
-\f
-
-;; Not yet implemented.
-;; (defvar image-transform-minor-mode-map
-;;   (let ((map (make-sparse-keymap)))
-;;     ;; (define-key map  [(control ?+)] 'image-scale-in)
-;;     ;; (define-key map  [(control ?-)] 'image-scale-out)
-;;     ;; (define-key map  [(control ?=)] 'image-scale-none)
-;;     ;; (define-key map "c f h" 'image-scale-fit-height)
-;;     ;; (define-key map "c ]" 'image-rotate-right)
-;;     map)
-;;   "Minor mode keymap `image-transform-mode'.")
-;;
-;; (define-minor-mode image-transform-mode
-;;   "Minor mode for scaling and rotating images.
-;; With a prefix argument ARG, enable the mode if ARG is positive,
-;; and disable it otherwise.  If called from Lisp, enable the mode
-;; if ARG is omitted or nil.  This minor mode requires Emacs to have
-;; been compiled with ImageMagick support."
-;;   nil "image-transform" image-transform-minor-mode-map)
-
-
-;; FIXME this doesn't seem mature yet. Document in manual when it is.
-(defvar image-transform-resize nil
-  "The image resize operation.
-Its value should be one of the following:
- - nil, meaning no resizing.
- - `fit-height', meaning to fit the image to the window height.
- - `fit-width', meaning to fit the image to the window width.
- - A number, which is a scale factor (the default size is 1).")
-
-(defvar image-transform-scale 1.0
-  "The scale factor of the image being displayed.")
-
-(defvar image-transform-rotation 0.0
-  "Rotation angle for the image in the current Image mode buffer.")
-
-(defvar image-transform-right-angle-fudge 0.0001
-  "Snap distance to a multiple of a right angle.
-There's no deep theory behind the default value, it should just
-be somewhat larger than ImageMagick's MagickEpsilon.")
-
-(defsubst image-transform-width (width height)
-  "Return the bounding box width of a rotated WIDTH x HEIGHT rectangle.
-The rotation angle is the value of `image-transform-rotation' in degrees."
-  (let ((angle (degrees-to-radians image-transform-rotation)))
-    ;; Assume, w.l.o.g., that the vertices of the rectangle have the
-    ;; coordinates (+-w/2, +-h/2) and that (0, 0) is the center of the
-    ;; rotation by the angle A.  The projections onto the first axis
-    ;; of the vertices of the rotated rectangle are +- (w/2) cos A +-
-    ;; (h/2) sin A, and the difference between the largest and the
-    ;; smallest of the four values is the expression below.
-    (+ (* width (abs (cos angle))) (* height (abs (sin angle))))))
-
-;; The following comment and code snippet are from
-;; ImageMagick-6.7.4-4/magick/distort.c
-
-;;    /* Set the output image geometry to calculated 'best fit'.
-;;       Yes this tends to 'over do' the file image size, ON PURPOSE!
-;;       Do not do this for DePolar which needs to be exact for virtual tiling.
-;;    */
-;;    if ( fix_bounds ) {
-;;      geometry.x = (ssize_t) floor(min.x-0.5);
-;;      geometry.y = (ssize_t) floor(min.y-0.5);
-;;      geometry.width=(size_t) ceil(max.x-geometry.x+0.5);
-;;      geometry.height=(size_t) ceil(max.y-geometry.y+0.5);
-;;    }
-
-;; Other parts of the same file show that here the origin is in the
-;; left lower corner of the image rectangle, the center of the
-;; rotation is the center of the rectangle and min.x and max.x
-;; (resp. min.y and max.y) are the smallest and the largest of the
-;; projections of the vertices onto the first (resp. second) axis.
-
-(defun image-transform-fit-width (width height length)
-  "Return (w . h) so that a rotated w x h image has exactly width LENGTH.
-The rotation angle is the value of `image-transform-rotation'.
-Write W for WIDTH and H for HEIGHT.  Then the w x h rectangle is
-an \"approximately uniformly\" scaled W x H rectangle, which
-currently means that w is one of floor(s W) + {0, 1, -1} and h is
-floor(s H), where s can be recovered as the value of `image-transform-scale'.
-The value of `image-transform-rotation' may be replaced by
-a slightly different angle.  Currently this is done for values
-close to a multiple of 90, see `image-transform-right-angle-fudge'."
-  (cond ((< (abs (- (mod (+ image-transform-rotation 90) 180) 90))
-	    image-transform-right-angle-fudge)
-	 (cl-assert (not (zerop width)) t)
-	 (setq image-transform-rotation
-	       (float (round image-transform-rotation))
-	       image-transform-scale (/ (float length) width))
-	 (cons length nil))
-	((< (abs (- (mod (+ image-transform-rotation 45) 90) 45))
-	    image-transform-right-angle-fudge)
-	 (cl-assert (not (zerop height)) t)
-	 (setq image-transform-rotation
-	       (float (round image-transform-rotation))
-	       image-transform-scale (/ (float length) height))
-	 (cons nil length))
-	(t
-	 (cl-assert (not (and (zerop width) (zerop height))) t)
-	 (setq image-transform-scale
-	       (/ (float (1- length)) (image-transform-width width height)))
-	 ;; Assume we have a w x h image and an angle A, and let l =
-	 ;; l(w, h) = w |cos A| + h |sin A|, which is the actual width
-	 ;; of the bounding box of the rotated image, as calculated by
-	 ;; `image-transform-width'.  The code snippet quoted above
-	 ;; means that ImageMagick puts the rotated image in
-	 ;; a bounding box of width L = 2 ceil((w+l+1)/2) - w.
-	 ;; Elementary considerations show that this is equivalent to
-	 ;; L - w being even and L-3 < l(w, h) <= L-1.  In our case, L is
-	 ;; the given `length' parameter and our job is to determine
-	 ;; reasonable values for w and h which satisfy these
-	 ;; conditions.
-	 (let ((w (floor (* image-transform-scale width)))
-	       (h (floor (* image-transform-scale height))))
-	   ;; Let w and h as bound above.  Then l(w, h) <= l(s W, s H)
-	   ;; = L-1 < l(w+1, h+1) = l(w, h) + l(1, 1) <= l(w, h) + 2,
-	   ;; hence l(w, h) > (L-1) - 2 = L-3.
-	   (cons
-	    (cond ((= (mod w 2) (mod length 2))
-		   w)
-		  ;; l(w+1, h) >= l(w, h) > L-3, but does l(w+1, h) <=
-		  ;; L-1 hold?
-		  ((<= (image-transform-width (1+ w) h) (1- length))
-		   (1+ w))
-		  ;; No, it doesn't, but this implies that l(w-1, h) =
-		  ;; l(w+1, h) - l(2, 0) >= l(w+1, h) - 2 > (L-1) -
-		  ;; 2 = L-3.  Clearly, l(w-1, h) <= l(w, h) <= L-1.
-		  (t
-		   (1- w)))
-	    h)))))
-
-(defun image-transform-check-size ()
-  "Check that the image exactly fits the width/height of the window.
-
-Do this for an image of type `imagemagick' to make sure that the
-elisp code matches the way ImageMagick computes the bounding box
-of a rotated image."
-  (when (and (not (numberp image-transform-resize))
-	     (boundp 'image-type)
-	     (eq image-type 'imagemagick))
-    (let ((size (image-display-size (image-get-display-property) t)))
-      (cond ((eq image-transform-resize 'fit-width)
-	     (cl-assert (= (car size)
-			(- (nth 2 (window-inside-pixel-edges))
-			   (nth 0 (window-inside-pixel-edges))))
-		     t))
-	    ((eq image-transform-resize 'fit-height)
-	     (cl-assert (= (cdr size)
-			(- (nth 3 (window-inside-pixel-edges))
-			   (nth 1 (window-inside-pixel-edges))))
-		     t))))))
-
-(defun image-transform-properties (spec)
-  "Return rescaling/rotation properties for image SPEC.
-These properties are determined by the Image mode variables
-`image-transform-resize' and `image-transform-rotation'.  The
-return value is suitable for appending to an image spec.
-
-Rescaling and rotation properties only take effect if Emacs is
-compiled with ImageMagick support."
-  (setq image-transform-scale 1.0)
-  (when (or image-transform-resize
-	    (/= image-transform-rotation 0.0))
-    ;; Note: `image-size' looks up and thus caches the untransformed
-    ;; image.  There's no easy way to prevent that.
-    (let* ((size (image-size spec t))
-	   (resized
-	    (cond
-	     ((numberp image-transform-resize)
-	      (unless (= image-transform-resize 1)
-		(setq image-transform-scale image-transform-resize)
-		(cons nil (floor (* image-transform-resize (cdr size))))))
-	     ((eq image-transform-resize 'fit-width)
-	      (image-transform-fit-width
-	       (car size) (cdr size)
-	       (- (nth 2 (window-inside-pixel-edges))
-		  (nth 0 (window-inside-pixel-edges)))))
-	     ((eq image-transform-resize 'fit-height)
-	      (let ((res (image-transform-fit-width
-			  (cdr size) (car size)
-			  (- (nth 3 (window-inside-pixel-edges))
-			     (nth 1 (window-inside-pixel-edges))))))
-		(cons (cdr res) (car res)))))))
-      `(,@(when (car resized)
-	    (list :width (car resized)))
-	,@(when (cdr resized)
-	    (list :height (cdr resized)))
-	,@(unless (= 0.0 image-transform-rotation)
-	    (list :rotation image-transform-rotation))))))
-
-(defun image-transform-set-scale (scale)
-  "Prompt for a number, and resize the current image by that amount.
-This command has no effect unless Emacs is compiled with
-ImageMagick support."
-  (interactive "nScale: ")
-  (setq image-transform-resize scale)
-  (image-toggle-display-image))
-
-(defun image-transform-fit-to-height ()
-  "Fit the current image to the height of the current window.
-This command has no effect unless Emacs is compiled with
-ImageMagick support."
-  (interactive)
-  (setq image-transform-resize 'fit-height)
-  (image-toggle-display-image))
 
-(defun image-transform-fit-to-width ()
-  "Fit the current image to the width of the current window.
-This command has no effect unless Emacs is compiled with
-ImageMagick support."
-  (interactive)
-  (setq image-transform-resize 'fit-width)
-  (image-toggle-display-image))
-
-(defun image-transform-set-rotation (rotation)
-  "Prompt for an angle ROTATION, and rotate the image by that amount.
-ROTATION should be in degrees.  This command has no effect unless
-Emacs is compiled with ImageMagick support."
-  (interactive "nRotation angle (in degrees): ")
-  (setq image-transform-rotation (float (mod rotation 360)))
-  (image-toggle-display-image))
 
 (provide 'image-mode)
 
diff --git a/lisp/image-transform.el b/lisp/image-transform.el
new file mode 100644
index 0000000..080ae4f
--- /dev/null
+++ b/lisp/image-transform.el
@@ -0,0 +1,930 @@
+;;; image-transform.el --- support for image transformations  -*- lexical-binding: nil -*-
+;;
+;; Copyright (C) 2013 Free Software Foundation, Inc.
+;;
+;; Author: Vitalie Spinu <spinuvit@gmail.com>
+;; Keywords: multimedia
+;; Package: emacs
+;;
+;; This file is part of GNU Emacs.
+;;
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+;;
+;;; Commentary:
+;;
+;;; Code:
+
+(require 'image)
+(require 'pcase)
+(eval-when-compile
+  (require 'cl-macs)
+  ;; (require 'cl-lib)
+  )
+
+
+\f
+;;; GENERAL IMAGE FUNCTIONS (fixme: move to image.el)
+
+(defun image-get-display-property (&optional pos)
+  (setq pos (or pos (point)))
+  (or (get-char-property pos 'display
+                         ;; There might be different images for different displays.
+                         (if (eq (window-buffer) (current-buffer))
+                             (selected-window)))
+      ;; overlay before-string/after-string display property, like in put-image
+      (let ((OVS (overlays-at pos))
+            ov disp)
+        (while (setq ov (pop OVS))
+          (let ((bs (overlay-get ov 'before-string))
+                (as (overlay-get ov 'after-string)))
+            ;; last one takes precedence
+            (setq disp (or (and as (get-text-property 0 'display as))
+                           (and bs (get-text-property 0 'display bs))))))
+        disp)))
+
+;;;###autoload
+(defun get-image (&optional pos)
+  "Get image at POS in current buffer
+
+This function investigates text properties as well as overlays at
+POS for display property that holds an image."
+  (let* ((disp (image-get-display-property pos)))
+    (or (and (eq (car-safe disp) 'image)
+             disp)
+        ;; margin images
+        (and (eq (car-safe (cdr-safe disp)) 'image)
+             (cdr disp)))))
+
+(defun image--delete-properties (image props)
+  "Remove PROPS from IMAGE destructively.
+This is as opposed to setting them to nil. Return transformed
+image."
+  (let ((p (cdr image)))
+    (while p
+      (if (member (cadr p) props)
+          (setcdr p (nthcdr 3 p))
+        (setq p (cdr p)))
+      image)))
+
+\f
+;;; INTERNALS
+;; these are 3, virtuly unchenged, objects from old image-mode.el
+;; fixme: see the author
+(defvar image--right-angle-fudge 0.0001
+  "Snap distance to a multiple of a right angle.
+There's no deep theory behind the default value, it should just
+be somewhat larger than ImageMagick's MagickEpsilon.")
+
+(defsubst image--get-rotated-width (width height rotation)
+  "Return the bounding box width of a rotated WIDTH x HEIGHT rectangle.
+ROTATION is the rotation angle in  degrees."
+  (let ((angle (degrees-to-radians rotation)))
+    ;; Assume, w.l.o.g., that the vertices of the rectangle have the
+    ;; coordinates (+-w/2, +-h/2) and that (0, 0) is the center of the
+    ;; rotation by the angle A.  The projections onto the first axis
+    ;; of the vertices of the rotated rectangle are +- (w/2) cos A +-
+    ;; (h/2) sin A, and the difference between the largest and the
+    ;; smallest of the four values is the expression below.
+    (+ (* width (abs (cos angle))) (* height (abs (sin angle))))))
+
+;; The following comment and code snippet are from
+;; ImageMagick-6.7.4-4/magick/distort.c
+
+;;    /* Set the output image geometry to calculated 'best fit'.
+;;       Yes this tends to 'over do' the file image size, ON PURPOSE!
+;;       Do not do this for DePolar which needs to be exact for virtual tiling.
+;;    */
+;;    if ( fix_bounds ) {
+;;      geometry.x = (ssize_t) floor(min.x-0.5);
+;;      geometry.y = (ssize_t) floor(min.y-0.5);
+;;      geometry.width=(size_t) ceil(max.x-geometry.x+0.5);
+;;      geometry.height=(size_t) ceil(max.y-geometry.y+0.5);
+;;    }
+
+;; Other parts of the same file show that here the origin is in the
+;; left lower corner of the image rectangle, the center of the
+;; rotation is the center of the rectangle and min.x and max.x
+;; (resp. min.y and max.y) are the smallest and the largest of the
+;; projections of the vertices onto the first (resp. second) axis.
+
+(defun image--get-rotated-size (width height length &optional rotation)
+  "Return (w . h) so that a rotated w x h image has exactly width LENGTH.
+The ROTATION angle defaults 0 and SCALE to 1.
+
+Write W for WIDTH and H for HEIGHT.  Then the w x h rectangle is
+an \"approximately uniformly\" scaled W x H rectangle, which
+currently means that w is one of floor(s W) + {0, 1, -1} and h is
+floor(s H), where s is a scale factor. The value of ROTATION may
+be replaced by a slightly different angle.  Currently this is
+done for values close to a multiple of 90, see
+`image--right-angle-fudge'."
+  (setq rotation (or rotation 0.0))
+  (cond ((< (abs (- (mod (+ rotation 90) 180) 90))
+            image--right-angle-fudge)
+         (cl-assert (not (zerop width)) t)
+         (cons length nil))
+        ((< (abs (- (mod (+ rotation 45) 90) 45))
+            image--right-angle-fudge)
+         (cl-assert (not (zerop height)) t)
+         (cons nil length))
+        (t
+         (let (scale)
+           (cl-assert (not (and (zerop width) (zerop height))) t)
+           ;; on GNU Emacs 24.3.50.4 (i686-pc-linux-gnu, X toolkit, Xaw
+           ;; scroll bars) of 2013-07-16, image width is slightly
+           ;; truncated, ~6px, so the below mambo math for .5px
+           ;; adjustment is pretty useless.
+           (setq scale
+                 (/ (float (1- length))
+                    (image--get-rotated-width width height rotation)))
+           ;; Assume we have a w x h image and an angle A, and let l =
+           ;; l(w, h)) = w |cos A| + h |sin A|, which is the actual width
+           ;; of the bounding box of the rotated image, as calculated by
+           ;; `image--get-rotated-width'.  The code snippet quoted above
+           ;; means that ImageMagick puts the rotated image in
+           ;; a bounding box of width L = 2 ceil((w+l+1)/2) - w.
+           ;; Elementary considerations show that this is equivalent to
+           ;; L - w being even and L-3 < l(w, h) <= L-1.  In our case, L is
+           ;; the given `length' parameter and our job is to determine
+           ;; reasonable values for w and h which satisfy these
+           ;; conditions.
+           (let ((w (floor (* scale width)))
+                 (h (floor (* scale height))))
+             ;; Let w and h as bound above.  Then l(w, h) <= l(s W, s H)
+             ;; = L-1 < l(w+1, h+1) = l(w, h) + l(1, 1) <= l(w, h) + 2,
+             ;; hence l(w, h) > (L-1) - 2 = L-3.
+             (cons
+              ;; VS[16-07-2013]: returning (w . h) is unnecessary, it
+              ;; distorts the image and processing becomes very slow
+
+              (cond ((= (mod w 2) (mod length 2))
+                     w)
+                    ;; l(w+1, h) >= l(w, h) > L-3, but does l(w+1, h) <=
+                    ;; L-1 hold?
+                    ((<= (image--get-rotated-width (1+ w) h rotation)
+                         (1- length))
+                     (1+ w))
+                    ;; No, it doesn't, but this implies that l(w-1, h) =
+                    ;; l(w+1, h) - l(2, 0) >= l(w+1, h) - 2 > (L-1) -
+                    ;; 2 = L-3.  Clearly, l(w-1, h) <= l(w, h) <= L-1.
+                    (t
+                     (1- w)))
+              nil))))))
+
+
+\f
+;;; TRANSFORM API
+
+;;;###autoload
+(defun image-transform (image &rest specs)
+  "Return destructively transformed IMAGE."
+
+  ;; ROTATE is the rotation angle in degrees.
+
+  ;; RESIZE can be
+  ;;  - a number, giving a proportional scaling of the image.
+  ;;  - a cons, giving thesize (w x h) in pixels.
+  ;;  - a symbol:
+  ;;    *`fit' - maximally scale IMAGE to fit into WIN.
+  ;;    *`fit-height' - fit the image to WIN's height.
+  ;;    *`fit-width' - fit the image to WIN's width.
+  ;;    *`fit-stretch' - stretch the image to fit to both height and
+  ;;     width of WIN.
+
+  ;; WIN is a window that is used when RESIZE is a symbol.  Defaults
+  ;; to the selected window.
+
+  ;; This functions uses plist-put. Thus it might, or might not
+  ;; destructively modify IMAGE.
+
+  ;; Rescaling, resizing and rotation only take effect if Emacs is
+  ;; compiled with ImageMagick support."
+
+  (let* ((resize (cadr (memq :resize specs)))
+         (rotate (cadr (memq :rotate specs)))
+         (orot (plist-get (cdr image) :rotation)))
+    (setq rotate (float (mod (+ (or rotate 0.0) (or orot 0.0)) 360)))
+    ;; Reset rotation. Otherwise returned image-size is the size of
+    ;; rotated image, and image-size seems to rotate the image
+    ;; internally before reporting the size. This could be slow. Avoid
+    ;; this and other problems by caching original size below.
+    ;; (image--delete-properties image :rotation)
+
+    (when (symbolp resize)
+
+      (unless (and (symbolp resize)
+                   (member resize '(nil fit fit-if-large fit-width
+                                        fit-height fit-stretch)))
+        (error "Invalid :resize argument"))
+
+      (let* ((win (or (cadr (memq :WIN specs))
+                      (selected-window)))
+             ;; Note: `image-size' looks up and thus caches the
+             ;; untransformed (VS[17-07-2013]: I think this changed,
+             ;; it returns transformed size for me) image. There's no
+             ;; easy way to prevent that.
+             (size (or (plist-get (cdr image) :osize)
+                       (image-size image t)))
+             ;; transformed by the user: user-size
+             (usize (cons (plist-get (cdr image) :width)
+                          (plist-get (cdr image) :height)))
+             newsize)
+
+        ;; (image--delete-properties image '(:width :height))
+        ;; cache original-size
+        (plist-put (cdr image) :osize size)
+
+        (setq newsize (cons (image--get-rotated-width
+                             (car size) (cdr size) rotate)
+                            (image--get-rotated-width
+                             (cdr size) (car size) rotate)))
+
+        (plist-put specs :resize
+                   ;; fixme: simplify with pcase?
+                   (let* ((wedges (window-inside-pixel-edges win))
+                          (wsize (cons (- (nth 2 wedges)
+                                          (nth 0 wedges))
+                                       (- (nth 3 wedges)
+                                          (nth 1 wedges))))
+                          (resize (if (and (eq resize 'fit-if-large)
+                                           (or (> (car newsize) (car wsize))
+                                               (> (cdr newsize) (cdr wsize))))
+                                      'fit
+                                    resize))
+                          (resize (if (eq resize 'fit)
+                                      (if (< (/ (float (car wsize)) (cdr wsize))
+                                             (/ (float (car newsize)) (cdr newsize)))
+                                          'fit-width
+                                        'fit-height)
+                                    resize)))
+
+                     (cond
+                      ((eq resize 'fit-stretch)
+                       (let ((res (image--get-rotated-size
+                                   (car wsize) (cdr wsize) (car wsize) rotate)))
+                         ;; fixme: stretching doesn't work correctly with rotation
+                         (when (null (car res))
+                           (setcar res (car wsize)))
+                         (when (null (cdr res))
+                           (setcdr res (cdr wsize)))
+                         res))
+                      ((eq resize 'fit-width)
+                       (image--get-rotated-size
+                        (car size) (cdr size) (car wsize) rotate))
+                      ((eq resize 'fit-height)
+                       (let ((res (image--get-rotated-size
+                                   (cdr size) (car size) (cdr wsize) rotate)))
+                         (cons (cdr res) (car res)))))))))
+    
+    (when (or (and orot (/= rotate orot))
+              (/= rotate 0.0))
+      (plist-put specs :rotate rotate))
+
+    (let ((bfuncs (cl-loop for b in image-transform-backends
+                        collect (intern (concat "image-transform:" (symbol-name b)))))
+          timage)
+      (while (and bfuncs
+                  (null (setq timage
+                              (apply (pop bfuncs) image specs))))))
+    ;; (setcdr image (cdr image))
+    image))
+
+(defun image-transform-interactive (&optional image &rest specs)
+  "Like `image-transform' but finds IMAGE at point if not supplied.
+and refreshes window display. Intended to be used for user level commands."
+  (unless image
+    (unless (setq image (get-image))
+      (error "No image at point")))
+
+  (prog1 (apply 'image-transform image specs)
+    (force-window-update (selected-window))))
+
+(defun image-transform-unsupported-features (backend specs)
+  "Return unsupported features of BACKEND from the list of features in SPECS.
+SPECS is a list of :keyword value pairs like in plist but with
+value might be omitted. Features are the keywords. BACKEND is a
+symbol or string and FEATURES is a list of symbols to be looked
+in image-transform-features:BACKEND alist."
+  (let ((features (cl-loop for s in specs if (keywordp s) collect s))
+        (available (symbol-value
+                    (intern (concat "image-transform-features:"
+                                    (if (symbolp backend)
+                                        (symbol-name backend)
+                                      backend))))))
+    (cl-loop for f in features
+          unless (assoc f available)
+          collect f)))
+
+(defcustom image-transform-backends '(imagemagick convert)
+  "Backends to try out for image transformation.
+
+For `imagemagick', `image-transform' will try to use internal
+Emacs ImageMagick support. For `convert' use external ImageMagick
+\"convert\" utility to produce a transformed temporary image
+file.
+
+If Emacs was not compiled with ImageMagick support `imagemagick'
+backend is ignored.
+
+The actual transformation functions are image-transform:BACKEND
+where BACKEND is backend's name. See `image-transform' for more."
+  :group 'image
+  :type '(repeat symbol))
+
+\f
+;;; IMAGEMAGICK BACKEND
+(defun image-transform:imagemagick (image &rest specs)
+  "Image transform Emacs ImageMagick backend.
+See `image-transform' for the definition of SPEC and what a
+image-transform:BACKEND function should do.
+
+Accepted arguments by this backend:
+
+:resize - If number treat as width. If string, should be of the
+form Wx, xH, WxH where x is arbitrary string not containing
+numbers. If cons:  (W . H). 
+
+:scale - If number scale in percent. If string, should either
+encode a number or be of the form S% where S is a number.
+
+:rotate - Number or numeric string giving the rotation in
+degrees.
+
+:background - String giving color."
+  (when (and (image-type-available-p 'imagemagick)
+             (null (image-transform-unsupported-features 'imagemagick specs)))
+    ;; first process specs and then adjust the image
+    (let ((new-specs
+           (cl-loop for s on specs by 'cddr append
+                 ;; fixme: rewrite in terms of simple cons
+                 (pcase s 
+                   (`(:resize . (,size . ,_))
+                    (setq size
+                          (pcase size
+                            ((or (pred null)
+                                 (pred consp)) size)
+                            ((pred numberp) (cons size nil))
+                            ((pred stringp)
+                             (if (image-tr--parse-geometry:convert size t)
+                                 (cl-return) ; resize is intended for :convert backend,
+                               (image-tr--parse-geometry:imagemagick size)))
+                            ((pred keywordp) (error ":resize parameter is empty"))
+                            (_ (cl-return))))
+                    `((:width . ,(car size)) (:height . ,(cdr size))))
+                   (`(:scale . (,scale . ,_))
+                    (setq scale
+                          (pcase scale
+                            ((or (pred null)
+                                 (pred numberp)) scale)
+                            ((pred stringp) (or (image-tr--parse-scale:imagemagick scale)
+                                                (cl-return))) ; not intended for imagemagick
+                            ((pred keywordp) (error ":scale parameter is empty"))
+                            (_ (cl-return))))
+                    `((:scale . ,scale)))
+                   (`(:background . (,bg . ,_))
+                    (if (stringp bg)
+                        `((:background . ,bg))
+                      (if (keywordp bg)
+                          (error ":background argument is emtpy")                                                   
+                        (cl-return))))
+                   (`(:rotate . (,rot . ,_))
+                    (let ((out (pcase rot
+                                 ((or (pred null)
+                                      (pred numberp)) rot)
+                                 ((pred stringp) (or (image-tr--parse-number:imagemagick rot)
+                                                     (cl-return)))
+                                 ((pred keywordp) (error ":scale parameter is empty"))
+                                 (_ (cl-return)))))
+                      `((:rotation . ,out))))
+                   (x (error "%s is not a feature in imagemagick backend" x))))))
+      (when new-specs
+        ;; specs are correct so alter the image
+        (cl-loop for s in new-specs do
+              ;; null values have no effect? tothink: chaining effect
+              (when (cdr s) 
+                (pcase s
+                  (`(:width . ,w)
+                   (plist-put (cdr image) :width w))
+                  (`(:height . ,h)
+                   (plist-put (cdr image) :height h))
+                  (`(:scale . ,s)
+                   (unless (= s 100)
+                     (let ((s (/ s 100.0))
+                           (uw (plist-get (cdr image) :width))
+                           (uh (plist-get (cdr image) :height)))
+                       ;; only one could have been supplied, keep it
+                       (if (or uw uh)
+                           (progn (when uw
+                                    (plist-put (cdr image)
+                                               :width (floor (* s uw))))
+                                  (when uh
+                                    (plist-put (cdr image)
+                                               :height (floor (* s uh)))))
+                         (let ((size (or (plist-get (cdr image) :osize)
+                                         (image-size image t))))
+                           (plist-put (cdr image) :osize size)
+                           (plist-put (cdr image) :width (floor (* s (car size)))))))))
+                  (`(,kwd . ,val) (plist-put (cdr image) kwd val))
+                  (_ (error "Unclear mess in imagemagick backend. Please report")))))
+        (plist-put (cdr image) :type 'imagemagick)
+        image))))
+
+(defvar image-transform-features:imagemagick '((:background)
+                                               (:resize)
+                                               (:rotate)
+                                               (:scale))
+  "List of supported features by Emacs ImageMagick backend.")
+
+(defun image-tr--parse-geometry:imagemagick (geom)
+  "Simple geometry parser.
+Parse WxH where W and H are digits and x is arbitrary non digit
+string. Wx and xH are also fine with obvious interpretation. xHx
+is interpreted as height. Return (W . H) where W and H are
+strings representing numbers or nil."
+  ;; fixme: multiple dots are not checked
+  (if (not (string-match "^\\([0-9.]+\\)*[^0-9.]*\\([0-9.]*\\)" geom))
+      (error "Invalid geometry format supplied")
+    (let ((out (cons (match-string 1 geom)
+                     (match-string 2 geom))))
+      (setcar out
+              (unless (= 0 (length (car out)))
+                (string-to-number (car out))))
+      (setcdr out
+              (unless (= 0 (length (cdr out)))
+                (string-to-number (cdr out)))))))
+
+(defun image-tr--parse-scale:imagemagick (scale)
+  (when (string-match "^ *\\([0-9.]\\)%? *$" scale)
+    (string-to-number (match-string 1 scale))))
+
+(defun image-tr--parse-number:imagemagick (scale)
+  (when (string-match "^ *\\([0-9.]\\) *$" scale)
+    (string-to-number (match-string 1 scale))))
+
+\f
+;;; CONVERT BACKEND
+
+(defun image-transform:convert (image &rest specs)
+  nil)
+
+(defun image-tr--parse-geometry:convert (geom &optional specific?)
+  "If geom is an ImageMagick geometry specification return GEOM else nil.
+If SPECIFIC is non-nil match only the specific convert regexp. 
+See http://www.imagemagick.org/script/command-line-processing.php#geometry"
+  (when (and geom
+             (string-match-p
+              (concat "^ *"
+                      (unless specific? "[0-9.]+\\|" )
+                      "\\([0-9.]+%\\|[0-9.]+%x[0-9.]+%\\|[0-9.]+x[0-9.]+[!<>^]?\\|[0-9.]+@\\) *$")
+              geom))
+    geom))
+
+(defvar image-transform-features:convert 
+  "Convert backend features.
+An alist of values like (:feature type 'description'). If type is
+nil, this is a boolean option."
+
+  '(
+    ;; Image Settings:
+    (:adjoin nil 	"join images into a single multi-image file")
+    (:affine 'matrix	"affine transform matrix")
+    (:antialias nil	"remove pixel-aliasing")
+    (:authenticate 'value	"decrypt image with this password")
+    (:background 'color	"background color")
+    (:bias 'value	"add bias when convolving an image")
+    (:black-point-compensation nil	"use black point compensation")
+    (:blue-primary 'point	"chromaticity blue primary point")
+    (:bordercolor 'color	"border color")
+    (:caption 'string	"assign a caption to an image")
+    (:cdl 'filename	"color correct with a color decision list")
+    (:channel 'type	"apply option to select image channels")
+    (:colors 'value	"preferred number of colors in the image")
+    (:colorspace 'type	"alternate image colorspace")
+    (:comment 'string	"annotate image with comment")
+    (:compose 'operator	"set image composite operator")
+    (:compress 'type	"type of pixel compression when writing the image")
+    (:decipher 'filename	"convert cipher pixels to plain pixels")
+    (:define 'format:option	"define one or more image format options")
+    (:delay 'value	"display the next image after pausing")
+    (:density 'geometry	"horizontal and vertical density of the image")
+    (:depth 'value	"image depth")
+    (:direction 'type	"render text right-to-left or left-to-right")
+    (:display 'server	"get image or font from this X server")
+    (:dispose 'method	"layer disposal method")
+    (:dither 'method	"apply error diffusion to image")
+    (:encipher 'filename	"convert plain pixels to cipher pixels")
+    (:encoding 'type	"text encoding type")
+    (:endian 'type	"endianness (MSB or LSB) of the image")
+    (:family 'name	"render text with this font family")
+    (:features 'distance	"analyze image features (e.g. contrast, correlation")
+    (:fill 'color	"color to use when filling a graphic primitive")
+    (:filter 'type	"use this filter when resizing an image")
+    (:flatten nil	"flatten a sequence of images")
+    (:font 'name	"render text with this font")
+    (:format 'string	"output formatted image characteristics")
+    (:fuzz 'distance	"colors within this distance are considered equal")
+    (:gravity 'type	"horizontal and vertical text placement")
+    (:green-primary point 	"chromaticity green primary point")
+    (:intent 'type	"type of rendering intent when managing the image color")
+    (:interlace 'type	"type of image interlacing scheme")
+    (:interpolate 'method	"pixel color interpolation method")
+    (:kerning 'value	"set the space between two letters")
+    (:label 'string	"assign a label to an image")
+    (:limit type value	"pixel cache resource limit")
+    (:loop 'iterations	"add Netscape loop extension to your GIF animation")
+    (:mask 'filename	"associate a mask with the image")
+    (:matte nil 	"store matte channel if the image has one")
+    (:mattecolor 'color	"frame color")
+    (:monitor nil 	"monitor progress")
+    (:orient 'type	"image orientation")
+    (:origin 'geometry	"image origin")
+    (:page 'geometry	"size and location of an image canvas (setting)")
+    (:ping nil 	"efficiently determine image attributes")
+    (:pointsize 'value	"font point size")
+    (:preview 'type	"image preview type")
+    (:quality 'value	"JPEG/MIFF/PNG compression level")
+    (:quiet nil 	"suppress all warning messages")
+    (:red-primary 'point	"chromaticity red primary point")
+    (:regard-warnings nil 	"pay attention to warning messages")
+    (:sampling-factor 'geometry	"horizontal and vertical sampling factor")
+    (:scene 'value	"image scene number")
+    (:seed 'value	"seed a new sequence of pseudo-random numbers")
+    (:size 'geometry	"width and height of image")
+    (:statistic type geometry	"replace each pixel with corresponding statistic from the neighborhood")
+    (:stretch 'type	"render text with this font stretch")
+    (:stroke 'color	"graphic primitive stroke color")
+    (:strokewidth 'value	"graphic primitive stroke width")
+    (:style 'type	"render text with this font style")
+    (:support 'factor	"resize support: > 1.0 is blurry, < 1.0 is sharp")
+    (:synchronize nil 	"synchronize image to storage device")
+    (:taint nil 	"declare the image as modified")
+    (:texture 'filename	"name of texture to tile onto the image background")
+    (:tile-offset 'geometry	"tile offset")
+    (:treedepth 'value	"color tree depth")
+    (:transparent-color 'color	"transparent color")
+    (:undercolor 'color	"annotation bounding box color")
+    (:units 'type	"the units of image resolution")
+    (:verbose nil 	"print detailed information about the image")
+    (:view nil 	"FlashPix viewing transforms")
+    (:virtual-pixel 'method	"virtual pixel access method")
+    (:weight 'type	"render text with this font weight")
+    (:white-point 'point	"chromaticity white point")
+
+    ;; Image Operators:
+    (:adaptive-blur 'geometry	"adaptively blur pixels, decrease effect near edges")
+    (:adaptive-resize 'geometry	"adaptively resize image with data dependent triangulation")
+    (:adaptive-sharpen 'geometry	"adaptively sharpen pixels, increase effect near edges")
+    (:annotate geometry text 	"annotate the image with text")
+    (:auto-orient nil 	"automatically orient image")
+    (:black-threshold 'value	"force all pixels below the threshold into black")
+    (:blur 'geometry	"reduce image noise and reduce detail levels")
+    (:border 'geometry	"surround image with a border of color")
+    (:charcoal 'radius	"simulate a charcoal drawing")
+    (:chop 'geometry	"remove pixels from the image interior")
+    (:clip nil 	"clip along the first path from the 8BIM profile")
+    (:clip-mask 'filename	"associate a clip mask with the image")
+    (:clip-path 'id	"clip along a named path from the 8BIM profile")
+    (:colorize 'value	"colorize the image with the fill color")
+    (:color-matrix 'matrix  "apply color correction to the image")
+    (:contrast nil 	"enhance or reduce the image contrast")
+    (:contrast-stretch 'geometry	"improve contrast by `stretching' the intensity range")
+    (:convolve 'coefficients	"apply a convolution kernel to the image")
+    (:cycle 'amount	"cycle the image colormap")
+    (:despeckle nil 	"reduce the speckles within an image")
+    (:draw 'string	"annotate the image with a graphic primitive")
+    (:edge 'radius	"apply a filter to detect edges in the image")
+    (:emboss 'radius	"emboss an image")
+    (:enhance nil 	"apply a digital filter to enhance a noisy image")
+    (:equalize nil 	"perform histogram equalization to an image")
+    (:evaluate operator value	"evaluate an arithmetic, relational, or logical expression")
+    (:extent 'geometry	"set the image size")
+    (:extract 'geometry	"extract area from image")
+    (:fft nil 	"implements the discrete Fourier transform (DFT)")
+    (:flip nil 	"flip image vertically")
+    (:floodfill 'geometry-color	"floodfill the image with color") ;??
+    (:flop nil 	"flop image horizontally")
+    (:frame 'geometry	"surround image with an ornamental border")
+    (:function 'name	"apply a function to the image")
+    (:gamma 'value	"level of gamma correction")
+    (:gaussian-blur 'geometry	"reduce image noise and reduce detail levels")
+    (:geometry 'geometry	"preferred size or location of the image")
+    (:identify nil 	"identify the format and characteristics of the image")
+    (:ift nil 	"implements the inverse discrete Fourier transform (DFT)")
+    (:implode 'amount	"implode image pixels about the center")
+    (:lat 'geometry	"local adaptive thresholding")
+    (:layers 'method	"optimize or compare image layers")
+    (:level 'value	"adjust the level of image contrast")
+    (:linear-stretch 'geometry	"improve contrast by `stretching with saturation' the intensity range")
+    (:median 'geometry	"apply a median filter to the image")
+    (:mode 'geometry	"make each pixel the 'predominant color' of the neighborhood")
+    (:modulate 'value	"vary the brightness, saturation, and hue")
+    (:monochrome nil 	"transform image to black and white")
+    (:morphology 'method-kernel	"apply a morphology method to the image") ;;??
+    (:motion-blur 'geometry	"simulate motion blur")
+    (:negate nil 	"replace each pixel with its complementary color")
+    (:noise 'geometry	"add or reduce noise in an image")
+    (:normalize nil 	"transform image to span the full range of colors")
+    (:opaque 'color	"change this color to the fill color")
+    (:ordered-dither 'NxN	"add a noise pattern to the image with specific amplitudes")
+    (:paint 'radius	"simulate an oil painting")
+    (:polaroid 'angle	"simulate a Polaroid picture")
+    (:posterize 'levels	"reduce the image to a limited number of color levels")
+    (:print 'string	"interpret string and print to console")
+    (:profile 'filename	"add, delete, or apply an image profile")
+    (:quantize 'colorspace	"reduce colors in this colorspace")
+    (:radial-blur 'angle	"radial blur the image")
+    (:raise 'value	"lighten/darken image edges to create a 3-D effect")
+    (:random-threshold 'low,high	"random threshold the image")
+    (:region 'geometry	"apply options to a portion of the image")
+    (:render nil 	"render vector graphics")
+    (:repage 'geometry	"size and location of an image canvas")
+    (:resample 'geometry	"change the resolution of an image")
+    (:resize 'geometry	"resize the image")
+    (:roll 'geometry	"roll an image vertically or horizontally")
+    (:rotate 'degrees	"apply Paeth rotation to the image")
+    (:sample 'geometry	"scale image with pixel sampling")
+    (:scale 'geometry	"scale the image")
+    (:segment 'values	"segment an image")
+    (:selective-blur 'geometry	"selectively blur pixels within a contrast threshold")
+    (:sepia-tone 'threshold	"simulate a sepia-toned photo")
+    (:set property value	"set an image property")
+    (:shade 'degrees	"shade the image using a distant light source")
+    (:shadow 'geometry	"simulate an image shadow")
+    (:sharpen 'geometry	"sharpen the image")
+    (:shave 'geometry	"shave pixels from the image edges")
+    (:shear 'geometry	"slide one edge of the image along the X or Y axis")
+    (:sigmoidal-contrast 'geometry	"lightness rescaling using sigmoidal contrast enhancement")
+    (:sketch 'geometry	"simulate a pencil sketch")
+    (:solarize 'threshold	"negate all pixels above the threshold level")
+    (:splice 'geometry	"splice the background color into the image")
+    (:spread 'amount	"displace image pixels by a random amount")
+    (:strip nil 	"strip image of all profiles and comments")
+    (:swirl 'degrees	"swirl image pixels about the center")
+    (:threshold 'value	"threshold the image")
+    (:thumbnail 'geometry	"create a thumbnail of the image")
+    (:tile 'filename	"tile image when filling a graphic primitive")
+    (:tint 'value	"tint the image with the fill color")
+    (:transform nil 	"affine transform image")
+    (:transparent 'color	"make this color transparent within the image")
+    (:transpose nil 	"flip image vertically and rotate 90 degrees")
+    (:transverse nil 	"flop image horizontally and rotate 270 degrees")
+    (:trim nil 	"trim image edges")
+    (:type 'type	"image type")
+    (:unique-colors nil 	"discard all but one of any pixel color")
+    (:unsharp 'geometry	"sharpen the image")
+    (:vignette 'geometry	"soften the edges of the image in vignette style")
+    (:wave 'geometry	"alter an image along a sine wave")
+    (:white-threshold 'value	"force all pixels above the threshold into white")
+
+    ;; Image Sequence Operators:
+    (:affinity 'filename	"transform image colors to match this set of colors")
+    (:append nil 	"append an image sequence top to bottom (use +append for left to right)")
+    (:clut nil 	"apply a color lookup table to the image")
+    (:coalesce nil 	"merge a sequence of images")
+    (:combine nil 	"combine a sequence of images")
+    (:composite nil 	"composite image")
+    (:crop 'geometry	"cut out a rectangular region of the image")
+    (:deconstruct nil 	"break down an image sequence into constituent parts")
+    (:evaluate-sequence 'operator	"evaluate an arithmetic, relational, or logical expression")
+    (:flatten nil 	"flatten a sequence of images")
+    (:fx 'expression	"apply mathematical expression to an image channel(s)")
+    (:hald-clut nil 	"apply a Hald color lookup table to the image")
+    (:morph 'value	"morph an image sequence")
+    (:mosaic nil 	"create a mosaic from an image sequence")
+    (:process 'arguments	"process the image with a custom image filter")
+    (:separate nil 	"separate an image channel into a grayscale image")
+    (:smush 'geometry	"smush an image sequence together")
+    (:write 'filename	"write images to this file")
+
+    ;; Image Stack Operators:
+    (:clone 'indexes	"clone an image")
+    (:delete 'indexes	"delete the image from the image sequence")
+    (:duplicate 'count,indexes	"duplicate an image one or more times")
+    (:insert 'index	"insert last image into the image sequence")
+    (:swap 'indexes	"swap two images in the image sequence")
+
+    ;; Miscellaneous Options:
+    (:debug 'events	"display copious debugging information")
+    (:help nil 	"print program options")
+    (:log 'format	"format of debugging information")
+    (:list 'type	"print a list of supported option arguments")
+    (:version nil 	"print version information")
+    ))
+                                       
+
+\f
+;;; Transform UI
+
+(defcustom image-scale-step 1.1
+  "Each positive or negative step scales the current image by
+this amount."
+  :type 'number
+  :group 'image)
+
+;;;###autoload
+(defun image-scale-adjust (&optional inc)
+  "Adjust the scale of the image by INC.
+
+INC may be passed as a numeric prefix argument.
+
+The actual adjustment made depends on the final component of the
+key-binding used to invoke the command, with all modifiers removed:
+
+   +, =   Increase the size of the image by one step
+   -      Decrease the size of the image by one step
+   0      Reset to the original image size
+
+When adjusting with `+' or `-', continue to read input events and
+further adjust the face height as long as the input event read
+\(with all modifiers removed) is `+' or `-'.
+
+Each step scales the image by the value of `image-scale-step' (a
+negative number of steps decreases the height by the same
+amount).  As a special case, an argument of 0 will remove any
+scaling currently active.
+
+This command is a special-purpose wrapper around the
+`image-scale-increase'."
+  ;; fixme: doesn't work with universal arg
+  (interactive "p")
+  (let ((ev last-command-event)
+        (echo-keystrokes nil))
+    (let* ((base (event-basic-type ev))
+           (step
+            (pcase base
+              ((or ?+ ?=) inc)
+              (?- (- inc))
+              (?0 0)
+              (t inc))))
+      (image-scale-increase step)
+      (message "Use +,-,0 for further adjustment")
+      (set-temporary-overlay-map
+       (let ((map (make-sparse-keymap)))
+         (dolist (mods '(() (control)))
+           (dolist (key '(?- ?+ ?= ?0)) ;; = is often unshifted +.
+             (define-key map (vector (append mods (list key)))
+               `(lambda () (interactive) (image-scale-adjust (abs ,inc))))))
+         map)))))
+
+;;;###autoload
+(defun image-scale-increase (&optional inc image)
+  "Increase the size of the IMAGE by INC steps.
+
+IMAGE defaults to the image at point found by `get-image'.
+
+Each step scales up the size of the IMAGE the value of
+`text-scale-mode-step' (a negative number of steps decreases the
+size by the same amount).  As a special case, an argument of 0
+will remove any scaling currently active.
+
+This command has no unless Emacs is compiled with
+ImageMagick support."
+  (interactive "p")
+  (unless image
+    (unless (setq image (get-image))
+      (error "No image at point")))
+  (if (/= inc 0)
+      (image-transform image :scale (* 100 (expt image-scale-step inc)))
+    (image--delete-properties image '(:width :height)))
+  (force-window-update (selected-window)))
+
+;;;###autoload
+(defun image-scale-decrease (&optional inc image)
+  "Decrease the size of the IMAGE by INC steps.
+
+IMAGE defaults to the image at point found by `get-image'.
+
+Each step scales down the size of the IMAGE the value of
+`text-scale-mode-step' (a negative number of steps increases the
+size by the same amount).  As a special case, an argument of 0
+will remove any scaling currently active.
+
+This command has no effect unless Emacs is compiled with
+ImageMagick support."
+  (interactive "p")
+  (image-scale-increase (- inc) image))
+
+;;;###autoload
+(defun image-fit-to-window-height (&optional image)
+  "Fit IMAGE to the height of the current window.
+If not provided, IMAGE is the image at point.
+
+This command has no effect unless Emacs is compiled with
+ImageMagick support."
+  (interactive)
+  (image-transform-interactive image :resize 'fit-height))
+
+;;;###autoload
+(defun image-fit-to-window-width (&optional image)
+  "Fit IMAGE to the width of the current window.
+If not provided, IMAGE is the image at point.
+
+This command has no effect unless Emacs is compiled with
+ImageMagick support."
+  (interactive)
+  (image-transform-interactive image :resize 'fit-width))
+
+;;;###autoload
+(defun image-fit-to-window (&optional image)
+  "Maximally fit IMAGE into current window.
+If not provided, IMAGE is the image at point.
+
+This command has no effect unless Emacs is compiled with
+ImageMagick support."
+  (interactive)
+  (image-transform-interactive image :resize 'fit))
+
+;;;###autoload
+(defun image-stretch-to-window (&optional image)
+  "Stretch IMAGE into current window.
+If not provided, IMAGE is the image at point.
+
+This command has no effect unless Emacs is compiled with
+ImageMagick support."
+  (interactive)
+  (image-transform-interactive image :resize 'fit-stretch))
+
+;;;###autoload
+(defun image-rotate (rotation &optional image)
+  "Prompt for an angle ROTATION, and rotate the image by that amount.
+ROTATION should be in degrees.
+
+This command has no effect unless Emacs is compiled with
+ImageMagick support."
+  (interactive "nRotation angle (in degrees): ")
+  (image-transform-interactive image :rotate rotation))
+
+;;;###autoload
+(defun image-rotate-right (&optional image)
+  "Rotate the image clockwise by 90 degrees.
+
+This command has no effect unless Emacs is compiled with
+ImageMagick support."
+  (interactive)
+  (image-transform-interactive image :rotate 90))
+
+;;;###autoload
+(defun image-rotate-left (&optional image)
+  "Rotate the image counter-clockwise by 90 degrees.
+
+This command has no effect unless Emacs is compiled with
+ImageMagick support."
+  (interactive)
+  (image-transform-interactive image :rotate -90))
+
+;;;###autoload
+(defun image-change-background (&optional background image)
+  "Set background of the IMAGE to BACKGROUND.
+For this to work, image must have a transparent background.
+If not provided, IMAGE is the image at point.
+
+This command has no effect unless Emacs is compiled with
+ImageMagick support."
+  (interactive)
+  (let ((bg (or background (read-color "Background: " t))))
+    (unless image
+      (unless (setq image (get-image))
+        (error "No image at point")))
+    (image-transform-interactive image :background bg)))
+
+(defun image--add-transform-keys (map &optional mod)
+  "Add manipulation keys to MAP.
+MOD is a vector of modifiers, like [control] or [control meta]."
+  (define-key map (vector `(,@mod ?+)) 'image-scale-adjust)
+  (define-key map (vector `(,@mod ?-)) 'image-scale-adjust)
+  (define-key map (vector `(,@mod ?=)) 'image-scale-adjust)
+  (define-key map (vector `(,@mod ?0)) 'image-scale-adjust)
+  (define-key map (vector `(,@mod ?o)) 'image-rotate)
+  (define-key map (vector `(,@mod ?\])) 'image-rotate-right)
+  (define-key map (vector `(,@mod ?\[)) 'image-rotate-left)
+  (define-key map (vector `(,@mod ?r) `(,@mod ?f)) 'image-fit-to-window)
+  (define-key map (vector `(,@mod ?r) `(,@mod ?h)) 'image-fit-to-window-height)
+  (define-key map (vector `(,@mod ?r) `(,@mod ?w)) 'image-fit-to-window-width)
+  (define-key map (vector `(,@mod ?r) `(,@mod ?s)) 'image-stretch-to-window)
+  (define-key map (vector `(,@mod shift ?b)) 'image-change-background)
+  map)
+
+;;;###autoload
+(defvar image-transform-map
+  (let ((map (make-sparse-keymap)))
+    (image--add-transform-keys map))
+  "Image manipulation keymap.
+Usually used as keymap text property for images. See also
+`image--add-transform-keys' for how to add manipulation keys
+to a map with modifiers.
+
+\\{image-transform-map}")
+
+
+(provide 'image-transform)
diff --git a/lisp/image.el b/lisp/image.el
index 804dc3a..63bebdf 100644
--- a/lisp/image.el
+++ b/lisp/image.el
@@ -425,7 +425,7 @@ means display it in the right marginal area."
 
 
 ;;;###autoload
-(defun insert-image (image &optional string area slice)
+(defun insert-image (image &optional string area slice map)
   "Insert IMAGE into current buffer at point.
 IMAGE is displayed by inserting STRING into the current buffer
 with a `display' property whose value is the image.  STRING
@@ -438,7 +438,10 @@ SLICE specifies slice of IMAGE to insert.  SLICE nil or omitted
 means insert whole image.  SLICE is a list (X Y WIDTH HEIGHT)
 specifying the X and Y positions and WIDTH and HEIGHT of image area
 to insert.  A float value 0.0 - 1.0 means relative to the width or
-height of the image; integer values are taken as pixel values."
+height of the image; integer values are taken as pixel values.
+If MAP is provided, it must be a keymap what will be used as
+text property keymap. A special value of t means to use
+`image-transform-map'"
   ;; Use a space as least likely to cause trouble when it's a hidden
   ;; character in the buffer.
   (unless string (setq string " "))
@@ -455,12 +458,16 @@ height of the image; integer values are taken as pixel values."
     ;; cut-and-paste.  (Yanking killed image text next to another copy
     ;; of it loses anyway.)
     (setq image (cons 'image (cdr image))))
+  (when (eq map t)
+    (setq map image-transform-map))
   (let ((start (point)))
     (insert string)
     (add-text-properties start (point)
 			 `(display ,(if slice
 					(list (cons 'slice slice) image)
-				      image) rear-nonsticky (display)))))
+				      image)
+                                   rear-nonsticky (display)
+                                   keymap ,map))))
 
 
 ;;;###autoload

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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-18 22:27                 ` Vitalie Spinu
@ 2013-07-19  9:22                   ` Stefan Monnier
  2013-07-20  7:25                     ` Vitalie Spinu
  0 siblings, 1 reply; 55+ messages in thread
From: Stefan Monnier @ 2013-07-19  9:22 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: Lars Magne Ingebrigtsen, joakim, emacs-devel

> On the other hand, the user might requests several transforms in a
> sequence, so you will have to store to the file to pass it further to
> 'convert' anyhow. It might also better work on remotes as the file is
> stored on remote machine.

Maybe the API should be made in two parts: one part to build a transform
and then another to apply it to an image, this way you can do "several
transforms in sequence" with a single call to "convert".


        Stefan



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

* Re: image-transform.el and image-mode.el rewrite
  2013-07-18 23:22               ` image-transform.el and image-mode.el rewrite Vitalie Spinu
@ 2013-07-19 11:52                 ` Wolfgang Jenkner
  2013-07-19 12:21                   ` Wolfgang Jenkner
  2013-07-22 20:37                 ` Glenn Morris
  1 sibling, 1 reply; 55+ messages in thread
From: Wolfgang Jenkner @ 2013-07-19 11:52 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: Stefan Monnier, joakim, emacs-devel

On Fri, Jul 19 2013, Vitalie Spinu wrote:

> +;; these are 3, virtuly unchenged, objects from old image-mode.el
> +;; fixme: see the author

Hi!

> +           ;; on GNU Emacs 24.3.50.4 (i686-pc-linux-gnu, X toolkit, Xaw
> +           ;; scroll bars) of 2013-07-16, image width is slightly
> +           ;; truncated, ~6px, so the below mambo math for .5px
> +           ;; adjustment is pretty useless.

The rotation stuff is written in such a a way that fit-width
(resp. fit-height) produces a rotated image whose bounding-box, with the
roundings applied by ImageMagick, viz.

> +;;      geometry.x = (ssize_t) floor(min.x-0.5);
> +;;      geometry.y = (ssize_t) floor(min.y-0.5);
> +;;      geometry.width=(size_t) ceil(max.x-geometry.x+0.5);
> +;;      geometry.height=(size_t) ceil(max.y-geometry.y+0.5);

has _exactly_ the desired pixel width (resp. height), and there's an
assertion in image-mode which tests this.

So, except for this

> +(defvar image--right-angle-fudge 0.0001
> +  "Snap distance to a multiple of a right angle.
> +There's no deep theory behind the default value, it should just
> +be somewhat larger than ImageMagick's MagickEpsilon.")

everything is exact math without fudge factors.

In particular, thing's won't be quite correct if you do

> +              ;; VS[16-07-2013]: returning (w . h) is unnecessary, it
> +              ;; distorts the image and processing becomes very slow


Wolfgang



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

* Re: image-transform.el and image-mode.el rewrite
  2013-07-19 11:52                 ` Wolfgang Jenkner
@ 2013-07-19 12:21                   ` Wolfgang Jenkner
  2013-07-20  7:18                     ` Vitalie Spinu
  0 siblings, 1 reply; 55+ messages in thread
From: Wolfgang Jenkner @ 2013-07-19 12:21 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: Stefan Monnier, joakim, emacs-devel

On Fri, Jul 19 2013, Wolfgang Jenkner wrote:

>> +           ;; on GNU Emacs 24.3.50.4 (i686-pc-linux-gnu, X toolkit, Xaw
>> +           ;; scroll bars) of 2013-07-16, image width is slightly
>> +           ;; truncated, ~6px,

Perhaps, the (apparent) truncation you see is the result of not using
a right fringe, in which case there's now always some space on the right
of the window used for continuation or truncation glyphs, even on
graphical displays, even in image-mode, see bug#11832.

Wolfgang



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

* Re: image-transform.el and image-mode.el rewrite
  2013-07-19 12:21                   ` Wolfgang Jenkner
@ 2013-07-20  7:18                     ` Vitalie Spinu
  0 siblings, 0 replies; 55+ messages in thread
From: Vitalie Spinu @ 2013-07-20  7:18 UTC (permalink / raw)
  To: Vitalie Spinu, Stefan Monnier, joakim@verona.se,
	emacs-devel@gnu.org

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

Yes, you are right. I figured that out after I put that comment there.
Image width and window width  are precisely the same,so the truncation
happens for a different reason.

Thanks,
     Vitalie.

On Friday, 19 July 2013, Wolfgang Jenkner wrote:

> On Fri, Jul 19 2013, Wolfgang Jenkner wrote:
>
> >> +           ;; on GNU Emacs 24.3.50.4 (i686-pc-linux-gnu, X toolkit, Xaw
> >> +           ;; scroll bars) of 2013-07-16, image width is slightly
> >> +           ;; truncated, ~6px,
>
> Perhaps, the (apparent) truncation you see is the result of not using
> a right fringe, in which case there's now always some space on the right
> of the window used for continuation or truncation glyphs, even on
> graphical displays, even in image-mode, see bug#11832.
>
> Wolfgang
>

[-- Attachment #2: Type: text/html, Size: 1009 bytes --]

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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-19  9:22                   ` Stefan Monnier
@ 2013-07-20  7:25                     ` Vitalie Spinu
  0 siblings, 0 replies; 55+ messages in thread
From: Vitalie Spinu @ 2013-07-20  7:25 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: Lars Magne Ingebrigtsen, joakim@verona.se, emacs-devel@gnu.org

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

Indeed, this is my plan right now. I will keep track of the transforms and
stack them in the final call to convert. This way temp files could be
avoided with no quality loss, as the transforms are always applied to the
original file.

Vitalie.

On Friday, 19 July 2013, Stefan Monnier wrote:

> > On the other hand, the user might requests several transforms in a
> > sequence, so you will have to store to the file to pass it further to
> > 'convert' anyhow. It might also better work on remotes as the file is
> > stored on remote machine.
>
> Maybe the API should be made in two parts: one part to build a transform
> and then another to apply it to an image, this way you can do "several
> transforms in sequence" with a single call to "convert".
>
>
>         Stefan
>

[-- Attachment #2: Type: text/html, Size: 1015 bytes --]

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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-18  8:47               ` Lars Magne Ingebrigtsen
  2013-07-18 22:27                 ` Vitalie Spinu
@ 2013-07-22 20:17                 ` Vitalie Spinu
  2013-07-22 20:31                   ` Lars Magne Ingebrigtsen
  1 sibling, 1 reply; 55+ messages in thread
From: Vitalie Spinu @ 2013-07-22 20:17 UTC (permalink / raw)
  To: Lars Magne Ingebrigtsen; +Cc: Stefan Monnier, joakim, emacs-devel

 >> Lars Magne Ingebrigtsen <larsi@gnus.org>
 >> on Thu, 18 Jul 2013 10:47:15 +0200 wrote:

 > Vitalie Spinu <spinuvit@gmail.com> writes:
 >> For `imagemagick', `image-transform' will try to use internal
 >> Emacs ImageMagick support. For `convert' use external ImageMagick
 >> \"convert\" utility to produce a transformed temporary image
 >> file.

 > If you want to avoid temporary file management, you can "convert" with
 > output to a buffer, and then just call `create-image' on the buffer
 > contents.

 > It'll be slower, but I haven't measured how much slower. 

Redirecting output to a buffer is very fast, as fast as using temp
files. For a 3.5MB image various transforms give no difference in speed.

But I wonder what is the correct way of doing it.

   (call-process "convert"
                  nil (list (get-buffer-create "tttt")) nil
                  "temp.jpg" "-size 500x1000" "-")

also puts silly warnings into the same buffer:

Fontconfig warning: "/etc/fonts/conf.d/50-user.conf", line 9: reading configurations from ~/.fonts.conf is deprecated.
Fontconfig warning: "/etc/fonts/conf.d/50-user.conf", line 9: reading configurations from ~/.fonts.conf is deprecated.
 
How do I get rid of those?

    Vitalie



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-22 20:17                 ` Vitalie Spinu
@ 2013-07-22 20:31                   ` Lars Magne Ingebrigtsen
  2013-07-23  8:31                     ` Vitalie Spinu
  0 siblings, 1 reply; 55+ messages in thread
From: Lars Magne Ingebrigtsen @ 2013-07-22 20:31 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: Stefan Monnier, joakim, emacs-devel

Vitalie Spinu <spinuvit@gmail.com> writes:

> But I wonder what is the correct way of doing it.
>
>    (call-process "convert"
>                   nil (list (get-buffer-create "tttt")) nil
>                   "temp.jpg" "-size 500x1000" "-")
>
> also puts silly warnings into the same buffer:
>
> Fontconfig warning: "/etc/fonts/conf.d/50-user.conf", line 9: reading configurations from ~/.fonts.conf is deprecated.

Presumably (or hopefully :-) those are from STDERR, so you need to
redirect that:

(call-process PROGRAM &optional INFILE DESTINATION DISPLAY &rest ARGS)

[...]

DESTINATION can also have the form (REAL-BUFFER STDERR-FILE); in that case,
REAL-BUFFER says what to do with standard output, as above,
while STDERR-FILE says what to do with standard error in the child.
STDERR-FILE may be nil (discard standard error output),
t (mix it with ordinary output), or a file name string.

So that should be

 (call-process "convert"
                nil (list (get-buffer-create "tttt") nil) nil
                "temp.jpg" "-size 500x1000" "-")

Note the extra nil in DESTINATION.                

-- 
(domestic pets only, the antidote for overdose, milk.)
  bloggy blog http://lars.ingebrigtsen.no/



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

* Re: image-transform.el and image-mode.el rewrite
  2013-07-18 23:22               ` image-transform.el and image-mode.el rewrite Vitalie Spinu
  2013-07-19 11:52                 ` Wolfgang Jenkner
@ 2013-07-22 20:37                 ` Glenn Morris
  2013-07-22 21:05                   ` Vitalie Spinu
  2013-10-08 18:08                   ` Glenn Morris
  1 sibling, 2 replies; 55+ messages in thread
From: Glenn Morris @ 2013-07-22 20:37 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: Stefan Monnier, joakim, emacs-devel


Thanks for this. The diff is hard to read owing to lots of unnecessary
whitespace changes (looks like you untabified everything?).



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

* Re: image-transform.el and image-mode.el rewrite
  2013-07-22 20:37                 ` Glenn Morris
@ 2013-07-22 21:05                   ` Vitalie Spinu
  2013-10-08 18:08                   ` Glenn Morris
  1 sibling, 0 replies; 55+ messages in thread
From: Vitalie Spinu @ 2013-07-22 21:05 UTC (permalink / raw)
  To: Glenn Morris; +Cc: Stefan Monnier, joakim, emacs-devel

 >> Glenn Morris <rgm@gnu.org>
 >> on Mon, 22 Jul 2013 16:37:53 -0400 wrote:

 > Thanks for this. The diff is hard to read owing to lots of unnecessary
 > whitespace changes (looks like you untabified everything?).

Hm, indeed. Sorry for that. It happened during re-indentation which
replaces tabs for me. I will take care of them next time.

Anyways the diff is there to try the new changes and is not intended for
heavy reading as yet. I am still figuring out the best way to organize
the API, so it is still pretty raw as yet.

    Vitalie









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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-22 20:31                   ` Lars Magne Ingebrigtsen
@ 2013-07-23  8:31                     ` Vitalie Spinu
  0 siblings, 0 replies; 55+ messages in thread
From: Vitalie Spinu @ 2013-07-23  8:31 UTC (permalink / raw)
  To: Lars Magne Ingebrigtsen; +Cc: emacs-devel


I cannot reproduce these warnings anymore. They suddenly
disappeared. But I am almost sure they are stderr. Similar warning
appears when emacs starts, and emacs 2> error.log gets rid of them. So
your suggestion should work.

Thanks, 

    Vitalie


 >> Lars Magne Ingebrigtsen <larsi@gnus.org>
 >> on Mon, 22 Jul 2013 22:31:15 +0200 wrote:

 > Vitalie Spinu <spinuvit@gmail.com> writes:
 >> But I wonder what is the correct way of doing it.
 >> 
 >> (call-process "convert"
 >> nil (list (get-buffer-create "tttt")) nil
 >> "temp.jpg" "-size 500x1000" "-")
 >> 
 >> also puts silly warnings into the same buffer:
 >> 
 >> Fontconfig warning: "/etc/fonts/conf.d/50-user.conf", line 9: reading configurations from ~/.fonts.conf is deprecated.

 > Presumably (or hopefully :-) those are from STDERR, so you need to
 > redirect that:

 > (call-process PROGRAM &optional INFILE DESTINATION DISPLAY &rest ARGS)

 > [...]

 > DESTINATION can also have the form (REAL-BUFFER STDERR-FILE); in that case,
 > REAL-BUFFER says what to do with standard output, as above,
 > while STDERR-FILE says what to do with standard error in the child.
 > STDERR-FILE may be nil (discard standard error output),
 > t (mix it with ordinary output), or a file name string.

 > So that should be

 >  (call-process "convert"
 >                 nil (list (get-buffer-create "tttt") nil) nil
 >                 "temp.jpg" "-size 500x1000" "-")

 > Note the extra nil in DESTINATION.                



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

* Re: imagemagic in image-mode and image-dired-thumbnail-mode?
  2013-07-15 10:39                   ` Óscar Fuentes
@ 2013-08-02 15:32                     ` Steinar Bang
  0 siblings, 0 replies; 55+ messages in thread
From: Steinar Bang @ 2013-08-02 15:32 UTC (permalink / raw)
  To: emacs-devel

>>>>> Óscar Fuentes <ofv@wanadoo.es>:
> "Stephen J. Turnbull" <stephen@xemacs.org> writes:
>> Footnotes: 
>> [1]  Among the more-or-less standalone libraries.  I imagine the ones
>> used by KDE and GNOME are pretty stable but bring in huge dependencies.

> The official KDE PDF viewer (Okular) uses libpoppler, which comes from
> xpdf. In my not extensive experience, it works well. Its dependency set
> is small (freetype and image libraries, mostly.)

I use evince, which also uses libpoppler, on both debian and Windows.

Evince behaves much better than acrobat reader on either platfrom: it is
faster, it uses less computer resources, it is stabler, and it
successfully prints to my 9 year old, PostScript HP Color LaserJet.

It's licensed as either GPLv2 or GPLv3.

 http://en.wikipedia.org/wiki/Poppler_(software)




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

* Re: image-transform.el and image-mode.el rewrite
  2013-07-22 20:37                 ` Glenn Morris
  2013-07-22 21:05                   ` Vitalie Spinu
@ 2013-10-08 18:08                   ` Glenn Morris
  2013-10-08 23:43                     ` Vitalie Spinu
  1 sibling, 1 reply; 55+ messages in thread
From: Glenn Morris @ 2013-10-08 18:08 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: emacs-devel


Hi,

This was looking pretty promising. What's the current status?

Vitalie Spinu wrote:

> Anyways the diff is there to try the new changes and is not intended for
> heavy reading as yet. I am still figuring out the best way to organize
> the API, so it is still pretty raw as yet.



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

* Re: image-transform.el and image-mode.el rewrite
  2013-10-08 18:08                   ` Glenn Morris
@ 2013-10-08 23:43                     ` Vitalie Spinu
  2013-10-09  0:02                       ` Michael Heerdegen
  0 siblings, 1 reply; 55+ messages in thread
From: Vitalie Spinu @ 2013-10-08 23:43 UTC (permalink / raw)
  To: Glenn Morris; +Cc: emacs-devel


It's quite frustrating. I almost finished it back then. The only part
remaining was the cropping UI (I also wanted to adjust doc-mode to use
image-transform api, but it can wait).

It was a very hectic 2 months for me (job and country change + a lot of
travel). I will be very busy for another 1.5 weeks, but then I can use a
weekend to finish it up. 


  Vitalie





 >>> Glenn Morris on Tue, 08 Oct 2013 14:08:22 -0400 wrote:

 > Hi,

 > This was looking pretty promising. What's the current status?

 > Vitalie Spinu wrote:

 >> Anyways the diff is there to try the new changes and is not intended for
 >> heavy reading as yet. I am still figuring out the best way to organize
 >> the API, so it is still pretty raw as yet.



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

* Re: image-transform.el and image-mode.el rewrite
  2013-10-08 23:43                     ` Vitalie Spinu
@ 2013-10-09  0:02                       ` Michael Heerdegen
  2014-12-15  9:33                         ` Vitalie Spinu
  0 siblings, 1 reply; 55+ messages in thread
From: Michael Heerdegen @ 2013-10-09  0:02 UTC (permalink / raw)
  To: emacs-devel

Vitalie Spinu <spinuvit@gmail.com> writes:

> It's quite frustrating. I almost finished it back then. The only part
> remaining was the cropping UI (I also wanted to adjust doc-mode to use
> image-transform api, but it can wait).
>
> It was a very hectic 2 months for me (job and country change + a lot of
> travel). I will be very busy for another 1.5 weeks, but then I can use a
> weekend to finish it up. 

That would be really really cool.  image-mode is not very useful
currently.


Regards,

Michael.




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

* Re: image-transform.el and image-mode.el rewrite
  2013-10-09  0:02                       ` Michael Heerdegen
@ 2014-12-15  9:33                         ` Vitalie Spinu
  2014-12-18 14:17                           ` Michael Heerdegen
  2014-12-18 15:15                           ` Stefan Monnier
  0 siblings, 2 replies; 55+ messages in thread
From: Vitalie Spinu @ 2014-12-15  9:33 UTC (permalink / raw)
  To: Michael Heerdegen, Glenn Morris; +Cc: emacs-devel

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


Hi,

I have finally got down to this.

The image-transform.el and refactored image-mode.el:

  https://github.com/vspinu/image-transform

Diff:

  https://github.com/vspinu/image-transform/compare/emacs...master

Tests and examples:

  https://github.com/vspinu/image-transform/blob/master/tests.el


The documentation is in `image-transform` and `image-transform-backends`
docstrings.

The biggest change on image-mode.el side is the introduction of the
local `image-manipulation-map` that includes all commands that are also
meaningful outside of `image-mode.el`.

I changed functions that are meaningful outside of `image-mode` not to
include "-mode-" infix and to operate on &optional image instead of
current image. Once the patch is agreed upon, I would like to isolate
all these functions into a separate `image-manip.el`. The
`image-mode.el` is better kept for image-mode, image-minor-mode and
multi-image-mode (still to be written).

At this stage the stuff is ready for a review as I have only minor
things to fix. I will be traveling till 18th and will resume once I am
back. Would be really great if interested people could have a quick look
till then.

Thanks,

  Vitalie



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-diff, Size: 45725 bytes --]

	Modified   image-mode.el
diff --git a/image-mode.el b/image-mode.el
index b94162d..630b2e0 100644
--- a/image-mode.el
+++ b/image-mode.el
@@ -39,9 +39,50 @@
 ;;; Code:
 
 (require 'image)
-(eval-when-compile (require 'cl-lib))
+(require 'image-transform)
+;; fixme: VS: why did I remove this?
+;; (eval-when-compile (require 'cl-lib))
+
+(defgroup image-mode ()
+  "Support for visiting image files."
+  :group 'multimedia)
+
+(defcustom image-mode-auto-resize 'fit-if-large
+  "Image auto-resize default.
+
+If null, don't auto resize.  If set to a symbol, must take one of
+the following values:
+
+   *`fit' - maximally scale IMAGE to fit into window
+   *`fit-if-large' - like `fit', but only when image is larger than window
+   *`fit-height' - fit the image to window height
+   *`fit-width' - fit the image to window width
+   *`fit-stretch' - stretch the image to fit to both height and
+    width of the window
+
+A number is interpreted as width in pixels.  Cons cell, string and
+list values are as the VALUE argument of `image-transform-spec:geometry'."
+  :type '(choice
+	  (const :tag "No Resize" nil)
+	  (const :tag "Fit" fit)
+	  (const :tag "Fit if Large" fit-if-large)
+	  (const :tag "Fit Height" fit-height)
+	  (const :tag "Fit Width" fit-width)
+	  (const :tag "Fit Stretch" fit-stretch)
+	  (number :tag "Width")
+	  (string)
+	  (cons number number)
+	  (list number number string))
+  :group 'image-mode
+  :version "25.1")
+
+(defcustom image-mode-show-cursor t
+  "Non-nil if the cursor should be shown in `image-mode'."
+  :group 'image-mode
+  :type 'boolean)
 
-;;; Image mode window-info management.
+\f
+;;; Window Info Management.
 
 (defvar-local image-mode-winprops-alist t)
 
@@ -49,31 +90,13 @@
   "Special hook run when image data is requested in a new window.
 It is called with one argument, the initial WINPROPS.")
 
-;; FIXME this doesn't seem mature yet. Document in manual when it is.
-(defvar image-transform-resize nil
-  "The image resize operation.
-Its value should be one of the following:
- - nil, meaning no resizing.
- - `fit-height', meaning to fit the image to the window height.
- - `fit-width', meaning to fit the image to the window width.
- - A number, which is a scale factor (the default size is 1).")
-
-(defvar image-transform-scale 1.0
-  "The scale factor of the image being displayed.")
-
-(defvar image-transform-rotation 0.0
-  "Rotation angle for the image in the current Image mode buffer.")
-
-(defvar image-transform-right-angle-fudge 0.0001
-  "Snap distance to a multiple of a right angle.
-There's no deep theory behind the default value, it should just
-be somewhat larger than ImageMagick's MagickEpsilon.")
-
 (defun image-mode-winprops (&optional window cleanup)
   "Return winprops of WINDOW.
-A winprops object has the shape (WINDOW . ALIST).
-WINDOW defaults to `selected-window' if it displays the current buffer, and
-otherwise it defaults to t, used for times when the buffer is not displayed."
+A winprops object has the shape (WINDOW . ALIST).  WINDOW defaults
+to `selected-window' if it displays the current buffer, and
+otherwise it defaults to t, used for times when the buffer is not
+displayed.  When CLEANUP is non-nil, remove all winprops with
+deleted window."
   (cond ((null window)
          (setq window
                (if (eq (current-buffer) (window-buffer)) (selected-window) t)))
@@ -144,13 +167,45 @@ otherwise it defaults to t, used for times when the buffer is not displayed."
   (add-hook 'window-configuration-change-hook
  	    'image-mode-reapply-winprops nil t))
 
-;;; Image scrolling functions
-
-(defun image-get-display-property ()
-  (get-char-property (point-min) 'display
-                     ;; There might be different images for different displays.
-                     (if (eq (window-buffer) (current-buffer))
-                         (selected-window))))
+\f
+;;; Access Images at Point
+
+(defun image-get-display-property (&optional pos)
+  (setq pos (or pos (point)))
+  (or (get-char-property pos 'display
+			 ;; There might be different images for different displays.
+			 (if (eq (window-buffer) (current-buffer))
+			     (selected-window)))
+      ;; overlay before-string/after-string display property, like in put-image
+      (let ((OVS (overlays-at pos))
+	    ov disp)
+	(while (setq ov (pop OVS))
+	  (let ((bs (overlay-get ov 'before-string))
+		(as (overlay-get ov 'after-string)))
+	    ;; last one takes precedence
+	    (setq disp (or (and as (get-text-property 0 'display as))
+			   (and bs (get-text-property 0 'display bs))))))
+	disp)))
+
+(defun image-at-point (&optional pos)
+  "Return image at POS if there is one, or nil otherwise.
+Search text and overlays at POS for a 'display' property that
+holds an image.  POS defaults to point."
+  ;; fixme: check preceding point as well
+  (let* ((disp (image-get-display-property pos)))
+    (or (and (eq (car-safe disp) 'image)
+	     disp)
+	;; margin images
+	(and (eq (car-safe (cdr-safe disp)) 'image)
+	     (cdr disp)))))
+
+(defun image-get-transforms (&optional image)
+  "Return transformation chain of the IMAGE.
+IMAGE defaults to `image-at-point'."
+  (interactive)
+  (setq image (or image (image-at-point)))
+  (or (plist-get (cdr image) :transforms)
+      '(tr)))
 
 (declare-function image-size "image.c" (spec &optional pixels frame))
 
@@ -179,6 +234,10 @@ but not `slice', return the `image-size' of the specified image."
 	    (t
 	     (error "Invalid image specification: %s" spec))))))
 
+\f
+;;; Image Scrolling
+;; fixme: operate on images?
+
 (defun image-forward-hscroll (&optional n)
   "Scroll image in current window to the left by N character widths.
 Stop if the right edge of the image is reached."
@@ -305,21 +364,22 @@ stopping if the top or bottom edge of the image is reached."
     (image-set-window-hscroll (max 0 (- img-width win-width)))
     (image-set-window-vscroll (max 0 (- img-height win-height)))))
 
-;; Adjust frame and image size.
+\f
+;;; Adjust frame and image size.
 
-(defun image-mode-fit-frame (&optional frame toggle)
-  "Fit FRAME to the current image.
+(defun image-scale-frame-to-fit-image (&optional frame toggle image)
+  "Fit FRAME to the image.
 If FRAME is omitted or nil, it defaults to the selected frame.
 All other windows on the frame are deleted.
 
 If called interactively, or if TOGGLE is non-nil, toggle between
-fitting FRAME to the current image and restoring the size and
-window configuration prior to the last `image-mode-fit-frame'
-call."
+fitting FRAME to the IMAGE and restoring the size and window
+configuration prior to the last `image-scale-frame-to-fit-image'
+call.  IMAGE defaults to `image-at-point'."
   (interactive (list nil t))
   (let* ((buffer (current-buffer))
-         (display (image-get-display-property))
-         (size (image-display-size display))
+         (image (image-at-point))
+         (size (image-display-size image))
 	 (saved (frame-parameter frame 'image-mode-saved-params))
 	 (window-configuration (current-window-configuration frame))
 	 (width  (frame-width  frame))
@@ -352,34 +412,27 @@ call."
 				     (cons width height)
 				     window-configuration)))))))
 
-;;; Image Mode setup
+(define-obsolete-function-alias 'image-mode-fit-frame 'image-scale-frame-to-fit-image "25.1")
+
+\f
+;;; Image Mode
 
 (defvar-local image-type nil
   "The image type for the current Image mode buffer.")
 
-(defvar-local image-multi-frame nil
-  "Non-nil if image for the current Image mode buffer has multiple frames.")
-
 (defvar image-mode-previous-major-mode nil
   "Internal variable to keep the previous non-image major mode.")
 
 (defvar image-mode-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map special-mode-map)
-    (define-key map "\C-c\C-c" 'image-toggle-display)
+    (define-key map "\C-c\C-c" 'image-mode-toggle-display)
     (define-key map (kbd "SPC")       'image-scroll-up)
     (define-key map (kbd "S-SPC")     'image-scroll-down)
     (define-key map (kbd "DEL")       'image-scroll-down)
     (define-key map (kbd "RET")       'image-toggle-animation)
-    (define-key map "F" 'image-goto-frame)
-    (define-key map "f" 'image-next-frame)
-    (define-key map "b" 'image-previous-frame)
-    (define-key map "n" 'image-next-file)
-    (define-key map "p" 'image-previous-file)
-    (define-key map "a+" 'image-increase-speed)
-    (define-key map "a-" 'image-decrease-speed)
-    (define-key map "a0" 'image-reset-speed)
-    (define-key map "ar" 'image-reverse-speed)
+    (define-key map "n" 'image-mode-next-file)
+    (define-key map "p" 'image-mode-previous-file)
     (define-key map [remap forward-char] 'image-forward-hscroll)
     (define-key map [remap backward-char] 'image-backward-hscroll)
     (define-key map [remap right-char] 'image-forward-hscroll)
@@ -396,82 +449,22 @@ call."
     (define-key map [remap end-of-buffer] 'image-eob)
     (easy-menu-define image-mode-menu map "Menu for Image mode."
       '("Image"
-	["Show as Text" image-toggle-display :active t
+	["Show as Text" image-mode-toggle-display :active t
 	 :help "Show image as text"]
 	"--"
-	["Fit to Window Height" image-transform-fit-to-height
-	 :visible (eq image-type 'imagemagick)
-	 :help "Resize image to match the window height"]
-	["Fit to Window Width" image-transform-fit-to-width
-	 :visible (eq image-type 'imagemagick)
-	 :help "Resize image to match the window width"]
-	["Rotate Image..." image-transform-set-rotation
-	 :visible (eq image-type 'imagemagick)
-	 :help "Rotate the image"]
-	["Reset Transformations" image-transform-reset
-	 :visible (eq image-type 'imagemagick)
-	 :help "Reset all image transformations"]
-	"--"
-	["Show Thumbnails"
-	 (lambda ()
-	   (interactive)
-	   (image-dired default-directory))
-	 :active default-directory
+	["Show Thumbnails" image-mode-show-thumbnails :active default-directory
 	 :help "Show thumbnails for all images in this directory"]
-	["Next Image" image-next-file :active buffer-file-name
+	["Next Image" image-mode-next-file :active buffer-file-name
          :help "Move to next image in this directory"]
-	["Previous Image" image-previous-file :active buffer-file-name
+	["Previous Image" image-mode-previous-file :active buffer-file-name
          :help "Move to previous image in this directory"]
-	"--"
-	["Fit Frame to Image" image-mode-fit-frame :active t
-	 :help "Resize frame to match image"]
-	"--"
-	["Animate Image" image-toggle-animation :style toggle
-	 :selected (let ((image (image-get-display-property)))
-		     (and image (image-animate-timer image)))
-	 :active image-multi-frame
-         :help "Toggle image animation"]
-	["Loop Animation"
-	 (lambda () (interactive)
-	   (setq image-animate-loop (not image-animate-loop))
-	   ;; FIXME this is a hacky way to make it affect a currently
-	   ;; animating image.
-	   (when (let ((image (image-get-display-property)))
-		   (and image (image-animate-timer image)))
-	     (image-toggle-animation)
-	     (image-toggle-animation)))
-	 :style toggle :selected image-animate-loop
-	 :active image-multi-frame
-	 :help "Animate images once, or forever?"]
-	["Reverse Animation" image-reverse-speed
-	 :style toggle :selected (let ((image (image-get-display-property)))
-				   (and image (<
-					       (image-animate-get-speed image)
-					       0)))
-	 :active image-multi-frame
-	 :help "Reverse direction of this image's animation?"]
-	["Speed Up Animation" image-increase-speed
-	 :active image-multi-frame
-	 :help "Speed up this image's animation"]
-	["Slow Down Animation" image-decrease-speed
-	 :active image-multi-frame
-	 :help "Slow down this image's animation"]
-	["Reset Animation Speed" image-reset-speed
-	 :active image-multi-frame
-	 :help "Reset the speed of this image's animation"]
-	["Next Frame" image-next-frame :active image-multi-frame
-	 :help "Show the next frame of this image"]
-	["Previous Frame" image-previous-frame :active image-multi-frame
-	 :help "Show the previous frame of this image"]
-	["Goto Frame..." image-goto-frame :active image-multi-frame
-	 :help "Show a specific frame of this image"]
 	))
     map)
   "Mode keymap for `image-mode'.")
 
 (defvar image-minor-mode-map
   (let ((map (make-sparse-keymap)))
-    (define-key map "\C-c\C-c" 'image-toggle-display)
+    (define-key map "\C-c\C-c" 'image-mode-toggle-display)
     map)
   "Mode keymap for `image-minor-mode'.")
 
@@ -482,7 +475,7 @@ call."
 ;;;###autoload
 (defun image-mode ()
   "Major mode for image files.
-You can use \\<image-mode-map>\\[image-toggle-display]
+You can use \\<image-mode-map>\\[image-mode-toggle-display]
 to toggle between display as an image and display as text.
 
 Key bindings:
@@ -498,7 +491,7 @@ Key bindings:
 
 	(if (not (image-get-display-property))
 	    (progn
-	      (image-toggle-display-image)
+	      (image-mode-toggle-display-image)
 	      ;; If attempt to display the image fails.
 	      (if (not (image-get-display-property))
 		  (error "Invalid image")))
@@ -512,24 +505,25 @@ Key bindings:
 
 	;; Use our own bookmarking function for images.
 	(setq-local bookmark-make-record-function
-                    #'image-bookmark-make-record)
+		    #'image-bookmark-make-record)
 
 	;; Keep track of [vh]scroll when switching buffers
 	(image-mode-setup-winprops)
 
-	(add-hook 'change-major-mode-hook 'image-toggle-display-text nil t)
-	(add-hook 'after-revert-hook 'image-after-revert-hook nil t)
+	(setq-local revert-buffer-function 'image-mode-revert-buffer)
+
+	(add-hook 'change-major-mode-hook 'image-mode-toggle-display-text nil t)
+	(add-hook 'after-revert-hook 'image-mode-after-revert nil t)
 	(run-mode-hooks 'image-mode-hook)
 	(let ((image (image-get-display-property))
 	      (msg1 (substitute-command-keys
-		     "Type \\[image-toggle-display] to view the image as "))
+		     "Type \\[image-mode-toggle-display] to view the image as "))
 	      animated)
 	  (cond
 	   ((null image)
 	    (message "%s" (concat msg1 "an image.")))
 	   ((setq animated (image-multi-frame-p image))
-	    (setq image-multi-frame t
-		  mode-line-process
+	    (setq mode-line-process
 		  `(:eval
 		    (concat " "
 			    (propertize
@@ -559,6 +553,12 @@ mouse-3: Previous frame"
       (if (called-interactively-p 'any) 'error 'message)
       "Cannot display image: %s" (cdr err)))))
 
+(defun image-mode-revert-buffer (ignore noconfirm)
+  ;; fixme: revert without re-installing the mode; deriving modes is difficult
+  ;; don't ask on reversion
+  (let ((revert-buffer-function nil))
+    (revert-buffer ignore t)))
+
 ;;;###autoload
 (define-minor-mode image-minor-mode
   "Toggle Image minor mode in this buffer.
@@ -566,7 +566,7 @@ With a prefix argument ARG, enable Image minor mode if ARG is
 positive, and disable it otherwise.  If called from Lisp, enable
 the mode if ARG is omitted or nil.
 
-Image minor mode provides the key \\<image-mode-map>\\[image-toggle-display],
+Image minor mode provides the key \\<image-mode-map>\\[image-mode-toggle-display],
 to switch back to `image-mode' and display an image file as the
 actual image."
   nil (:eval (if image-type (format " Image[%s]" image-type) " Image"))
@@ -581,7 +581,7 @@ actual image."
   "Set a non-image mode as major mode in combination with image minor mode.
 A non-image major mode found from `auto-mode-alist' or Fundamental mode
 displays an image file as text.  `image-minor-mode' provides the key
-\\<image-mode-map>\\[image-toggle-display] to switch back to `image-mode'
+\\<image-mode-map>\\[image-mode-toggle-display] to switch back to `image-mode'
 to display an image file as the actual image.
 
 You can use `image-mode-as-text' in `auto-mode-alist' when you want
@@ -617,16 +617,16 @@ on these modes."
     ;; Enable image minor mode with `C-c C-c'.
     (image-minor-mode 1)
     ;; Show the image file as text.
-    (image-toggle-display-text)
+    (image-mode-toggle-display-text)
     (message "%s" (concat
 		   (substitute-command-keys
-		    "Type \\[image-toggle-display] to view the image as ")
+		    "Type \\[image-mode-toggle-display] to view the image as ")
 		   (if (image-get-display-property)
 		       "text" "an image") "."))))
 
 (define-obsolete-function-alias 'image-mode-maybe 'image-mode "23.2")
 
-(defun image-toggle-display-text ()
+(defun image-mode-toggle-display-text ()
   "Show the image file as text.
 Remove text properties that display the image."
   (let ((inhibit-read-only t)
@@ -639,11 +639,19 @@ Remove text properties that display the image."
     (if (called-interactively-p 'any)
 	(message "Repeat this command to go back to displaying the image"))))
 
+(define-obsolete-function-alias 'image-toggle-display-text 'image-mode-toggle-display-text "25.1")
+
+(defun image-mode-show-thumbnails ()
+  "Show thumbnails alongside dired buffer.
+Based on `image-dired'"
+  (interactive)
+  (image-dired default-directory))
+
 (defvar archive-superior-buffer)
 (defvar tar-superior-buffer)
 (declare-function image-flush "image.c" (spec &optional frame))
 
-(defun image-toggle-display-image ()
+(defun image-mode-toggle-display-image ()
   "Show the image of the image file.
 Turn the image data into a real image, but only if the whole file
 was inserted."
@@ -662,19 +670,9 @@ was inserted."
 			   (string-make-unibyte
 			    (buffer-substring-no-properties (point-min) (point-max)))
 			 filename))
-	 ;; If we have a `fit-width' or a `fit-height', don't limit
-	 ;; the size of the image to the window size.
-	 (edges (and (null image-transform-resize)
-		     (window-inside-pixel-edges
-		      (get-buffer-window (current-buffer)))))
-	 (type (if (fboundp 'imagemagick-types)
-		   'imagemagick
-		 (image-type file-or-data nil data-p)))
-	 (image (if (not edges)
-		    (create-image file-or-data type data-p)
-		  (create-image file-or-data type data-p
-				:max-width (- (nth 2 edges) (nth 0 edges))
-				:max-height (- (nth 3 edges) (nth 1 edges)))))
+	 (image (create-image file-or-data nil data-p))
+	 (type (plist-get (cdr image) :type))
+	 ;; (type (image-type file-or-data nil data-p))
 	 (inhibit-read-only t)
 	 (buffer-undo-list t)
 	 (modified (buffer-modified-p))
@@ -682,19 +680,23 @@ was inserted."
 
     ;; Discard any stale image data before looking it up again.
     (image-flush image)
-    (setq image (append image (image-transform-properties image)))
+    (image-transform-interactive image :resize image-mode-auto-resize)
+    
     (setq props
 	  `(display ,image
 		    ;; intangible ,image
 		    rear-nonsticky (display) ;; intangible
-		    read-only t front-sticky (read-only)))
+		    read-only t front-sticky (read-only)
+		    keymap ,image-manipulation-map))
 
     (let ((buffer-file-truename nil)) ; avoid changing dir mtime by lock_file
       (add-text-properties (point-min) (point-max) props)
       (restore-buffer-modified-p modified))
-    ;; Inhibit the cursor when the buffer contains only an image,
-    ;; because cursors look very strange on top of images.
-    (setq cursor-type nil)
+
+    ;; It's important to distinguish active buffer/image.
+    (unless image-mode-show-cursor
+      (setq cursor-type nil))
+
     ;; This just makes the arrow displayed in the right fringe
     ;; area look correct when the image is wider than the window.
     (setq truncate-lines t)
@@ -708,11 +710,12 @@ was inserted."
     (setq image-type type)
     (if (eq major-mode 'image-mode)
 	(setq mode-name (format "Image[%s]" type)))
-    (image-transform-check-size)
     (if (called-interactively-p 'any)
 	(message "Repeat this command to go back to displaying the file as text"))))
 
-(defun image-toggle-display ()
+(define-obsolete-function-alias 'image-toggle-display-image  'image-mode-toggle-display-image "25.1")
+
+(defun image-mode-toggle-display ()
   "Toggle between image and text display.
 If the current buffer is displaying an image file as an image,
 call `image-mode-as-text' to switch to text.  Otherwise, display
@@ -722,13 +725,17 @@ the image by calling `image-mode'."
       (image-mode-as-text)
     (image-mode)))
 
-(defun image-after-revert-hook ()
+(define-obsolete-function-alias 'image-toggle-display 'image-mode-toggle-display "25.1")
+
+(defun image-mode-after-revert ()
   (when (image-get-display-property)
-    (image-toggle-display-text)
+    (image-mode-toggle-display-text)
     ;; Update image display.
     (mapc (lambda (window) (redraw-frame (window-frame window)))
-          (get-buffer-window-list (current-buffer) 'nomini 'visible))
-    (image-toggle-display-image)))
+	  (get-buffer-window-list (current-buffer) 'nomini 'visible))
+    (image-mode-toggle-display-image)))
+
+(define-obsolete-function-alias 'image-after-revert-hook 'image-mode-after-revert "25.1")
 
 \f
 ;;; Animated images
@@ -739,12 +746,13 @@ the image by calling `image-mode'."
   :version "24.1"
   :group 'image)
 
-(defun image-toggle-animation ()
-  "Start or stop animating the current image.
-If `image-animate-loop' is non-nil, animation loops forever.
-Otherwise it plays once, then stops."
+(defun image-toggle-animation (&optional image)
+  "Start or stop animating IMAGE.
+If `image-animate-loop' is non-nil, animation loops
+forever.  Otherwise it plays once, then stops.  IMAGE defaults to
+the image at point."
   (interactive)
-  (let ((image (image-get-display-property))
+  (let ((image (or image (image-at-point)))
 	animation)
     (cond
      ((null image)
@@ -763,15 +771,16 @@ Otherwise it plays once, then stops."
 	    (image-animate image index
 			   (if image-animate-loop t)))))))))
 
-(defun image--set-speed (speed &optional multiply)
-  "Set speed of an animated image to SPEED.
+(defun image--set-speed (image speed &optional multiply)
+  "Set speed of an animated IMAGE to SPEED.
 If MULTIPLY is non-nil, treat SPEED as a multiplication factor.
-If SPEED is `reset', reset the magnitude of the speed to 1."
-  (let ((image (image-get-display-property)))
+If SPEED is `reset', reset the magnitude of the speed to 1.
+IMAGE defaults to `image-at-point'."
+  (let ((image (or image (image-at-point))))
     (cond
      ((null image)
       (error "No image is present"))
-     ((null image-multi-frame)
+     ((null (image-multi-frame-p image))
       (message "No image animation."))
      (t
       (if (eq speed 'reset)
@@ -785,38 +794,46 @@ If SPEED is `reset', reset the magnitude of the speed to 1."
 	(image-toggle-animation))
       (message "Image speed is now %s" (image-animate-get-speed image))))))
 
-(defun image-increase-speed ()
-  "Increase the speed of current animated image by a factor of 2."
+(defun image-increase-speed (&optional image)
+  "Increase the speed of animated IMAGE by a factor of 2.
+IMAGE defaults to `image-at-point'."
   (interactive)
-  (image--set-speed 2 t))
+  (image--set-speed image 2 t))
 
-(defun image-decrease-speed ()
-  "Decrease the speed of current animated image by a factor of 2."
+(defun image-decrease-speed (&optional image)
+  "Decrease the speed of animated IMAGE by a factor of 2.
+IMAGE defaults to `image-at-point'"
   (interactive)
-  (image--set-speed 0.5 t))
+  (image--set-speed image 0.5 t))
 
-(defun image-reverse-speed ()
-  "Reverse the animation of the current image."
+(defun image-reverse-speed (&optional image)
+  "Reverse the animation of the IMAGE.
+IMAGE defaults to `image-at-point'."
   (interactive)
-  (image--set-speed -1 t))
+  (image--set-speed image -1 t))
 
-(defun image-reset-speed ()
-  "Reset the animation speed of the current image."
+(defun image-reset-speed (&optional image)
+  "Reset the animation speed of the IMAGE.
+IMAGE defaults to `image-at-point'."
   (interactive)
   (image--set-speed 'reset))
 
-(defun image-goto-frame (n &optional relative)
+\f
+;;; Multiframe Images
+
+(defun image-goto-frame (n &optional relative image)
   "Show frame N of a multi-frame image.
-Optional argument OFFSET non-nil means interpret N as relative to the
-current frame.  Frames are indexed from 1."
+Optional argument RELATIVE non-nil means interpret N as relative
+to the current frame.  Frames are indexed from 1. IMAGE defaults
+to `image-at-point'."
   (interactive
    (list (or current-prefix-arg
 	     (read-number "Show frame number: "))))
-  (let ((image (image-get-display-property)))
+  (let ((image (or image (image-at-point))))
     (cond
      ((null image)
       (error "No image is present"))
-     ((null image-multi-frame)
+     ((null (image-multi-frame-p image))
       (message "No image animation."))
      (t
       (image-show-frame image
@@ -824,24 +841,26 @@ current frame.  Frames are indexed from 1."
 			    (+ n (image-current-frame image))
 			  (1- n)))))))
 
-(defun image-next-frame (&optional n)
+(defun image-next-frame (&optional n image)
   "Switch to the next frame of a multi-frame image.
 With optional argument N, switch to the Nth frame after the current one.
-If N is negative, switch to the Nth frame before the current one."
+If N is negative, switch to the Nth frame before the current one.
+IMAGE defaults to `image-at-point'."
   (interactive "p")
   (image-goto-frame n t))
 
-(defun image-previous-frame (&optional n)
+(defun image-previous-frame (&optional n image)
   "Switch to the previous frame of a multi-frame image.
-With optional argument N, switch to the Nth frame before the current one.
-If N is negative, switch to the Nth frame after the current one."
+With optional argument N, switch to the Nth frame before the
+current one.  If N is negative, switch to the Nth frame after the
+current one.  IMAGE defaults to `image-at-point'."
   (interactive "p")
   (image-next-frame (- n)))
 
 \f
 ;;; Switching to the next/previous image
 
-(defun image-next-file (&optional n)
+(defun image-mode-next-file (&optional n)
   "Visit the next image in the same directory as the current image file.
 With optional argument N, visit the Nth image file after the
 current one, in cyclic alphabetical order.
@@ -864,7 +883,9 @@ replacing the current Image mode buffer."
     (setq idx (mod (+ idx (or n 1)) (length images)))
     (find-alternate-file (nth idx images))))
 
-(defun image-previous-file (&optional n)
+(define-obsolete-function-alias 'image-next-file 'image-mode-next-file "25.1")
+
+(defun image-mode-previous-file (&optional n)
   "Visit the preceding image in the same directory as the current file.
 With optional argument N, visit the Nth image file preceding the
 current one, in cyclic alphabetical order.
@@ -872,7 +893,7 @@ current one, in cyclic alphabetical order.
 This command visits the specified file via `find-alternate-file',
 replacing the current Image mode buffer."
   (interactive "p")
-  (image-next-file (- n)))
+  (image-mode-next-file (- n)))
 
 (defun image-mode--images-in-directory (file)
   (let* ((dir (file-name-directory buffer-file-name))
@@ -884,6 +905,8 @@ replacing the current Image mode buffer."
       (push file files))
     (sort files 'string-lessp)))
 
+(define-obsolete-function-alias 'image-previous-file 'image-mode-previous-file "25.1")
+
 \f
 ;;; Support for bookmark.el
 (declare-function bookmark-make-record-default
@@ -902,219 +925,236 @@ replacing the current Image mode buffer."
   ;; returned by `bookmark-make-record-function', which see.
   (prog1 (bookmark-default-handler bmk)
     (when (not (string= image-type (bookmark-prop-get bmk 'image-type)))
-      (image-toggle-display))))
+      (image-mode-toggle-display))))
+
 \f
+;;; Image Local Manipulation Map
 
-;; Not yet implemented.
-;; (defvar image-transform-minor-mode-map
-;;   (let ((map (make-sparse-keymap)))
-;;     ;; (define-key map  [(control ?+)] 'image-scale-in)
-;;     ;; (define-key map  [(control ?-)] 'image-scale-out)
-;;     ;; (define-key map  [(control ?=)] 'image-scale-none)
-;;     ;; (define-key map "c f h" 'image-scale-fit-height)
-;;     ;; (define-key map "c ]" 'image-rotate-right)
-;;     map)
-;;   "Minor mode keymap `image-transform-mode'.")
-;;
-;; (define-minor-mode image-transform-mode
-;;   "Minor mode for scaling and rotating images.
-;; With a prefix argument ARG, enable the mode if ARG is positive,
-;; and disable it otherwise.  If called from Lisp, enable the mode
-;; if ARG is omitted or nil.  This minor mode requires Emacs to have
-;; been compiled with ImageMagick support."
-;;   nil "image-transform" image-transform-minor-mode-map)
-
-
-(defsubst image-transform-width (width height)
-  "Return the bounding box width of a rotated WIDTH x HEIGHT rectangle.
-The rotation angle is the value of `image-transform-rotation' in degrees."
-  (let ((angle (degrees-to-radians image-transform-rotation)))
-    ;; Assume, w.l.o.g., that the vertices of the rectangle have the
-    ;; coordinates (+-w/2, +-h/2) and that (0, 0) is the center of the
-    ;; rotation by the angle A.  The projections onto the first axis
-    ;; of the vertices of the rotated rectangle are +- (w/2) cos A +-
-    ;; (h/2) sin A, and the difference between the largest and the
-    ;; smallest of the four values is the expression below.
-    (+ (* width (abs (cos angle))) (* height (abs (sin angle))))))
-
-;; The following comment and code snippet are from
-;; ImageMagick-6.7.4-4/magick/distort.c
-
-;;    /* Set the output image geometry to calculated 'best fit'.
-;;       Yes this tends to 'over do' the file image size, ON PURPOSE!
-;;       Do not do this for DePolar which needs to be exact for virtual tiling.
-;;    */
-;;    if ( fix_bounds ) {
-;;      geometry.x = (ssize_t) floor(min.x-0.5);
-;;      geometry.y = (ssize_t) floor(min.y-0.5);
-;;      geometry.width=(size_t) ceil(max.x-geometry.x+0.5);
-;;      geometry.height=(size_t) ceil(max.y-geometry.y+0.5);
-;;    }
-
-;; Other parts of the same file show that here the origin is in the
-;; left lower corner of the image rectangle, the center of the
-;; rotation is the center of the rectangle and min.x and max.x
-;; (resp. min.y and max.y) are the smallest and the largest of the
-;; projections of the vertices onto the first (resp. second) axis.
-
-(defun image-transform-fit-width (width height length)
-  "Return (w . h) so that a rotated w x h image has exactly width LENGTH.
-The rotation angle is the value of `image-transform-rotation'.
-Write W for WIDTH and H for HEIGHT.  Then the w x h rectangle is
-an \"approximately uniformly\" scaled W x H rectangle, which
-currently means that w is one of floor(s W) + {0, 1, -1} and h is
-floor(s H), where s can be recovered as the value of `image-transform-scale'.
-The value of `image-transform-rotation' may be replaced by
-a slightly different angle.  Currently this is done for values
-close to a multiple of 90, see `image-transform-right-angle-fudge'."
-  (cond ((< (abs (- (mod (+ image-transform-rotation 90) 180) 90))
-	    image-transform-right-angle-fudge)
-	 (cl-assert (not (zerop width)) t)
-	 (setq image-transform-rotation
-	       (float (round image-transform-rotation))
-	       image-transform-scale (/ (float length) width))
-	 (cons length nil))
-	((< (abs (- (mod (+ image-transform-rotation 45) 90) 45))
-	    image-transform-right-angle-fudge)
-	 (cl-assert (not (zerop height)) t)
-	 (setq image-transform-rotation
-	       (float (round image-transform-rotation))
-	       image-transform-scale (/ (float length) height))
-	 (cons nil length))
-	(t
-	 (cl-assert (not (and (zerop width) (zerop height))) t)
-	 (setq image-transform-scale
-	       (/ (float (1- length)) (image-transform-width width height)))
-	 ;; Assume we have a w x h image and an angle A, and let l =
-	 ;; l(w, h) = w |cos A| + h |sin A|, which is the actual width
-	 ;; of the bounding box of the rotated image, as calculated by
-	 ;; `image-transform-width'.  The code snippet quoted above
-	 ;; means that ImageMagick puts the rotated image in
-	 ;; a bounding box of width L = 2 ceil((w+l+1)/2) - w.
-	 ;; Elementary considerations show that this is equivalent to
-	 ;; L - w being even and L-3 < l(w, h) <= L-1.  In our case, L is
-	 ;; the given `length' parameter and our job is to determine
-	 ;; reasonable values for w and h which satisfy these
-	 ;; conditions.
-	 (let ((w (floor (* image-transform-scale width)))
-	       (h (floor (* image-transform-scale height))))
-	   ;; Let w and h as bound above.  Then l(w, h) <= l(s W, s H)
-	   ;; = L-1 < l(w+1, h+1) = l(w, h) + l(1, 1) <= l(w, h) + 2,
-	   ;; hence l(w, h) > (L-1) - 2 = L-3.
-	   (cons
-	    (cond ((= (mod w 2) (mod length 2))
-		   w)
-		  ;; l(w+1, h) >= l(w, h) > L-3, but does l(w+1, h) <=
-		  ;; L-1 hold?
-		  ((<= (image-transform-width (1+ w) h) (1- length))
-		   (1+ w))
-		  ;; No, it doesn't, but this implies that l(w-1, h) =
-		  ;; l(w+1, h) - l(2, 0) >= l(w+1, h) - 2 > (L-1) -
-		  ;; 2 = L-3.  Clearly, l(w-1, h) <= l(w, h) <= L-1.
-		  (t
-		   (1- w)))
-	    h)))))
-
-(defun image-transform-check-size ()
-  "Check that the image exactly fits the width/height of the window.
-
-Do this for an image of type `imagemagick' to make sure that the
-elisp code matches the way ImageMagick computes the bounding box
-of a rotated image."
-  (when (and (not (numberp image-transform-resize))
-	     (boundp 'image-type)
-	     (eq image-type 'imagemagick))
-    (let ((size (image-display-size (image-get-display-property) t)))
-      (cond ((eq image-transform-resize 'fit-width)
-	     (cl-assert (= (car size)
-			(- (nth 2 (window-inside-pixel-edges))
-			   (nth 0 (window-inside-pixel-edges))))
-		     t))
-	    ((eq image-transform-resize 'fit-height)
-	     (cl-assert (= (cdr size)
-			(- (nth 3 (window-inside-pixel-edges))
-			   (nth 1 (window-inside-pixel-edges))))
-		     t))))))
-
-(defun image-transform-properties (spec)
-  "Return rescaling/rotation properties for image SPEC.
-These properties are determined by the Image mode variables
-`image-transform-resize' and `image-transform-rotation'.  The
-return value is suitable for appending to an image spec.
-
-Rescaling and rotation properties only take effect if Emacs is
-compiled with ImageMagick support."
-  (setq image-transform-scale 1.0)
-  (when (or image-transform-resize
-	    (/= image-transform-rotation 0.0))
-    ;; Note: `image-size' looks up and thus caches the untransformed
-    ;; image.  There's no easy way to prevent that.
-    (let* ((size (image-size spec t))
-	   (resized
-	    (cond
-	     ((numberp image-transform-resize)
-	      (unless (= image-transform-resize 1)
-		(setq image-transform-scale image-transform-resize)
-		(cons nil (floor (* image-transform-resize (cdr size))))))
-	     ((eq image-transform-resize 'fit-width)
-	      (image-transform-fit-width
-	       (car size) (cdr size)
-	       (- (nth 2 (window-inside-pixel-edges))
-		  (nth 0 (window-inside-pixel-edges)))))
-	     ((eq image-transform-resize 'fit-height)
-	      (let ((res (image-transform-fit-width
-			  (cdr size) (car size)
-			  (- (nth 3 (window-inside-pixel-edges))
-			     (nth 1 (window-inside-pixel-edges))))))
-		(cons (cdr res) (car res)))))))
-      `(,@(when (car resized)
-	    (list :width (car resized)))
-	,@(when (cdr resized)
-	    (list :height (cdr resized)))
-	,@(unless (= 0.0 image-transform-rotation)
-	    (list :rotation image-transform-rotation))))))
-
-(defun image-transform-set-scale (scale)
-  "Prompt for a number, and resize the current image by that amount.
-This command has no effect unless Emacs is compiled with
-ImageMagick support."
-  (interactive "nScale: ")
-  (setq image-transform-resize scale)
-  (image-toggle-display-image))
-
-(defun image-transform-fit-to-height ()
-  "Fit the current image to the height of the current window.
-This command has no effect unless Emacs is compiled with
-ImageMagick support."
+(defcustom image-scale-step 1.1
+  "Each step scales the image by this amount."
+  :type 'number
+  :group 'image)
+
+(defun image-scale-adjust (&optional N)
+  "Adjust the scale of the image by N steps.
+
+N may be passed as a numeric prefix argument.  Each step scales
+the image by the value of `image-scale-step' (a negative number
+of steps decreases the height by the same amount).  As a special
+case, an argument of 0 will remove any scaling currently active.
+
+The actual adjustment depends on the final element of the
+key binding used to invoke this command:
+
+   +, =   Increase the size of the image by one step
+   -      Decrease the size of the image by one step
+   0      Reset to the original image size
+
+When adjusting with `+' or `-', continue to read input events and
+further adjust the scale as long as the input event read \(with
+all modifiers removed) is `+' or `-'.
+
+This command is a special-purpose wrapper around the
+`image-scale-increase'."
+  ;; fixme: doesn't work with universal arg
+  (interactive "p")
+  (let ((ev last-command-event)
+        (echo-keystrokes nil))
+    (let* ((base (event-basic-type ev))
+           (step
+            (pcase base
+              ((or ?+ ?=) N)
+              (?- (- N))
+              (?0 0)
+              (t N))))
+      (image-scale-increase step)
+      (message "Use +,-,0 for further adjustment")
+      (set-temporary-overlay-map
+       (let ((map (make-sparse-keymap)))
+         (dolist (mods '(() (control)))
+           (dolist (key '(?- ?+ ?= ?0)) ;; = is often unshifted +.
+             (define-key map (vector (append mods (list key)))
+               `(lambda () (interactive) (image-scale-adjust (floor (abs ,N)))))))
+         map)))))
+
+(defun image-scale-increase (&optional inc image)
+  "Scale the the IMAGE by INC steps.
+Each step scales up the size of the IMAGE the value of
+`text-scale-mode-step' (a negative number of steps decreases the
+size by the same amount).  As a special case, an argument of 0
+will remove any scaling currently active. IMAGE defaults to
+`image-at-point'."
+  (interactive "p")
+  (let  ((image (or image
+		    (image-at-point)
+		    (error "No image at point"))))
+    (if (/= inc 0)
+	(image-transform image :scale (* 100 (expt image-scale-step inc)))
+      (image-tr--delete-properties image '(:width :height :resize))
+      ;; don't touch :resize, It might have been set by initial 'fit-xxx operation
+      (image-tr--delete-transforms image '(:scale))
+      (image-transform image))
+    (force-window-update (selected-window))))
+
+(defun image-scale-decrease (&optional inc image)
+  "Scale the IMAGE by INC steps.
+Each step scales down the size of the IMAGE the value of
+`text-scale-mode-step' (a negative number of steps increases the
+size by the same amount).  As a special case, an argument of 0
+will remove any scaling currently active. IMAGE defaults to
+`image-at-point'."
+  (interactive "p")
+  (image-scale-increase (- inc) image))
+
+(defun image-scale-to-fit-height (&optional image)
+  "Fit IMAGE to the height of the current window.
+IMAGE defaults to `image-at-point'."
   (interactive)
-  (setq image-transform-resize 'fit-height)
-  (image-toggle-display-image))
+  (image-transform-interactive image :resize 'fit-height))
 
-(defun image-transform-fit-to-width ()
-  "Fit the current image to the width of the current window.
-This command has no effect unless Emacs is compiled with
-ImageMagick support."
+(defun image-scale-to-fit-width (&optional image)
+  "Fit IMAGE to the width of the current window.
+IMAGE defaults to `image-at-point'."
   (interactive)
-  (setq image-transform-resize 'fit-width)
-  (image-toggle-display-image))
+  (image-transform-interactive image :resize 'fit-width))
 
-(defun image-transform-set-rotation (rotation)
-  "Prompt for an angle ROTATION, and rotate the image by that amount.
-ROTATION should be in degrees.  This command has no effect unless
-Emacs is compiled with ImageMagick support."
+(defun image-scale-to-fit-window (&optional image)
+  "Maximally fit IMAGE into current window.
+IMAGE defaults to `image-at-point'."
+  (interactive)
+  (image-transform-interactive image :resize 'fit))
+
+(defun image-stretch-to-fit-window (&optional image)
+  "Stretch IMAGE into current window.
+IMAGE defaults to `image-at-point'."
+  (interactive)
+  (image-transform-interactive image :resize 'fit-stretch))
+
+(defun image-rotate (rotation &optional image)
+  "Prompt for an angle ROTATION, and rotate the IMAGE by that amount.
+ROTATION should be in degrees.  IMAGE defaults to `image-at-point'."
   (interactive "nRotation angle (in degrees): ")
-  (setq image-transform-rotation (float (mod rotation 360)))
-  (image-toggle-display-image))
+  (image-transform-interactive image :rotate rotation))
 
-(defun image-transform-reset ()
-  "Display the current image with the default size and rotation.
-This command has no effect unless Emacs is compiled with
-ImageMagick support."
+(defun image-rotate-right (&optional image)
+  "Rotate the IMAGE clockwise by 90 degrees.
+IMAGE defaults to `image-at-point'."
   (interactive)
-  (setq image-transform-resize nil
-	image-transform-rotation 0.0
-	image-transform-scale 1)
-  (image-toggle-display-image))
+  (image-transform-interactive image :rotate 90))
+
+(defun image-rotate-left (&optional image)
+  "Rotate the IMAGE counter-clockwise by 90 degrees.
+IMAGE defaults to `image-at-point'."
+  (interactive)
+  (image-transform-interactive image :rotate -90))
+
+(defun image-change-background (&optional background image)
+  "Set the BACKGROUND of the IMAGE.
+For this to work, image must have a transparent background.  IMAGE
+defaults to `image-at-point'."
+  (interactive)
+  (let ((bg (or background (read-color "Background: " t))))
+    (unless image
+      (unless (setq image (image-at-point))
+        (error "No image at point")))
+    (image-transform-interactive image :background bg)))
+
+(defvar image-manipulation-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "F" 'image-goto-frame)
+    (define-key map "f" 'image-next-frame)
+    (define-key map "b" 'image-previous-frame)
+    (define-key map "a+" 'image-increase-speed)
+    (define-key map "a-" 'image-decrease-speed)
+    (define-key map "a0" 'image-reset-speed)
+    (define-key map "ar" 'image-reverse-speed)
+    (define-key map "+" 'image-scale-adjust)
+    (define-key map "-" 'image-scale-adjust)
+    (define-key map "=" 'image-scale-adjust)
+    (define-key map "0" 'image-scale-adjust)
+    (define-key map "r" 'image-rotate)
+    (define-key map "]" 'image-rotate-right)
+    (define-key map "[" 'image-rotate-left)
+    (define-key map "ss" 'image-scale-to-fit-window)
+    (define-key map "sh" 'image-scale-to-fit-height)
+    (define-key map "sw" 'image-scale-to-fit-width)
+    (define-key map "sS" 'image-stretch-to-fit-window)
+    (define-key map "sf" 'image-scale-frame-to-fit-image)
+    (define-key map "ta" 'image-add-transform)
+    (define-key map "tk" 'image-delete-transform)
+    (define-key map "td" 'image-delete-transform)
+    (define-key map "tl" 'image-list-transforms)
+    (define-key map "B" 'image-change-background)
+    (easy-menu-define image-mode-menu map "Local Image Menu."
+      '("Manipulate"
+	["Scale to Window" image-scale-to-fit-window
+	 :help "Maximally resize image to fit into window"]
+	["Scale to Window Height" image-scale-to-fit-height
+	 :help "Resize image to match the window height"]
+	["Scale to Window Width" image-scale-to-fit-width
+	 :help "Resize image to match the window width"]
+	["Scale Frame to Image" image-scale-frame-to-fit-image :active t
+	 :help "Resize frame to match image"]
+	"--"
+	["Rotate Image..." image-rotate]
+	["Rotate Image Right" image-rotate-right]
+	["Rotate Image Left" image-rotate-left]
+	"--"
+	["Change Image Background..." image-change-background]
+	"--"
+	["Add Transform" image-add-transform]
+	["Delete Transform" image-delete-transform]
+	["List Transforms" image-list-transforms]
+	"--"
+	["Animate Image" image-toggle-animation :style toggle
+	 :selected (let ((image (image-at-point)))
+		     (and image (image-animate-timer image)))
+	 :active (image-multi-frame-p (image-at-point))
+         :help "Toggle image animation"]
+	["Loop Animation"
+	 (lambda () (interactive)
+	   (setq image-animate-loop (not image-animate-loop))
+	   ;; FIXME this is a hacky way to make it affect a currently
+	   ;; animating image.
+	   (when (let ((image (image-get-display-property)))
+		   (and image (image-animate-timer image)))
+	     (image-toggle-animation)
+	     (image-toggle-animation)))
+	 :style toggle :selected image-animate-loop
+	 :active (image-multi-frame-p (image-at-point))
+	 :help "Animate images once, or forever?"]
+	["Reverse Animation" image-reverse-speed
+	 :style toggle :selected (let ((image (image-get-display-property)))
+				   (and image (<
+					       (image-animate-get-speed image)
+					       0)))
+	 :active (image-multi-frame-p (image-at-point))
+	 :help "Reverse direction of this image's animation?"]
+	["Speed Up Animation" image-increase-speed
+	 :active (image-multi-frame-p (image-at-point))
+	 :help "Speed up this image's animation"]
+	["Slow Down Animation" image-decrease-speed
+	 :active (image-multi-frame-p (image-at-point))
+	 :help "Slow down this image's animation"]
+	["Reset Animation Speed" image-reset-speed
+	 :active (image-multi-frame-p (image-at-point))
+	 :help "Reset the speed of this image's animation"]
+	["Next Frame" image-next-frame
+	 :active (image-multi-frame-p (image-at-point))
+	 :help "Show the next frame of this image"]
+	["Previous Frame" image-previous-frame
+	 :active (image-multi-frame-p (image-at-point))
+	 :help "Show the previous frame of this image"]
+	["Goto Frame..." image-goto-frame
+	 :active (image-multi-frame-p (image-at-point))
+	 :help "Show a specific frame of this image"]
+	))
+    map)
+  "Image local manipulation keymap.
+Usually used as keymap text property for images.
+
+\\{image-manipulation-map}")
+
 
 (provide 'image-mode)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: Type: text/x-diff, Size: 2330 bytes --]

	Modified   image.el
diff --git a/image.el b/image.el
index 8430d36..1535567 100644
--- a/image.el
+++ b/image.el
@@ -441,7 +441,7 @@ means display it in the right marginal area."
 
 
 ;;;###autoload
-(defun insert-image (image &optional string area slice)
+(defun insert-image (image &optional string area slice map)
   "Insert IMAGE into current buffer at point.
 IMAGE is displayed by inserting STRING into the current buffer
 with a `display' property whose value is the image.  STRING
@@ -454,7 +454,10 @@ SLICE specifies slice of IMAGE to insert.  SLICE nil or omitted
 means insert whole image.  SLICE is a list (X Y WIDTH HEIGHT)
 specifying the X and Y positions and WIDTH and HEIGHT of image area
 to insert.  A float value 0.0 - 1.0 means relative to the width or
-height of the image; integer values are taken as pixel values."
+height of the image; integer values are taken as pixel values.
+If MAP is provided, it must be a keymap what will be used as
+text property keymap. A special value of t means to use
+`image-manipulation-map'"
   ;; Use a space as least likely to cause trouble when it's a hidden
   ;; character in the buffer.
   (unless string (setq string " "))
@@ -471,12 +474,16 @@ height of the image; integer values are taken as pixel values."
     ;; cut-and-paste.  (Yanking killed image text next to another copy
     ;; of it loses anyway.)
     (setq image (cons 'image (cdr image))))
+  (when (eq map t)
+    (setq map image-manipulation-map))
   (let ((start (point)))
     (insert string)
     (add-text-properties start (point)
 			 `(display ,(if slice
 					(list (cons 'slice slice) image)
-				      image) rear-nonsticky (display)))))
+				      image)
+                                   rear-nonsticky (display)
+                                   keymap ,map))))
 
 
 ;;;###autoload
@@ -519,7 +526,6 @@ The image is automatically split into ROWS x COLS slices."
       (insert (propertize "\n" 'line-height t)))))
 
 
-
 ;;;###autoload
 (defun remove-images (start end &optional buffer)
   "Remove images between START and END in BUFFER.
@@ -558,6 +564,7 @@ BUFFER nil or omitted means use the current buffer."
       (setq path (cdr path)))
     (if found filename)))
 
+
 ;;;###autoload
 (defun find-image (specs)
   "Find an image, choosing one of a list of image specifications.

[-- Attachment #4: image-transform.el --]
[-- Type: application/emacs-lisp, Size: 57236 bytes --]

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

* Re: image-transform.el and image-mode.el rewrite
  2014-12-15  9:33                         ` Vitalie Spinu
@ 2014-12-18 14:17                           ` Michael Heerdegen
  2014-12-18 21:32                             ` Vitalie Spinu
  2014-12-18 15:15                           ` Stefan Monnier
  1 sibling, 1 reply; 55+ messages in thread
From: Michael Heerdegen @ 2014-12-18 14:17 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: Glenn Morris, emacs-devel

Vitalie Spinu <spinuvit@gmail.com> writes:

> I have finally got down to this.
> [...]
> At this stage the stuff is ready for a review as I have only minor
> things to fix. I will be traveling till 18th and will resume once I am
> back. Would be really great if interested people could have a quick look
> till then.

Looks like it was a lot of work - many thanks!

I can't speak for Emacs dev, hope someone with background knowledge can
also review your code.  I played with it a bit, and it was working
nicely in general.

Some comments:

- When I visit an image file, `image-manipulation-map' doesn't seem to be
  installed.  E.g. "+" is not working etc.  OTOH when I hit C-c C-c two
  times, it works then.  Is this expected?

- I think it would be good when there would be entries in the
  "Manipulate" menu (defined in `image-manipulation-map') for increasing
  and decreasing the image size.

- I see some warnings about unused lexical variables.  I think some are
  concerning pcase (where you probably need to prefix unused vars with
  underscore in some patterns), but there are also some concerning
  function arguments.

- And there are some warnings about using cl functions at runtime.  I
  guess Emacs maintainers will want you to use only cl-lib?


HTH,

Michael.



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

* Re: image-transform.el and image-mode.el rewrite
  2014-12-15  9:33                         ` Vitalie Spinu
  2014-12-18 14:17                           ` Michael Heerdegen
@ 2014-12-18 15:15                           ` Stefan Monnier
  2014-12-18 23:23                             ` Vitalie Spinu
  1 sibling, 1 reply; 55+ messages in thread
From: Stefan Monnier @ 2014-12-18 15:15 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: Michael Heerdegen, Glenn Morris, emacs-devel

>   https://github.com/vspinu/image-transform/compare/emacs...master

Thanks Vitalie, overall it looks pretty good and I think it's pretty
much ready for inclusion.

This is not my area of expertise, so hopefully someone else can take
another look, but besides Michael's comments I'll add:

- You seem to have rename a few "image-mode-FOO" to "image-BAR" and also
  a few "image-TOTO" to "image-mode-TITI".  I'm not necessarily opposed
  to those changes, but I'm not sure I understand the rationale behind
  it.  I think it would be good to document (e.g. in the "Commentary:"
  section) the convention used to decide whether the name should be
  "image-mode-FOO" or "image-BAR".

- While it's OK to install such a change only for image-mode.el
  (i.e. take it one step at a time), I recommend you take a look at
  doc-view.el and plan on sharing some of the code there as well.
  E.g. the image-scale-step should probably be merged with
  doc-view-shrink-factor.

- Use (require 'cl-lib) instead of (require 'cl-macs).

- You don't need to (require 'pcase), it's autoloaded.

- Don't use `(lambda ...) when you could use a closure instead.

- Use `define-error' instead of (put 'next-backend 'error-conditions ...).

- Use "convert" instead of (executable-find "convert"), especially since
  you define the variable to hold a string, and executable-find can return nil.

- (executable-find "convert") does not return a "path" but a "file name".
  A "path" is a list of directories, as in $PATH, load-path, ...

- The :flatten arg to image-transform looks wrong.  Instead of
  ":flatten" it should be ":flatten t" (i.e. all keywords should be
  followed by a value and a nil value should be equivalent to not having
  mentioned the keyword).  IOW the "Boolean specs can miss the value, in
  which case t is assumed" is a misfeature.

- The image-transform-features:convert seems over-engineered.  I think
  I'd rather have a ":convert-args" that provides a mechanism to pass
  any args to "convert" and then remove the bulk of those keywords.


        Stefan



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

* Re: image-transform.el and image-mode.el rewrite
  2014-12-18 14:17                           ` Michael Heerdegen
@ 2014-12-18 21:32                             ` Vitalie Spinu
  0 siblings, 0 replies; 55+ messages in thread
From: Vitalie Spinu @ 2014-12-18 21:32 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: Glenn Morris, emacs-devel

 >>> Michael Heerdegen on Thu, 18 Dec 2014 15:17:01 +0100 wrote:

 > Some comments:

 > - When I visit an image file, `image-manipulation-map' doesn't seem to be
 >   installed.  E.g. "+" is not working etc.  OTOH when I hit C-c C-c two
 >   times, it works then.  Is this expected?

It should work at start. You should see a Manipulate menu and all the
keys from `image-manipulate-map` must be active. It works for me on
25.0.50.1.

 > - I think it would be good when there would be entries in the
 > "Manipulate" menu (defined in `image-manipulation-map') for
 > increasing and decreasing the image size.

Good point.

 > - I see some warnings about unused lexical variables.  I think some are
 >   concerning pcase (where you probably need to prefix unused vars with
 >   underscore in some patterns), but there are also some concerning
 >   function arguments.
 >
 > - And there are some warnings about using cl functions at runtime.  I
 >   guess Emacs maintainers will want you to use only cl-lib?

Sure, I am fixing these.

Thanks, 

  Vitalie



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

* Re: image-transform.el and image-mode.el rewrite
  2014-12-18 15:15                           ` Stefan Monnier
@ 2014-12-18 23:23                             ` Vitalie Spinu
  2014-12-19  4:19                               ` Stefan Monnier
  0 siblings, 1 reply; 55+ messages in thread
From: Vitalie Spinu @ 2014-12-18 23:23 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Michael Heerdegen, Glenn Morris, emacs-devel

 >>> Stefan Monnier on Thu, 18 Dec 2014 10:15:07 -0500 wrote:

 > - You seem to have rename a few "image-mode-FOO" to "image-BAR" and also
 >   a few "image-TOTO" to "image-mode-TITI".  I'm not necessarily opposed
 >   to those changes, but I'm not sure I understand the rationale behind
 >   it.  I think it would be good to document (e.g. in the "Commentary:"
 >   section) the convention used to decide whether the name should be
 >   "image-mode-FOO" or "image-BAR".

With the exception of `image-mode-fit-frame` all renames either added or
removed -mode- from the name. The rationale is very simple. Functions
that operate on images and are meaningful outside of `image-mode` don't
have -mode- in the name. Eventually, it would be nice to extract all
these functions into a separate `image-manip.el`.

The recently added image-mode-fit-frame was renamed into
image-scale-frame-to-fit-image because I wanted to place it on "s"
prefix in `image-manipulation-map' with all other scaling commands:

      "ss" 'image-scale-to-fit-window
      "sh" 'image-scale-to-fit-height
      "sw" 'image-scale-to-fit-width
      "sS" 'image-stretch-to-fit-window
      "sf" 'image-scale-frame-to-fit-image

The "f" in `image-mode-map`, which is arguably more suitable for this
functionality, has been used for `image-next-frame` for long time. So I
decided to use -scale- as a new mnemonic.

 > I recommend you take a look at doc-view.el and plan on sharing some
 > of the code there as well. E.g. the image-scale-step should probably
 > be merged with doc-view-shrink-factor.

Eventually all of the doc-view scaling and fitting should be based on
image-manip. I plan to look into that once this patch is done with.

 > - The :flatten arg to image-transform looks wrong.  Instead of
 > ":flatten" it should be ":flatten t" (i.e. all keywords should be
 > followed by a value and a nil value should be equivalent to not
 > having mentioned the keyword).  IOW the "Boolean specs can miss the
 > value, in which case t is assumed" is a misfeature.

It mimics convert/bash specification where boolean parameters are either
there or not. I would be happy to remove this feature, as it brings some
additional complexities.

 > - The image-transform-features:convert seems over-engineered.  I think
 >   I'd rather have a ":convert-args" that provides a mechanism to pass
 >   any args to "convert" and then remove the bulk of those keywords.

The `image-transform-features:convert' in the current form is at the
core of image-transform.el. Convert specification is used as a canonical
description of the transformations, thus ensuring compatibility between
backeds. This allows for writing of generic code independently of the
applied backend. Currently, any transformation chain that works under
'native backend will work with 'convert. If 'native backend is extended
in the future with more transformations, or new backends are added, old
code will work happily with all of the new features.

Also, a comprehensive list of transforms and their types makes possible
interactive application of transforms as in `image-add-transform`. This
essentially makes from Emacs a lightweight image editor.


  Vitalie



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

* Re: image-transform.el and image-mode.el rewrite
  2014-12-18 23:23                             ` Vitalie Spinu
@ 2014-12-19  4:19                               ` Stefan Monnier
  2014-12-19  4:46                                 ` Vitalie Spinu
                                                   ` (2 more replies)
  0 siblings, 3 replies; 55+ messages in thread
From: Stefan Monnier @ 2014-12-19  4:19 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: Michael Heerdegen, Glenn Morris, emacs-devel

> With the exception of `image-mode-fit-frame` all renames either added or
> removed -mode- from the name. The rationale is very simple. Functions
> that operate on images and are meaningful outside of `image-mode` don't
> have -mode- in the name.

Makes sense.  So just include this explanation in the Commentary:.

>> I recommend you take a look at doc-view.el and plan on sharing some
>> of the code there as well. E.g. the image-scale-step should probably
>> be merged with doc-view-shrink-factor.
> Eventually all of the doc-view scaling and fitting should be based on
> image-manip. I plan to look into that once this patch is done with.

Perfect, thanks (tho the scaling at least should not be performed on
the png images, but rather (as is the case now) should be done as part
of the conversion to png, otherwise the loss of quality is annoying).

> It mimics convert/bash specification where boolean parameters are either
> there or not.  I would be happy to remove this feature, as it brings some
> additional complexities.

Then please remove it.  This complexity is not worth its weight.

> The `image-transform-features:convert' in the current form is at the
> core of image-transform.el. Convert specification is used as a canonical
> description of the transformations, thus ensuring compatibility between
> backeds. This allows for writing of generic code independently of the
> applied backend. Currently, any transformation chain that works under
> 'native backend will work with 'convert.

image-transform-features:convert includes an insane amount of things
additionally to what we can ever expect to see in the native backend(s).

> If 'native backend is extended in the future with more
> transformations, or new backends are added, old code will work happily
> with all of the new features.

I don't really like the idea of "convert" being the definition of what
can be done.  So I'd rather stick to a smaller subset, along with an
escape hatch, in case the program is OK with being dependent on the
presence of "convert".

An intermediate solution might be to auto-generate the
bulk of the image-transform-features:convert entries from something like
"convert --help".


        Stefan



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

* Re: image-transform.el and image-mode.el rewrite
  2014-12-19  4:19                               ` Stefan Monnier
@ 2014-12-19  4:46                                 ` Vitalie Spinu
  2014-12-19  8:56                                 ` Eli Zaretskii
  2014-12-19 10:24                                 ` Vitalie Spinu
  2 siblings, 0 replies; 55+ messages in thread
From: Vitalie Spinu @ 2014-12-19  4:46 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Michael Heerdegen, Glenn Morris, emacs-devel

 >>> Stefan Monnier on Thu, 18 Dec 2014 23:19:17 -0500 wrote:

 > the scaling at least should not be performed on the png images, 

Then we might need a new "gs" backend.

 > image-transform-features:convert includes an insane amount of things
 > additionally to what we can ever expect to see in the native backend(s).

It's about 200 items in 240 lines. Is it really that big of a deal?

 > I don't really like the idea of "convert" being the definition of
 > what can be done.  

It's not really all that can be done, but rather a rigorous syntax for
expressing transforms. image-transform.el needs a syntax for
representing transforms anyways, so we have to either invent it
ourselves or pick it from an established system like convert.

 > An intermediate solution might be to auto-generate the
 > bulk of the image-transform-features:convert entries from something like
 > "convert --help".

This is a good idea. It would also keep in sync with the installed
version of convert. I will look into that.

  Vitalie



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

* Re: image-transform.el and image-mode.el rewrite
  2014-12-19  4:19                               ` Stefan Monnier
  2014-12-19  4:46                                 ` Vitalie Spinu
@ 2014-12-19  8:56                                 ` Eli Zaretskii
  2014-12-19 17:50                                   ` Stefan Monnier
  2014-12-19 10:24                                 ` Vitalie Spinu
  2 siblings, 1 reply; 55+ messages in thread
From: Eli Zaretskii @ 2014-12-19  8:56 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: michael_heerdegen, rgm, spinuvit, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Date: Thu, 18 Dec 2014 23:19:17 -0500
> Cc: Michael Heerdegen <michael_heerdegen@web.de>, Glenn Morris <rgm@gnu.org>,
> 	emacs-devel@gnu.org
> 
> > With the exception of `image-mode-fit-frame` all renames either added or
> > removed -mode- from the name. The rationale is very simple. Functions
> > that operate on images and are meaningful outside of `image-mode` don't
> > have -mode- in the name.
> 
> Makes sense.

Now _I_ am confused.  I thought the "image-mode-" prefix was for
namespace reasons, because the symbols are defined in a package named
"image-mode".  I thought this was our rule: to request such prefixes
based on the package name.

But now you seem to say that this rule is bendable under some
(unspecified) conditions?  Please help me understand what are those
conditions, and what exactly are the rules.



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

* Re: image-transform.el and image-mode.el rewrite
  2014-12-19  4:19                               ` Stefan Monnier
  2014-12-19  4:46                                 ` Vitalie Spinu
  2014-12-19  8:56                                 ` Eli Zaretskii
@ 2014-12-19 10:24                                 ` Vitalie Spinu
  2014-12-19 17:51                                   ` Stefan Monnier
  2 siblings, 1 reply; 55+ messages in thread
From: Vitalie Spinu @ 2014-12-19 10:24 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Michael Heerdegen, Glenn Morris, emacs-devel


 >>> Stefan Monnier on Thu, 18 Dec 2014 23:19:17 -0500 wrote:

 > image-transform-features:convert includes an insane amount of things
 > additionally to what we can ever expect to see in the native backend(s).

[...]

 > An intermediate solution might be to auto-generate the
 > bulk of the image-transform-features:convert entries from something like
 > "convert --help".

This doesn't work as smoothly as I thought. A lot of the options must be
removed anyways or require special post processing. So I decided to go
with your first suggestion and add :extra-convert-options argument to
convert backend. I have reduced the number of transforms to about 60. I
will cut them even further once I am fully clarified of their meaning.

Naturally, this selection is somewhat subjective. My main criteria was
the conceptual simplicity and the ease of the interactive usage. So I
left most common operations that might be useful for quick adjustment of
the image in an interactive settings. Things like flipping/flopping,
gamma/contrast correction, shifting, color inversion, thresholding,
noise reduction and various effects are all there:
https://github.com/vspinu/image-transform/blob/master/image-transform.el#L892-L1000


 Vitalie







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

* Re: image-transform.el and image-mode.el rewrite
  2014-12-19  8:56                                 ` Eli Zaretskii
@ 2014-12-19 17:50                                   ` Stefan Monnier
  2014-12-19 19:37                                     ` Eli Zaretskii
  0 siblings, 1 reply; 55+ messages in thread
From: Stefan Monnier @ 2014-12-19 17:50 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: michael_heerdegen, rgm, spinuvit, emacs-devel

>> > With the exception of `image-mode-fit-frame` all renames either added or
>> > removed -mode- from the name. The rationale is very simple. Functions
>> > that operate on images and are meaningful outside of `image-mode` don't
>> > have -mode- in the name.
>> Makes sense.
> Now _I_ am confused.  I thought the "image-mode-" prefix was for
> namespace reasons, because the symbols are defined in a package named
> "image-mode".  I thought this was our rule: to request such prefixes
> based on the package name.

Many packages use more than one prefix.  Some packages use only one
prefix, but it is slightly different from the file name.  Other packages
use one prefix shared by several files.
So, the rule is somewhat flexible.

If someone wants to formalize it, be my guest, but I haven't seen any
need for it so far.


        Stefan



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

* Re: image-transform.el and image-mode.el rewrite
  2014-12-19 10:24                                 ` Vitalie Spinu
@ 2014-12-19 17:51                                   ` Stefan Monnier
  0 siblings, 0 replies; 55+ messages in thread
From: Stefan Monnier @ 2014-12-19 17:51 UTC (permalink / raw)
  To: Vitalie Spinu; +Cc: Michael Heerdegen, Glenn Morris, emacs-devel

> convert backend. I have reduced the number of transforms to about 60.

Still seems daunting, but much better already, thank you.


        Stefan



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

* Re: image-transform.el and image-mode.el rewrite
  2014-12-19 17:50                                   ` Stefan Monnier
@ 2014-12-19 19:37                                     ` Eli Zaretskii
  2014-12-19 21:31                                       ` Stefan Monnier
  0 siblings, 1 reply; 55+ messages in thread
From: Eli Zaretskii @ 2014-12-19 19:37 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: michael_heerdegen, rgm, spinuvit, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: spinuvit@gmail.com,  michael_heerdegen@web.de,  rgm@gnu.org,  emacs-devel@gnu.org
> Date: Fri, 19 Dec 2014 12:50:20 -0500
> 
> >> > With the exception of `image-mode-fit-frame` all renames either added or
> >> > removed -mode- from the name. The rationale is very simple. Functions
> >> > that operate on images and are meaningful outside of `image-mode` don't
> >> > have -mode- in the name.
> >> Makes sense.
> > Now _I_ am confused.  I thought the "image-mode-" prefix was for
> > namespace reasons, because the symbols are defined in a package named
> > "image-mode".  I thought this was our rule: to request such prefixes
> > based on the package name.
> 
> Many packages use more than one prefix.  Some packages use only one
> prefix, but it is slightly different from the file name.  Other packages
> use one prefix shared by several files.
> So, the rule is somewhat flexible.

No matter what is the current situation, the question is what we want
it to be.  I guess the answer is more or less "we don't care".



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

* Re: image-transform.el and image-mode.el rewrite
  2014-12-19 19:37                                     ` Eli Zaretskii
@ 2014-12-19 21:31                                       ` Stefan Monnier
  2014-12-19 21:49                                         ` Eli Zaretskii
  0 siblings, 1 reply; 55+ messages in thread
From: Stefan Monnier @ 2014-12-19 21:31 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: michael_heerdegen, rgm, spinuvit, emacs-devel

> No matter what is the current situation, the question is what we want
> it to be.  I guess the answer is more or less "we don't care".

I'm fine with one prefix being shared among a few different files
(e.g. "image-" used by both image.el and image-mode.el) as long as
they're maintained somewhat together (so there shouldn't be a risk of
collision).

I'm OK with the prefix being slightly different from the file name
itself (e.g. "ad-" for advice.el).

I don't like it when a single file uses more than one prefix, but in
some cases it can make sense, tho often it's more trouble than anything
(e.g. the "tex-" vs "latex-" in tex-mode.el is kind of a mess).


        Stefan



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

* Re: image-transform.el and image-mode.el rewrite
  2014-12-19 21:31                                       ` Stefan Monnier
@ 2014-12-19 21:49                                         ` Eli Zaretskii
  0 siblings, 0 replies; 55+ messages in thread
From: Eli Zaretskii @ 2014-12-19 21:49 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: michael_heerdegen, rgm, spinuvit, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Date: Fri, 19 Dec 2014 16:31:57 -0500
> Cc: michael_heerdegen@web.de, rgm@gnu.org, spinuvit@gmail.com,
> 	emacs-devel@gnu.org
> 
> I'm fine with one prefix being shared among a few different files
> (e.g. "image-" used by both image.el and image-mode.el) as long as
> they're maintained somewhat together (so there shouldn't be a risk of
> collision).
> 
> I'm OK with the prefix being slightly different from the file name
> itself (e.g. "ad-" for advice.el).
> 
> I don't like it when a single file uses more than one prefix, but in
> some cases it can make sense, tho often it's more trouble than anything
> (e.g. the "tex-" vs "latex-" in tex-mode.el is kind of a mess).

I can live with that, although just having the prefix identical to the
file name would have been a simpler rule.



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

end of thread, other threads:[~2014-12-19 21:49 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-14  7:25 imagemagic in image-mode and image-dired-thumbnail-mode? Vitalie Spinu
2013-07-14  8:32 ` joakim
2013-07-14 11:48   ` Vitalie Spinu
2013-07-14 12:40     ` joakim
2013-07-14 13:01       ` Vitalie Spinu
2013-07-14 12:42     ` Lars Magne Ingebrigtsen
2013-07-14 18:21       ` Glenn Morris
2013-07-14 19:50         ` Lars Magne Ingebrigtsen
2013-07-14 20:06           ` Eli Zaretskii
2013-07-14 20:11             ` Lars Magne Ingebrigtsen
2013-07-14 22:00             ` Vitalie Spinu
2013-07-15  4:38               ` Eli Zaretskii
2013-07-15  4:15             ` Stephen J. Turnbull
2013-07-15  4:46               ` Eli Zaretskii
2013-07-15  5:45                 ` Stephen J. Turnbull
2013-07-15 10:39                   ` Óscar Fuentes
2013-08-02 15:32                     ` Steinar Bang
2013-07-15 15:50                   ` Eli Zaretskii
2013-07-14 18:33   ` Glenn Morris
2013-07-14 19:17     ` joakim
2013-07-15 10:51       ` Vitalie Spinu
2013-07-16 15:57         ` Glenn Morris
2013-07-16 21:26         ` Stefan Monnier
2013-07-17  7:29           ` Vitalie Spinu
2013-07-17 15:51             ` Vitalie Spinu
2013-07-18  8:47               ` Lars Magne Ingebrigtsen
2013-07-18 22:27                 ` Vitalie Spinu
2013-07-19  9:22                   ` Stefan Monnier
2013-07-20  7:25                     ` Vitalie Spinu
2013-07-22 20:17                 ` Vitalie Spinu
2013-07-22 20:31                   ` Lars Magne Ingebrigtsen
2013-07-23  8:31                     ` Vitalie Spinu
2013-07-18 23:22               ` image-transform.el and image-mode.el rewrite Vitalie Spinu
2013-07-19 11:52                 ` Wolfgang Jenkner
2013-07-19 12:21                   ` Wolfgang Jenkner
2013-07-20  7:18                     ` Vitalie Spinu
2013-07-22 20:37                 ` Glenn Morris
2013-07-22 21:05                   ` Vitalie Spinu
2013-10-08 18:08                   ` Glenn Morris
2013-10-08 23:43                     ` Vitalie Spinu
2013-10-09  0:02                       ` Michael Heerdegen
2014-12-15  9:33                         ` Vitalie Spinu
2014-12-18 14:17                           ` Michael Heerdegen
2014-12-18 21:32                             ` Vitalie Spinu
2014-12-18 15:15                           ` Stefan Monnier
2014-12-18 23:23                             ` Vitalie Spinu
2014-12-19  4:19                               ` Stefan Monnier
2014-12-19  4:46                                 ` Vitalie Spinu
2014-12-19  8:56                                 ` Eli Zaretskii
2014-12-19 17:50                                   ` Stefan Monnier
2014-12-19 19:37                                     ` Eli Zaretskii
2014-12-19 21:31                                       ` Stefan Monnier
2014-12-19 21:49                                         ` Eli Zaretskii
2014-12-19 10:24                                 ` Vitalie Spinu
2014-12-19 17:51                                   ` Stefan Monnier

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