Skip to content

Svg improvements, also more verbose images-test page #133

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions news/133.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- feature: "scale" SVGs by setting the correct height and width for the given scale in its metadata.
16 changes: 7 additions & 9 deletions plone/namedfile/scaling.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from Acquisition import aq_base
from DateTime import DateTime
from io import BytesIO
from plone.base.utils import safe_bytes
from plone.memoize import ram
from plone.namedfile.browser import ALLOWED_INLINE_MIMETYPES
from plone.namedfile.browser import DISALLOWED_INLINE_MIMETYPES
Expand All @@ -20,6 +19,7 @@
from plone.rfc822.interfaces import IPrimaryFieldInfo
from plone.scale.interfaces import IImageScaleFactory
from plone.scale.interfaces import IScaledImageQuality
from plone.scale.scale import scale_svg_image
from plone.scale.scale import scaleImage
from plone.scale.storage import IImageScaleStorage
from Products.CMFCore.utils import getToolByName
Expand Down Expand Up @@ -58,7 +58,7 @@ def _image_tag_from_values(*values):
for k, v in values:
if v is None:
continue
if isinstance(v, int):
if isinstance(v, (int, float)):
v = str(v)
elif isinstance(v, bytes):
v = str(v, "utf8")
Expand Down Expand Up @@ -327,14 +327,12 @@ def create_scale(self, data, mode, height, width, **parameters):
def handle_image(self, orig_value, orig_data, mode, height, width, **parameters):
"""Return a scaled image, its mimetype format, and width and height."""
if getattr(orig_value, "contentType", "") == "image/svg+xml":
# No need to scale, we can simply use the original data,
# but report a different width and height.
if isinstance(orig_data, (str)):
orig_data = safe_bytes(orig_data)
if isinstance(orig_data, (bytes)):
if isinstance(orig_data, bytes):
orig_data = BytesIO(orig_data)
result = orig_data.read(), "svg+xml", (width, height)
return result
if isinstance(orig_data, str):
orig_data = BytesIO(orig_data.encode("utf-8"))
scaled_data, size = scale_svg_image(orig_data, width, height, mode)
return scaled_data, "svg+xml", size
try:
result = self.create_scale(
orig_data, mode=mode, height=height, width=width, **parameters
Expand Down
100 changes: 67 additions & 33 deletions plone/namedfile/test.pt
Original file line number Diff line number Diff line change
Expand Up @@ -112,42 +112,76 @@
</section>
<hr />
<section id="examples">
<h2 i18n:translate="">Examples with mode</h2>
<h2 i18n:translate="">Examples with direction/mode</h2>
<p i18n:translate="">
There are three modes to scale an image:
<code>scale</code>,
<code>cover</code>
and
<code>contain</code>.
</p>
<p i18n:translate="">Scaling methods do never stretch/distort the image in one direction only.</p>

<h3 i18n:translate="">Mini</h3>
<figure class="figure"
tal:define="
img_tag python:images.tag('image', scale='mini');
"
>
<img tal:replace="structure img_tag" />
<br /><code tal:content="img_tag"></code>
</figure>
<h3 i18n:translate="">Mini direction=scale
<p i18n:translate="">
Scales to the requested dimensions without cropping.
The resulting image may have a different size than requested.
This option requires both, width and height, to be specified.
Does not scale up.
</p>
<p i18n:translate="">
Here direction is not explicit set, it uses by default
<code>direction="scale"</code>.
</p>
<p i18n:translate="">Deprecated spellings:
<code>keep</code>,
<code>thumbnail</code>.</p>
<figure class="figure"
tal:define="
img_tag python:images.tag('image', scale='mini');
"
>
<img tal:replace="structure img_tag" />
<br /><code tal:content="img_tag"></code>
</figure>

<h3 id="cover"
i18n:translate=""
>Mini mode=cover</h3>
<figure class="figure"
tal:define="
img_tag python:images.tag('image', scale='mini', mode='cover');
"
>
<img tal:replace="structure img_tag" />
<br /><code tal:content="img_tag"></code>
</figure>
<h3 id="cover"
i18n:translate=""
>Mini direction=cover</h3>
<p i18n:translate="">
Scales the relatively largest dimension up to the required size.
Despite the alternative spelling, I see no cropping happening.
</p>
<p i18n:translate="">Deprecated spellings:
<code>scale-crop-to-fill</code>,
<code>up</code>.</p>
<figure class="figure"
tal:define="
img_tag python:images.tag('image', scale='mini', mode='cover');
"
>
<img tal:replace="structure img_tag" />
<br /><code tal:content="img_tag"></code>
</figure>

<h3 id="contain"
i18n:translate=""
>Mini mode=contain</h3>
<figure class="figure"
tal:define="
img_tag python:images.tag('image', scale='mini', mode='contain');
"
>
<img tal:replace="structure img_tag" />
<br /><code tal:content="img_tag"></code>
</figure>
</section>
<h3 id="contain"
i18n:translate=""
>Mini direction=contain</h3>
<p i18n:translate="">
Starts by scaling the relatively smallest dimension to the required size and crops the other dimension if needed.
</p>
<p i18n:translate="">Deprecated spellings:
<code>scale-crop-to-fit</code>,
<code>down</code>.</p>
<figure class="figure"
tal:define="
img_tag python:images.tag('image', scale='mini', direction='contain');
"
>
<img tal:replace="structure img_tag" />
<br /><code tal:content="img_tag"></code>
</figure>
</h3></section>

<section id="picture">
<h2 i18n:translate="">Picture tags</h2>
Expand Down
6 changes: 5 additions & 1 deletion plone/namedfile/tests/test_scaling_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,11 @@ def testSVGPublishThumbViaName(self):
self.layer["app"].absolute_url() + "/svg/@@images/image/thumb"
)
self.assertEqual("image/svg+xml", self.browser.headers["content-type"])
self.assertEqual(self.browser.contents, data)
self.assertIn(b'width="128" height="32"', self.browser.contents)
self.assertEqual(self.browser.contents[:20], data[:20].replace(b'"', b"'"))
self.assertEqual(
self.browser.contents[-50:], data.replace(b"\r", b"").strip()[-50:]
)

def testImagesViewWithNoSubpath(self):
transaction.commit()
Expand Down
2 changes: 1 addition & 1 deletion plone/namedfile/utils.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Used in the widget itself to strip off any path, regardless of platform::
>>> safe_basename('/farmyard/cows/daisy')
'daisy'

>>> safe_basename('F:\FARMYARD\COWS\DAISY.TXT')
>>> safe_basename(r'F:\FARMYARD\COWS\DAISY.TXT')
'DAISY.TXT'

>>> safe_basename('Macintosh Farmyard:Cows:Daisy Text File')
Expand Down