@@ -5907,6 +5907,12 @@ defmodule Image do
59075907 a list of 3 or 4 float values depending on the image
59085908 color space.
59095909
5910+ ## Discrete rotation
5911+
5912+ When `angle` is a multiple of 90, and all displacement options
5913+ are unset, `nil`, `0` or `0.0`, the rotation will be done as a
5914+ discrete operation in order to preserve source pixel values.
5915+
59105916 ## Notes
59115917
59125918 The displacement parameters cause the image canvas to be
@@ -5935,10 +5941,41 @@ defmodule Image do
59355941
59365942 def rotate ( % Vimage { } = image , angle , options \\ [ ] ) when is_number ( angle ) do
59375943 with { :ok , options } <- Options.Rotate . validate_options ( options ) do
5938- Operation . rotate ( image , angle , options )
5944+ rot_angle = rot_angle ( angle , options )
5945+
5946+ if rot_angle do
5947+ Operation . rot ( image , rot_angle )
5948+ else
5949+ Operation . rotate ( image , angle , options )
5950+ end
5951+ end
5952+ end
5953+
5954+ defp rot_angle ( angle , options ) do
5955+ if Options.Rotate . no_displacement? ( options ) do
5956+ to_rot_angle ( angle )
59395957 end
59405958 end
59415959
5960+ defp to_rot_angle ( angle ) when is_integer ( angle ) and rem ( angle , 90 ) == 0 do
5961+ angle
5962+ |> Integer . mod ( 360 )
5963+ |> rot_angle_from_degrees ( )
5964+ end
5965+
5966+ defp to_rot_angle ( angle ) when is_float ( angle ) and angle == trunc ( angle ) do
5967+ angle
5968+ |> trunc ( )
5969+ |> to_rot_angle ( )
5970+ end
5971+
5972+ defp to_rot_angle ( _angle ) , do: nil
5973+
5974+ defp rot_angle_from_degrees ( 0 ) , do: :VIPS_ANGLE_D0
5975+ defp rot_angle_from_degrees ( 90 ) , do: :VIPS_ANGLE_D90
5976+ defp rot_angle_from_degrees ( 180 ) , do: :VIPS_ANGLE_D180
5977+ defp rot_angle_from_degrees ( 270 ) , do: :VIPS_ANGLE_D270
5978+
59425979 @ doc """
59435980 Rotate an image clockwise (to the
59445981 right) by a number of degrees.
0 commit comments