@@ -134,7 +134,7 @@ defmodule Mudbrick do
134134 ## Options
135135
136136 - `:position` - `{x, y}` in points, relative to bottom-left corner.
137- - `:scale` - `{w, h}` in points.
137+ - `:scale` - `{w, h}` in points. To preserve aspect ratio, set either, but not both, to `:auto`.
138138 - `:skew` - `{x, y}`, passed through to PDF `cm` operator.
139139
140140 All options default to `{0, 0}`.
@@ -145,24 +145,43 @@ defmodule Mudbrick do
145145 ...> |> Mudbrick.page()
146146 ...> |> Mudbrick.image(:lovely_flower, position: {100, 100}, scale: {100, 100})
147147
148+ Forgetting to register the image:
149+
148150 iex> Mudbrick.new()
149151 ...> |> Mudbrick.page()
150152 ...> |> Mudbrick.image(:my_face, position: {100, 100}, scale: {100, 100})
151153 ** (Mudbrick.Image.Unregistered) Unregistered image: my_face
152154
155+ Auto height:
156+
157+ iex> Mudbrick.new(images: %{lovely_flower: [file: Mudbrick.TestHelper.flower()]})
158+ ...> |> Mudbrick.page(size: {50, 50})
159+ ...> |> Mudbrick.image(:lovely_flower, position: {0, 0}, scale: {50, :auto})
160+ ...> |> Mudbrick.render()
161+ ...> |> then(&File.write("examples/image_auto_aspect_scale.pdf", &1))
162+
163+ <object width="400" height="100" data="examples/image_auto_aspect_scale.pdf?#navpanes=0" type="application/pdf"></object>
164+
165+ Attempting to set both width and height to `:auto`:
166+
167+ iex> Mudbrick.new(images: %{lovely_flower: [file: Mudbrick.TestHelper.flower()]})
168+ ...> |> Mudbrick.page()
169+ ...> |> Mudbrick.image(:lovely_flower, position: {100, 100}, scale: {:auto, :auto})
170+ ** (Mudbrick.Image.AutoScalingError) Auto scaling works with width or height, but not both.
171+
153172 Tip: to make the image fit the page, pass e.g. `Page.size(:a4)` as the
154173 `scale` and `{0, 0}` as the `position`.
155174 """
156175
157- @ spec image ( context ( ) , atom ( ) , ContentStream.Cm . options ( ) ) :: context ( )
176+ @ spec image ( context ( ) , atom ( ) , Image . image_options ( ) ) :: context ( )
158177 def image ( { doc , _content_stream_obj } = context , user_identifier , opts \\ [ ] ) do
159178 import ContentStream
160179
161180 case Map . fetch ( Document . root_page_tree ( doc ) . value . images , user_identifier ) do
162181 { :ok , image } ->
163182 context
164183 |> add ( % ContentStream.QPush { } )
165- |> add ( ContentStream.Cm . new ( opts ) )
184+ |> add ( ContentStream.Cm . new ( cm_opts ( image . value , opts ) ) )
166185 |> add ( % ContentStream.Do { image: image . value } )
167186 |> add ( % ContentStream.QPop { } )
168187
@@ -282,6 +301,29 @@ defmodule Mudbrick do
282301 end )
283302 end
284303
304+ @ spec cm_opts ( Mudbrick.Image . t ( ) , Image . image_options ( ) ) :: Mudbrick.ContentStream.Cm . options ( )
305+ defp cm_opts ( image , image_opts ) do
306+ scale =
307+ case image_opts [ :scale ] do
308+ { :auto , :auto } ->
309+ raise Mudbrick.Image.AutoScalingError ,
310+ "Auto scaling works with width or height, but not both."
311+
312+ { w , :auto } ->
313+ ratio = w / image . width
314+ { w , image . height * ratio }
315+
316+ { :auto , h } ->
317+ ratio = h / image . height
318+ { image . width * ratio , h }
319+
320+ otherwise ->
321+ otherwise
322+ end
323+
324+ Keyword . put ( image_opts , :scale , scale )
325+ end
326+
285327 defp fetch_font ( doc , opts ) do
286328 Keyword . update ( opts , :font , nil , fn user_identifier ->
287329 case Map . fetch ( Document . root_page_tree ( doc ) . value . fonts , user_identifier ) do
0 commit comments