Image-like content

Description

How to programmatically manipulate images on your Plone site.

Introduction

Plone supports image content in two forms:

  • As stand-alone content type, images will be visible in the sitemap. This is the case for the default Image content type, but you can create custom content types with similar properties.
  • As a field, the image is directly associated with one content object. Use Archetypes.fields.ImageField.

Custom image content type

If you want to have your custom content type behave like the stock Plone Image content type:

  • Inherit from the content class Products.ATContentType.content.image.ATImage and use the schema from that class.
  • When writing the GenericSetup XML of your type, follow the example of Image.xml.
  • Do not set workflow for your type in profiles/default/workflows.xml
<?xml version="1.0"?>
<object name="portal_workflow" meta_type="Plone Workflow Tool">

 <bindings>
  <type type_id="YourImageType"/>
 </bindings>
</object>

Image scales

Archetypes based content image scales is handled by plone.namedfile.

Dexterity based content image scales are handled by plone.namedfile.

Archetypes based content image scales is handled by plone.app.imaging.

Both packages offer the same traverseable @@images view which can be used from page templates and Python code to provide different image scales for image fields on content.

getScale()

ImageField provides a getScale() method to get the scaled version of the image based on the sizes configuration key.

See example in __bobo_traverse__:

Accessing images

ImageField is mapped to a traversable attribute of your content type. E.g. if your content object has a field imageOne and is found at this URL:

http://yoursite/content

the image can be directly downloaded from:

http://yoursite/content/imageOne

Scaled versions for Image content (ATImage)

If you want different scales you can add image_XXX prefix where XXX is the corresponding scale name:

http://yoursite/content/imageOne/image_preview

In Plone 4 this behavior comes from the monkey-patch applied by the plone.app.imaging package.

portal_catalog and images

Do not index image objects themselves, as adding image data to the portal_catalog brain objects would greatly increase their site and make brain look-up slow.

Instead, index only image paths using getPhysicalPath(). When you need to display image using metadata columns, you can generate the image URL manually. Then, the image object will be woken up when the browser makes a HTTP request for the image.

Custom image scales and recreating scale data

For Plone 4

plone.app.imaging allows you to configure available image scales in portal_properties -> imaging_properties.

You can update these through-the-web or using GenericSetup profile.

propertiestool.xml

<?xml version="1.0"?>
<object name="portal_properties" meta_type="Plone Properties Tool">
 <object name="imaging_properties" meta_type="Plone Property Sheet">
  <property name="title">Image handling properties</property>
  <property name="allowed_sizes" type="lines">
   <element value="large 768:768"/>
   <element value="preview 400:400"/>
   <element value="mini 200:200"/>
   <element value="thumb 128:128"/>
   <element value="tile 64:64"/>
   <element value="icon 32:32"/>
   <element value="listing 16:16"/>

   <!-- Include our custom sizes here -->
   <element value="custom1 290:290"/>
   <element value="custom2 210:210"/>
   <element value="custom_210_189 210:189"/>
   <element value="custom_290_258 290:256"/>

  </property>
 </object>
</object>

Note

For Plone 4, after adding new scales no batch processing of existing images are needed and new scales are created on-demand when the images are viewed for the first time.

Automatic image scales on ReferenceFields

Python code:

 from zope.component import adapts
 from zope.interface import implements, Interface
 from plone.app.imaging.interfaces import IImageScaleHandler


 def dereference(func_name):
     def new_func(self, instance, *args, **kw):
         if self.context is None:
             instance = self.reference_field.get(instance)
             self.context = instance.getPrimaryField()
         handler = IImageScaleHandler(self.context)
         func = getattr(handler, func_name)
         return func(instance, *args, **kw)
     return new_func


 class IReferenceField(Interface):
     """ marker """

 class ReferencedImageScaleHandler(object):
     """ proxy the standard image scale handler so that it operates on a referenced image """
     implements(IImageScaleHandler)
     adapts(IReferenceField)

     def __init__(self, context):
         self.reference_field = context
         self.context = None

     getScale = dereference('getScale')
     createScale = dereference('createScale')
     retrieveScale = dereference('retrieveScale')
storeScale = dereference('storeScale')

in configure.zcml:

<class class="Products.Archetypes.Field.ReferenceField">
  <implements interface=".IReferenceField"/>
</class>

<adapter
    factory=".ReferencedImageScaleHandler" />