
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@2927 fd906abe-77d9-0310-91a1-e0d9ade77398
170 lines
5.8 KiB
Python
170 lines
5.8 KiB
Python
#
|
|
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
#
|
|
|
|
"""
|
|
Media asset file adapter.
|
|
|
|
Authors: Johann Schimpf, Erich Seifert.
|
|
|
|
$Id$
|
|
"""
|
|
|
|
from logging import getLogger
|
|
import mimetypes
|
|
import os, re, sys
|
|
|
|
from zope import component
|
|
from zope.interface import implements
|
|
from cybertools.media.interfaces import IMediaAsset, IFileTransform
|
|
from cybertools.media.piltransform import PILTransform
|
|
from cybertools.storage.filesystem import FileSystemStorage
|
|
|
|
TRANSFORM_STATEMENT = re.compile(r"\s*(\+?)([\w]+[\w\d]*)\(([^\)]*)\)\s*")
|
|
|
|
DEFAULT_FORMATS = {
|
|
"image": "image/jpeg"
|
|
}
|
|
|
|
def parseTransformStatements(txStr):
|
|
""" Parse statements in transform chain strings."""
|
|
statements = TRANSFORM_STATEMENT.findall(txStr)
|
|
return statements
|
|
|
|
def getMimeBasetype(mimetype):
|
|
return mimetype.split("/",1)[0]
|
|
|
|
def getMimetypeExt(mimetype):
|
|
exts = mimetypes.guess_all_extensions(mimetype)
|
|
return exts and exts[-1] or ""
|
|
|
|
|
|
class MediaAssetFile(object):
|
|
""" Class for extracting metadata from assets and to create transformed
|
|
variants using file representations in subdirectories.
|
|
"""
|
|
|
|
implements(IMediaAsset)
|
|
|
|
def __init__(self, dataPath, rules, contentType):
|
|
self.dataPath = dataPath
|
|
self.rules = rules
|
|
self.mimeType = contentType
|
|
|
|
def getData(self, variant=None):
|
|
if variant == None:
|
|
return self.getOriginalData()
|
|
path = self.getPath(variant)
|
|
if not os.path.exists(path):
|
|
getLogger('Asset Manager').warn(
|
|
'Media asset directory for transformation %r not found.' % variant)
|
|
return ''
|
|
f = open(path, 'rb')
|
|
data =f.read()
|
|
f.close()
|
|
return data
|
|
|
|
def getContentType(self, variant=None):
|
|
contentType = self.getMimeType()
|
|
if variant == None:
|
|
return contentType
|
|
outputFormat = None
|
|
# Scan all statements for a defintion of an output format
|
|
optionsstr = self.rules.get(variant)
|
|
if optionsstr:
|
|
statements = parseTransformStatements(optionsstr)
|
|
for prefix, command, args in statements:
|
|
if command == "output":
|
|
outputFormat = args
|
|
break
|
|
# Return default type if no defintion was found
|
|
if not outputFormat:
|
|
baseType = getMimeBasetype(contentType)
|
|
return DEFAULT_FORMATS.get(baseType)
|
|
return outputFormat
|
|
|
|
def transform(self, rules=None):
|
|
if rules is None:
|
|
rules = self.rules
|
|
for variant, commands in rules.items():
|
|
self.createVariant(variant, commands)
|
|
|
|
def createVariant(self, variant, commands):
|
|
oldassetdir = self.getDataPath()
|
|
# get or create output directory
|
|
path = self.getPath(variant)
|
|
assetdir = os.path.dirname(path)
|
|
if not os.path.exists(assetdir):
|
|
os.makedirs(assetdir)
|
|
excInfo = None # Save info of exceptions that may occure
|
|
try:
|
|
mediaFile = PILTransform()
|
|
mediaFile.open(oldassetdir)
|
|
statements = parseTransformStatements(commands)
|
|
for prefix, command, args in statements:
|
|
if command == "rotate":
|
|
rotArgs = args.split(",")
|
|
angle = float(rotArgs[0])
|
|
resize = False
|
|
if len(rotArgs) > 1:
|
|
resize = bool(int(rotArgs[1]))
|
|
mediaFile.rotate(angle, resize)
|
|
elif command == "color":
|
|
mode = args
|
|
mediaFile.color(mode)
|
|
elif command == "crop":
|
|
dims = [float(i) for i in args.split(",")]
|
|
if dims and (2 <= len(dims) <= 4):
|
|
mediaFile.crop(*dims)
|
|
elif command == "size":
|
|
size = [int(i) for i in args.split(",")]
|
|
if size and len(size)==2:
|
|
mediaFile.resize(*size)
|
|
outputFormat = self.getContentType(variant)
|
|
mediaFile.save(path, outputFormat)
|
|
except Exception, e:
|
|
excInfo = sys.exc_info()
|
|
# Handle exceptions that have occured during the transformation
|
|
# in order to provide information on the affected asset
|
|
if excInfo:
|
|
eType, eValue, eTraceback = excInfo # Extract exception information
|
|
raise eType("Error transforming asset '%s': %s" %
|
|
(oldassetdir, eValue)), None, eTraceback
|
|
|
|
def getPath(self, variant):
|
|
pathOrig = self.getDataPath()
|
|
dirOrig, fileOrig = os.path.split(pathOrig)
|
|
pathTx = os.path.join(dirOrig, variant, self.getName())
|
|
outputFormat = self.getContentType(variant)
|
|
outputExt = getMimetypeExt(outputFormat)
|
|
pathTx = os.path.splitext(pathTx)[0] + outputExt
|
|
return pathTx
|
|
|
|
def getMimeType(self):
|
|
return self.mimeType
|
|
|
|
def getName(self):
|
|
return os.path.split(self.getDataPath())[1]
|
|
|
|
def getDataPath(self):
|
|
return self.dataPath
|
|
|
|
def getOriginalData(self):
|
|
f = self.getDataPath().open()
|
|
data = f.read()
|
|
f.close()
|
|
return data
|