Back to index

plone3  3.1.7
image.py
Go to the documentation of this file.
00001 #  ATContentTypes http://plone.org/products/atcontenttypes/
00002 #  Archetypes reimplementation of the CMF core types
00003 #  Copyright (c) 2003-2006 AT Content Types development team
00004 #
00005 #  This program is free software; you can redistribute it and/or modify
00006 #  it under the terms of the GNU General Public License as published by
00007 #  the Free Software Foundation; either version 2 of the License, or
00008 #  (at your option) any later version.
00009 #
00010 #  This program is distributed in the hope that it will be useful,
00011 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 #  GNU General Public License for more details.
00014 #
00015 #  You should have received a copy of the GNU General Public License
00016 #  along with this program; if not, write to the Free Software
00017 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 #
00019 """AT Image
00020 
00021 The basics for the EXIF information, orientation code and the rotation code
00022 were taken from CMFPhoto.
00023 """
00024 __author__  = 'Christian Heimes <tiran@cheimes.de>'
00025 __docformat__ = 'restructuredtext'
00026 __old_name__ = 'Products.ATContentTypes.types.ATImage'
00027 
00028 from Products.CMFCore.permissions import View
00029 from Products.CMFCore.permissions import ModifyPortalContent
00030 from AccessControl import ClassSecurityInfo
00031 from Acquisition import aq_base
00032 from ComputedAttribute import ComputedAttribute
00033 
00034 from Products.Archetypes.atapi import Schema
00035 from Products.Archetypes.atapi import ImageField
00036 from Products.Archetypes.atapi import ImageWidget
00037 from Products.Archetypes.atapi import PrimaryFieldMarshaller
00038 from Products.Archetypes.atapi import AnnotationStorage
00039 
00040 from Products.ATContentTypes.config import PROJECTNAME
00041 from Products.ATContentTypes.configuration import zconf
00042 from Products.ATContentTypes.content.base import registerATCT
00043 from Products.ATContentTypes.content.base import ATCTFileContent
00044 from Products.ATContentTypes.interfaces import IATImage
00045 from Products.ATContentTypes.content.schemata import ATContentTypeSchema
00046 from Products.ATContentTypes.content.schemata import finalizeATCTSchema
00047 from Products.ATContentTypes.lib.imagetransform import ATCTImageTransform
00048 
00049 from Products.ATContentTypes import ATCTMessageFactory as _
00050 
00051 from Products.validation.config import validation
00052 from Products.validation.validators.SupplValidators import MaxSizeValidator
00053 from Products.validation import V_REQUIRED
00054 
00055 validation.register(MaxSizeValidator('checkImageMaxSize',
00056                                      maxsize=zconf.ATImage.max_file_size))
00057 
00058 
00059 ATImageSchema = ATContentTypeSchema.copy() + Schema((
00060     ImageField('image',
00061                required=True,
00062                primary=True,
00063                languageIndependent=True,
00064                storage = AnnotationStorage(migrate=True),
00065                swallowResizeExceptions = zconf.swallowImageResizeExceptions.enable,
00066                pil_quality = zconf.pil_config.quality,
00067                pil_resize_algo = zconf.pil_config.resize_algo,
00068                max_size = zconf.ATImage.max_image_dimension,
00069                sizes= {'large'   : (768, 768),
00070                        'preview' : (400, 400),
00071                        'mini'    : (200, 200),
00072                        'thumb'   : (128, 128),
00073                        'tile'    :  (64, 64),
00074                        'icon'    :  (32, 32),
00075                        'listing' :  (16, 16),
00076                       },
00077                validators = (('isNonEmptyFile', V_REQUIRED),
00078                              ('checkImageMaxSize', V_REQUIRED)),
00079                widget = ImageWidget(
00080                         description = '',
00081                         label= _(u'label_image', default=u'Image'),
00082                         show_content_type = False,)),
00083 
00084     ), marshall=PrimaryFieldMarshaller()
00085     )
00086 
00087 # Title is pulled from the file name if we don't specify anything,
00088 # so it's not strictly required, unlike in the rest of ATCT.
00089 ATImageSchema['title'].required = False
00090 
00091 finalizeATCTSchema(ATImageSchema)
00092 
00093 
00094 class ATImage(ATCTFileContent, ATCTImageTransform):
00095     """An image, which can be referenced in documents or displayed in an album."""
00096 
00097     schema         =  ATImageSchema
00098 
00099     portal_type    = 'Image'
00100     archetype_name = 'Image'
00101     _atct_newTypeFor = {'portal_type' : 'CMF Image', 'meta_type' : 'Portal Image'}
00102     assocMimetypes = ('image/*', )
00103     assocFileExt   = ('jpg', 'jpeg', 'png', 'gif', )
00104     cmf_edit_kws   = ('file', )
00105 
00106     __implements__ = ATCTFileContent.__implements__, IATImage
00107 
00108     security       = ClassSecurityInfo()
00109 
00110     def exportImage(self, format, width, height):
00111         return '',''
00112 
00113     security.declareProtected(ModifyPortalContent, 'setImage')
00114     def setImage(self, value, refresh_exif=True, **kwargs):
00115         """Set id to uploaded id
00116         """
00117         # set exif first because rotation might screw up the exif data
00118         # the exif methods can handle str, Pdata, OFSImage and file
00119         # like objects
00120         self.getEXIF(value, refresh=refresh_exif)
00121         self._setATCTFileContent(value, **kwargs)
00122 
00123     security.declareProtected(View, 'tag')
00124     def tag(self, **kwargs):
00125         """Generate image tag using the api of the ImageField
00126         """
00127         return self.getField('image').tag(self, **kwargs)
00128 
00129     def __str__(self):
00130         """cmf compatibility
00131         """
00132         return self.tag()
00133 
00134     security.declareProtected(View, 'get_size')
00135     def get_size(self):
00136         """ZMI / Plone get size method
00137 
00138         BBB: ImageField.get_size() returns the size of the original image + all
00139         scales but we want only the size of the original image.
00140         """
00141         img = self.getImage()
00142         if not getattr(aq_base(img), 'get_size', False):
00143             return 0
00144         return img.get_size()
00145 
00146     security.declareProtected(View, 'getSize')
00147     def getSize(self, scale=None):
00148         field = self.getField('image')
00149         return field.getSize(self, scale=scale)
00150 
00151     security.declareProtected(View, 'getWidth')
00152     def getWidth(self, scale=None):
00153         return self.getSize(scale)[0]
00154 
00155     security.declareProtected(View, 'getHeight')
00156     def getHeight(self, scale=None):
00157         return self.getSize(scale)[1]
00158 
00159     width = ComputedAttribute(getWidth, 1)
00160     height = ComputedAttribute(getHeight, 1)
00161 
00162     security.declarePrivate('cmf_edit')
00163     def cmf_edit(self, precondition='', file=None, title=None):
00164         if file is not None:
00165             self.setImage(file)
00166         if title is not None:
00167             self.setTitle(title)
00168         self.reindexObject()
00169 
00170     def __bobo_traverse__(self, REQUEST, name):
00171         """Transparent access to image scales
00172         """
00173         if name.startswith('image'):
00174             field = self.getField('image')
00175             image = None
00176             if name == 'image':
00177                 image = field.getScale(self)
00178             else:
00179                 scalename = name[len('image_'):]
00180                 if scalename in field.getAvailableSizes(self):
00181                     image = field.getScale(self, scale=scalename)
00182             if image is not None and not isinstance(image, basestring):
00183                 # image might be None or '' for empty images
00184                 return image
00185 
00186         return ATCTFileContent.__bobo_traverse__(self, REQUEST, name)
00187 
00188 registerATCT(ATImage, PROJECTNAME)