Make combinations of :width/:max-height image specs work reliably

* doc/lispref/display.texi (ImageMagick Images): Document
:width/:max-height combinations (etc) (bug #25583).

* src/image.c (compute_image_size): Handle :width/:max-height
(etc) combinations consistently (by letting "max" win and
preserve ratio).

* test/manual/image-size-tests.el (image-size-tests): Add
tests for :width/:max-height (etc) combinations.
This commit is contained in:
Lars Ingebrigtsen 2017-07-15 02:45:19 +02:00
parent 89c5d59280
commit ae56c9674b
4 changed files with 73 additions and 55 deletions

View file

@ -5305,6 +5305,17 @@ and if @code{:height} is set it will have precedence over
wish. @code{:max-width} and @code{:max-height} will always preserve
the aspect ratio.
If both @code{:width} and @code{:max-height} has been set (but
@code{:height} has not been set), then @code{:max-height} will have
precedence. The same is the case for the opposite combination: The
``max'' keyword has precedence. That is, if you have a 200x100 image
and specify that @code{:width} should be 400 and @code{:max-height}
should be 150, you'll end up with an image that is 300x150: Preserving
the aspect ratio and not exceeding the ``max'' setting. This
combination of parameters is a useful way of saying ``display this
image as large as possible, but no larger than the available display
area''.
@item :scale @var{scale}
This should be a number, where values higher than 1 means to increase
the size, and lower means to decrease the size. For instance, a value

View file

@ -762,6 +762,14 @@ Ido mode is active.
'image-scaling-factor' variable (if Emacs supports scaling the images
in question).
+++
*** It's now possible to specify aspect-ratio preserving combinations
of :width/:max-height and :height/:max-width keywords. In either
case, the "max" keywords win. (Previously some combinations would,
depending on the aspect ratio of the image, just be ignored and in
other instances this would lead to the aspect ratio not being
preserved.)
+++
*** Images inserted with 'insert-image' and related functions get a
keymap put into the text properties (or overlays) that span the

View file

@ -8086,83 +8086,76 @@ compute_image_size (size_t width, size_t height,
int *d_width, int *d_height)
{
Lisp_Object value;
int desired_width, desired_height;
int desired_width = -1, desired_height = -1, max_width = -1, max_height = -1;
double scale = 1;
value = image_spec_value (spec, QCscale, NULL);
if (NUMBERP (value))
scale = XFLOATINT (value);
value = image_spec_value (spec, QCmax_width, NULL);
if (NATNUMP (value))
max_width = min (XFASTINT (value), INT_MAX);
value = image_spec_value (spec, QCmax_height, NULL);
if (NATNUMP (value))
max_height = min (XFASTINT (value), INT_MAX);
/* If width and/or height is set in the display spec assume we want
to scale to those values. If either h or w is unspecified, the
unspecified should be calculated from the specified to preserve
aspect ratio. */
value = image_spec_value (spec, QCwidth, NULL);
desired_width = NATNUMP (value) ?
min (XFASTINT (value) * scale, INT_MAX) : -1;
if (NATNUMP (value))
{
desired_width = min (XFASTINT (value) * scale, INT_MAX);
/* :width overrides :max-width. */
max_width = -1;
}
value = image_spec_value (spec, QCheight, NULL);
desired_height = NATNUMP (value) ?
min (XFASTINT (value) * scale, INT_MAX) : -1;
if (NATNUMP (value))
{
desired_height = min (XFASTINT (value) * scale, INT_MAX);
/* :height overrides :max-height. */
max_height = -1;
}
/* If we have both width/height set explicitly, we skip past all the
aspect ratio-preserving computations below. */
if (desired_width != -1 && desired_height != -1)
goto out;
width = width * scale;
height = height * scale;
if (desired_width == -1)
{
value = image_spec_value (spec, QCmax_width, NULL);
if (NATNUMP (value))
{
int max_width = min (XFASTINT (value), INT_MAX);
if (max_width < width)
{
/* The image is wider than :max-width. */
desired_width = max_width;
if (desired_height == -1)
{
desired_height = scale_image_size (desired_width,
width, height);
value = image_spec_value (spec, QCmax_height, NULL);
if (NATNUMP (value))
{
int max_height = min (XFASTINT (value), INT_MAX);
if (max_height < desired_height)
{
desired_height = max_height;
desired_width = scale_image_size (desired_height,
height, width);
}
}
}
}
}
}
if (desired_height == -1)
{
value = image_spec_value (spec, QCmax_height, NULL);
if (NATNUMP (value))
{
int max_height = min (XFASTINT (value), INT_MAX);
if (max_height < height)
desired_height = max_height;
}
}
if (desired_width != -1 && desired_height == -1)
/* w known, calculate h. */
/* Width known, calculate height. */
desired_height = scale_image_size (desired_width, width, height);
if (desired_width == -1 && desired_height != -1)
/* h known, calculate w. */
else if (desired_width == -1 && desired_height != -1)
/* Height known, calculate width. */
desired_width = scale_image_size (desired_height, height, width);
/* We have no width/height settings, so just apply the scale. */
if (desired_width == -1 && desired_height == -1)
else
{
desired_width = width;
desired_height = height;
}
if (max_width != -1 && desired_width > max_width)
{
/* The image is wider than :max-width. */
desired_width = max_width;
desired_height = scale_image_size (desired_width, width, height);
}
if (max_height != -1 && desired_height > max_height)
{
/* The image is higher than :max-height. */
desired_height = max_height;
desired_width = scale_image_size (desired_height, height, width);
}
out:
*d_width = desired_width;
*d_height = desired_height;
}

View file

@ -25,8 +25,8 @@
(defmacro im-should (image width height &rest props)
`(let ((im (im-image ,image ,@props)))
(unless (im-compare im ,width ,height)
(error "%s didn't succeed; size is %s"
',props (image-size im t)))))
(error "%s %s didn't succeed; size is %s"
',image ',props (image-size im t)))))
(defun im-image (type &rest props)
(let ((image-scaling-factor 1))
@ -67,6 +67,9 @@
;; Both max-width/height.
(im-should :w 100 50 :max-width 100 :max-height 75)
(im-should :w 50 25 :max-width 100 :max-height 25)
;; :width and :max-height (max-height wins).
(im-should :w 400 200 :width 400 :max-height 200)
(im-should :w 400 200 :width 500 :max-height 200)
;; Test the image that's taller than it is wide.
(im-should :h 100 200)
@ -87,6 +90,9 @@
;; Both max-width/height.
(im-should :h 50 100 :max-width 75 :max-height 100)
(im-should :h 25 50 :max-width 25 :max-height 100)
;; :hieght and :max-width (max-width wins).
(im-should :h 200 400 :height 400 :max-width 200)
(im-should :h 200 400 :height 500 :max-width 200)
)
;;; image-size-tests.el ends here