+++ /dev/null
-# -*- coding: utf-8 -*-
-#######################################################################################
-# Photo is a part of Plinn - http://plinn.org #
-# Copyright (C) 2004-2007 BenoƮt PIN <benoit.pin@ensmp.fr> #
-# #
-# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #
-#######################################################################################
-""" Tile support module
-
-
-
-"""
-
-from AccessControl import ClassSecurityInfo
-from AccessControl import Unauthorized
-from AccessControl import getSecurityManager
-from AccessControl.Permissions import view, change_images_and_files
-from PIL import Image as PILImage
-from math import ceil
-from blobbases import Image
-from xmputils import TIFF_ORIENTATIONS
-from cache import memoizedmethod
-from BTrees.OOBTree import OOBTree
-from BTrees.IOBTree import IOBTree
-from ppm import PPMFile
-from threading import Lock
-from subprocess import Popen, PIPE
-from tempfile import TemporaryFile
-
-JPEG_ROTATE = 'jpegtran -rotate %d'
-JPEG_FLIP = 'jpegtran -flip horizontal'
-
-def runOnce(lock):
- """ Decorator. exit if already running """
-
- def wrapper(f):
- def method(*args, **kw):
- if not lock.locked() :
- lock.acquire()
- try:
- return f(*args, **kw)
- finally:
- lock.release()
- else :
- return False
- return method
- return wrapper
-
-
-
-class TileSupport :
- """ Mixin class to generate tiles from image """
-
- security = ClassSecurityInfo()
- tileSize = 256
- tileGenerationLock = Lock()
-
- def __init__(self) :
- self._tiles = OOBTree()
-
- security.declarePrivate('makeTilesAt')
- @runOnce(tileGenerationLock)
- def makeTilesAt(self, zoom):
- """generates tiles at zoom level"""
-
- if self._tiles.has_key(zoom) :
- return True
-
- assert zoom <= 1, "zoom arg must be <= 1 found: %s" % zoom
-
- ppm = self._getPPM()
- if zoom < 1 :
- ppm = ppm.resize(ratio=zoom)
-
- self._makeTilesAt(zoom, ppm)
- return True
-
- def _getPPM(self) :
- bf = self._getJpegBlob()
- f = bf.open('r')
-
- orientation = self.tiffOrientation()
- rotation, flip = TIFF_ORIENTATIONS.get(orientation, (0, False))
-
- if rotation and flip :
- tf = TemporaryFile(mode='w+')
- pRot = Popen(JPEG_ROTATE % rotation
- , stdin=f
- , stdout=PIPE
- , shell=True)
- pFlip = Popen(JPEG_FLIP
- , stdin=pRot.stdout
- , stdout=tf
- , shell=True)
- pFlip.wait()
- f.close()
- tf.seek(0)
- f = tf
-
- elif rotation :
- tf = TemporaryFile(mode='w+')
- pRot = Popen(JPEG_ROTATE % rotation
- , stdin=f
- , stdout=tf
- , shell=True)
- pRot.wait()
- f.close()
- tf.seek(0)
- f = tf
-
- elif flip :
- tf = TemporaryFile(mode='w+')
- pFlip = Popen(JPEG_FLIP
- , stdin=f
- , stdout=tf
- , shell=True)
- pFlip.wait()
- f.close()
- tf.seek(0)
- f = tf
-
- ppm = PPMFile(f, tileSize=self.tileSize)
- f.close()
- return ppm
-
- def _makeTilesAt(self, zoom, ppm):
- hooks = self._getAfterTilingHooks()
- self._tiles[zoom] = IOBTree()
- bgColor = getattr(self, 'tiles_background_color', '#fff')
-
- for x in xrange(ppm.tilesX) :
- self._tiles[zoom][x] = IOBTree()
- for y in xrange(ppm.tilesY) :
- tile = ppm.getTile(x, y)
- for hook in hooks :
- hook(self, tile)
-
- # fill with solid color
- if min(tile.size) < self.tileSize :
- blankTile = PILImage.new('RGB', (self.tileSize, self.tileSize), bgColor)
- box = (0,0) + tile.size
- blankTile.paste(tile, box)
- tile = blankTile
-
- zImg = Image('tile', 'tile', '', content_type='image/jpeg')
- out = zImg.open('w')
- tile.save(out, 'JPEG', quality=90)
- zImg.updateFormat(out.tell(), tile.size, 'image/jpeg')
- out.close()
-
- self._tiles[zoom][x][y] = zImg
-
- def _getAfterTilingHooks(self) :
- return []
-
-
- security.declareProtected(view, 'getAvailableZooms')
- def getAvailableZooms(self):
- zooms = list(self._tiles.keys())
- zooms.sort()
- return zooms
-
- security.declareProtected(view, 'getTile')
- def getTile(self, REQUEST, RESPONSE, zoom=1, x=0, y=0):
- """ publishes tile
- """
- zoom, x, y = float(zoom), int(x), int(y)
- if not self._tiles.has_key(zoom) :
- sm = getSecurityManager()
- if not sm.checkPermission(change_images_and_files, self) :
- raise Unauthorized("Tiling arbitrary zoom unauthorized")
- if self.makeTilesAt(zoom) :
- tile = self._tiles[zoom][x][y]
- return tile.index_html(REQUEST=REQUEST, RESPONSE=RESPONSE)
- else :
- tile = self._tiles[zoom][x][y]
- return tile.index_html(REQUEST=REQUEST, RESPONSE=RESPONSE)
-