X-Git-Url: https://scm.cri.ensmp.fr/git/Photo.git/blobdiff_plain/b0a7e10b4f32cf74864bb53268ca4d3080f23bc0:/ppm.py..6c41809185e322ce2d30e98234f71144f78f06c0:/Products/Photo/static/git-favicon.png diff --git a/ppm.py b/ppm.py deleted file mode 100755 index c1a31df..0000000 --- a/ppm.py +++ /dev/null @@ -1,198 +0,0 @@ -# -*- coding: utf-8 -*- -####################################################################################### -# Plinn - http://plinn.org # -# Copyright © 2009 Benoît Pin # -# # -# 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. # -####################################################################################### -""" PPM File support module - - - -""" - -from subprocess import Popen, PIPE -from tempfile import TemporaryFile -import os -from math import ceil -from PIL.Image import open as imgopen -from PIL.Image import fromstring -from PIL.Image import ANTIALIAS -from cStringIO import StringIO - -DGJPEG = 'djpeg' -RESIZING_TILE_SIZE = 1024 - -class PPMFile(object) : - - def __init__(self, f, tileSize=256, isRaw=False) : - # convert jpeg -> ppm with djpeg - if not isRaw : - # print 'djpeg' - self.fp = TemporaryFile(mode='w+') - p = Popen(DGJPEG, stdin=f, stdout=self.fp, stderr=PIPE, shell=True) - p.wait() - err = p.stderr.read() - if err : - raise SystemError, err - else : - self.fp = f - - # get image specs with PIL - self.fp.seek(0) - im = imgopen(self.fp) - decoder, region, offset, parameters = im.tile[0] - x, y, width, height = region - del im - assert decoder == 'raw' - mode = parameters[0] - assert mode in ('RGB', 'L'), "Unsupported mode %s" % mode - - if mode == 'RGB' : - sampleSize = 3 - elif mode == 'L' : - sampleSize = 1 - - self.width = width - self.height = height - self.offset = offset - self.mode = parameters[0] - self.sampleSize = sampleSize - self._setTileSize(tileSize) - - def _setTileSize(self, tileSize) : - self.tileSize = tileSize - self.tilesX = int(ceil(float(self.width) / self.tileSize)) - self.tilesY = int(ceil(float(self.height) / self.tileSize)) - - def getTile(self, xt, yt) : - f = self.fp - ss = self.sampleSize - x = xt * self.tileSize - y = yt * self.tileSize - start = (self.width * y + x) * ss + self.offset - - tw = th = self.tileSize - - bw = self.width - x - if bw < self.tileSize : - tw = bw - bh = self.height - y - if bh < self.tileSize : - th = bh - - assert tw > 0 and th > 0, "Tile requested out of image." - - size = (tw, th) - tll = tw * ss - jump = (self.width - tw) * ss - - f.seek(start) - data = StringIO() - - for line in xrange(size[1]) : - data.write(f.read(tll)) - f.seek(jump, 1) - - data.seek(0) - im = fromstring(self.mode, size, data.read()) - return im - - def getTileSequence(self): - seq = [] - for y in xrange(self.tilesY) : - for x in xrange(self.tilesX) : - seq.append((x, y)) - return seq - - def resize(self, ratio=None, maxLength=None) : - if ratio and maxLength : - raise AttributeError("'ratio' and 'size' are mutually exclusive.") - if maxLength : - maxFullLength = max(self.width, self.height) - ratio = float(maxLength) / maxFullLength - - tileSizeBak = self.tileSize - - self._setTileSize(RESIZING_TILE_SIZE) - - width = height = 0 - # cumul des arrondis - width = int(round(self.tileSize * ratio)) * (self.tilesX -1) - width += int(round((self.width - self.tileSize * (self.tilesX -1)) * ratio)) - - height = int(round(self.tileSize * ratio)) * (self.tilesY -1) - height += int(round((self.height - self.tileSize * (self.tilesY -1)) * ratio)) - - magic = self.mode == 'RGB' and 6 or 5 - head = 'P%d %d %d 255\n' % (magic, width, height) - offset = len(head) - - out = TemporaryFile(mode='w+') - out.write(head) - - ss = self.sampleSize - rTll = int(round(self.tileSize * ratio)) - - for x, y in self.getTileSequence() : - # print 'resize', (x,y) - tile = self.getTile(x,y) - tileSize = tile.size - size = map(lambda l : int(round(l * ratio)), tileSize) - - if size[0] and size[1] : - resized = tile.resize(size, ANTIALIAS) - data = resized.tostring() - - start = (y * width + x) * ss * rTll + offset - jump = (width - size[0]) * ss - - out.seek(start) - tll = size[0] * ss - - # écriture dans le bon ordre (c'est quand même plus agréable à l'œil) - for l in xrange(size[1]) : - lineData = data[l*tll:(l+1)*tll] - out.write(lineData) - out.seek(jump, 1) - - out.seek(0,2) - length = out.tell() - assert length - len(head) == width * height * ss, (length - len(head), width * height * ss) - out.seek(0) - - self._setTileSize(tileSizeBak) - return PPMFile(out, tileSize=tileSizeBak, isRaw=True) - - def getImage(self) : - self.fp.seek(0) - return imgopen(self.fp) - - def __del__(self) : - self.fp.close() - - -if __name__ == '__main__' : - f = open('/Users/pinbe/Desktop/Chauve_souris.jpg') - try : - ppm = PPMFile(f, tileSize=256) - rppm = ppm.resize(maxLength=800) - im = rppm.getImage() - im.show() - for x, y in ppm.getTileSequence() : - im = ppm.getTile(x, y) - im.save('testoutput/%d_%d.jpg' % (x, y), 'JPEG', quality=90) - finally : - f.close()