Commit b7a67ca8 authored by Jérome Perrin's avatar Jérome Perrin

safeimage: py3

parent d1c314b5
...@@ -16,9 +16,8 @@ ...@@ -16,9 +16,8 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
############################################################################## ##############################################################################
from __future__ import print_function import io
import os, sys, shutil, tempfile import os, sys, shutil, tempfile
from six.moves import cStringIO as StringIO
from zLOG import LOG,ERROR,INFO,WARNING from zLOG import LOG,ERROR,INFO,WARNING
from OFS.Image import File, Image from OFS.Image import File, Image
import os, transaction import os, transaction
...@@ -44,7 +43,7 @@ class ZoomifyBase: ...@@ -44,7 +43,7 @@ class ZoomifyBase:
_v_tileGroupMappings = {} _v_tileGroupMappings = {}
qualitySetting = 80 qualitySetting = 80
tileSize = 256 tileSize = 256
my_file = StringIO() my_file = io.BytesIO()
def openImage(self): def openImage(self):
""" load the image data """ """ load the image data """
...@@ -62,15 +61,15 @@ class ZoomifyBase: ...@@ -62,15 +61,15 @@ class ZoomifyBase:
width, height = (self.originalWidth, self.originalHeight) width, height = (self.originalWidth, self.originalHeight)
self._v_scaleInfo = [(width, height)] self._v_scaleInfo = [(width, height)]
while (width > self.tileSize) or (height > self.tileSize): while (width > self.tileSize) or (height > self.tileSize):
width, height = (width / 2, height / 2) width, height = (width // 2, height // 2)
self._v_scaleInfo.insert(0, (width, height)) self._v_scaleInfo.insert(0, (width, height))
totalTiles=0 totalTiles=0
tier, rows, columns = (0,0,0) tier, rows, columns = (0,0,0)
for tierInfo in self._v_scaleInfo: for tierInfo in self._v_scaleInfo:
rows = height/self.tileSize rows = height // self.tileSize
if height % self.tileSize > 0: if height % self.tileSize > 0:
rows +=1 rows +=1
columns = width/self.tileSize columns = width // self.tileSize
if width%self.tileSize > 0: if width%self.tileSize > 0:
columns += 1 columns += 1
totalTiles += rows * columns totalTiles += rows * columns
...@@ -87,7 +86,7 @@ class ZoomifyBase: ...@@ -87,7 +86,7 @@ class ZoomifyBase:
width, height = (self.originalWidth, self.originalHeight) width, height = (self.originalWidth, self.originalHeight)
self._v_scaleInfo = [(width, height)] self._v_scaleInfo = [(width, height)]
while (width > self.tileSize) or (height > self.tileSize): while (width > self.tileSize) or (height > self.tileSize):
width, height = (width / 2, height / 2) width, height = (width // 2, height // 2)
self._v_scaleInfo.insert(0, (width, height)) self._v_scaleInfo.insert(0, (width, height))
# tile and tile group information # tile and tile group information
self.preProcess() self.preProcess()
...@@ -146,7 +145,7 @@ class ZoomifyBase: ...@@ -146,7 +145,7 @@ class ZoomifyBase:
xmlOutput = '<IMAGE_PROPERTIES WIDTH="%s" HEIGHT="%s" NUMTILES="%s" NUMIMAGES="1" VERSION="1.8" TILESIZE="%s" />' xmlOutput = '<IMAGE_PROPERTIES WIDTH="%s" HEIGHT="%s" NUMTILES="%s" NUMIMAGES="1" VERSION="1.8" TILESIZE="%s" />'
xmlOutput = xmlOutput % (str(self.originalWidth), xmlOutput = xmlOutput % (str(self.originalWidth),
str(self.originalHeight), str(numberOfTiles), str(self.tileSize)) str(self.originalHeight), str(numberOfTiles), str(self.tileSize))
return xmlOutput return xmlOutput.encode()
def saveXMLOutput(self): def saveXMLOutput(self):
""" save xml metadata about the tiles """ """ save xml metadata about the tiles """
...@@ -176,15 +175,14 @@ class ZoomifyBase: ...@@ -176,15 +175,14 @@ class ZoomifyBase:
lr_y = ul_y + self.tileSize lr_y = ul_y + self.tileSize
else: else:
lr_y = self.originalHeight lr_y = self.originalHeight
print("Going to open image")
imageRow = image.crop([0, ul_y, self.originalWidth, lr_y]) imageRow = image.crop([0, ul_y, self.originalWidth, lr_y])
saveFilename = root + str(tier) + '-' + str(row) + ext saveFilename = root + str(tier) + '-' + str(row) + ext
if imageRow.mode != 'RGB': if imageRow.mode != 'RGB':
imageRow = imageRow.convert('RGB') imageRow = imageRow.convert('RGB')
imageRow.save(os.path.join(tempfile.gettempdir(), saveFilename), imageRow.save(os.path.join(tempfile.gettempdir(), saveFilename),
'JPEG', quality=100) # see https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#jpeg-saving
print("os path exist : %r" % os.path.exists(os.path.join( # for quality, Values above 95 should be avoided;
tempfile.gettempdir(), saveFilename))) 'JPEG', quality=95)
if os.path.exists(os.path.join(tempfile.gettempdir(), saveFilename)): if os.path.exists(os.path.join(tempfile.gettempdir(), saveFilename)):
self.processRowImage(tier=tier, row=row) self.processRowImage(tier=tier, row=row)
row += 1 row += 1
...@@ -192,9 +190,8 @@ class ZoomifyBase: ...@@ -192,9 +190,8 @@ class ZoomifyBase:
def processRowImage(self, tier=0, row=0): def processRowImage(self, tier=0, row=0):
""" for an image, create and save tiles """ """ for an image, create and save tiles """
print('*** processing tier: ' + str(tier) + ' row: ' + str(row))
tierWidth, tierHeight = self._v_scaleInfo[tier] tierWidth, tierHeight = self._v_scaleInfo[tier]
rowsForTier = tierHeight/self.tileSize rowsForTier = tierHeight // self.tileSize
if tierHeight % self.tileSize > 0: if tierHeight % self.tileSize > 0:
rowsForTier +=1 rowsForTier +=1
root, ext = os.path.splitext(self._v_imageFilename) root, ext = os.path.splitext(self._v_imageFilename)
...@@ -261,7 +258,7 @@ class ZoomifyBase: ...@@ -261,7 +258,7 @@ class ZoomifyBase:
# a bug was discovered when a row was exactly 1 pixel in height # a bug was discovered when a row was exactly 1 pixel in height
# this extra checking accounts for that # this extra checking accounts for that
if imageHeight > 1: if imageHeight > 1:
tempImage = imageRow.resize((imageWidth/2, imageHeight/2), tempImage = imageRow.resize((imageWidth//2, imageHeight//2),
PIL_Image.ANTIALIAS) PIL_Image.ANTIALIAS)
tempImage.save(os.path.join(tempfile.gettempdir(), root + str(tier) tempImage.save(os.path.join(tempfile.gettempdir(), root + str(tier)
+ '-' + str(row) + ext)) + '-' + str(row) + ext))
...@@ -269,9 +266,9 @@ class ZoomifyBase: ...@@ -269,9 +266,9 @@ class ZoomifyBase:
rowImage = None rowImage = None
if tier > 0: if tier > 0:
if row % 2 != 0: if row % 2 != 0:
self.processRowImage(tier=(tier-1), row=((row-1)/2)) self.processRowImage(tier=(tier-1), row=((row-1)//2))
elif row == rowsForTier-1: elif row == rowsForTier-1:
self.processRowImage(tier=(tier-1), row=(row/2)) self.processRowImage(tier=(tier-1), row=(row//2))
def ZoomifyProcess(self, imageNames): def ZoomifyProcess(self, imageNames):
""" the method the client calls to generate zoomify metadata """ """ the method the client calls to generate zoomify metadata """
...@@ -335,7 +332,7 @@ class ZoomifyZopeProcessor(ZoomifyBase): ...@@ -335,7 +332,7 @@ class ZoomifyZopeProcessor(ZoomifyBase):
def openImage(self): def openImage(self):
""" load the image data """ """ load the image data """
return PIL_Image.open(self._v_imageObject.name) return PIL_Image.open(self._v_imageObject)
def createDefaultViewer(self): def createDefaultViewer(self):
""" add the default Zoomify viewer to the Zoomify metadata """ """ add the default Zoomify viewer to the Zoomify metadata """
...@@ -411,7 +408,7 @@ class ZoomifyZopeProcessor(ZoomifyBase): ...@@ -411,7 +408,7 @@ class ZoomifyZopeProcessor(ZoomifyBase):
tileFileName = self.getTileFileName(scaleNumber, column, row) tileFileName = self.getTileFileName(scaleNumber, column, row)
tileContainerName = self.getAssignedTileContainerName( tileContainerName = self.getAssignedTileContainerName(
tileFileName=tileFileName) tileFileName=tileFileName)
tileImageData = StringIO() tileImageData = io.BytesIO()
image.save(tileImageData, 'JPEG', quality=self.qualitySetting) image.save(tileImageData, 'JPEG', quality=self.qualitySetting)
tileImageData.seek(0) tileImageData.seek(0)
if hasattr(self._v_saveFolderObject, tileContainerName): if hasattr(self._v_saveFolderObject, tileContainerName):
...@@ -529,7 +526,7 @@ class ERP5ZoomifyZopeProcessor(ZoomifyZopeProcessor): ...@@ -529,7 +526,7 @@ class ERP5ZoomifyZopeProcessor(ZoomifyZopeProcessor):
param2 = 0 param2 = 0
my_text = '%s %s %s %s %s %s \n' %(tile_group_id, tile_title, my_text = '%s %s %s %s %s %s \n' %(tile_group_id, tile_title,
algorithm, param1, param2, num) algorithm, param1, param2, num)
self.my_file.write(my_text) self.my_file.write(my_text.encode())
num = num - 1 num = num - 1
...@@ -543,7 +540,7 @@ class ERP5ZoomifyZopeProcessor(ZoomifyZopeProcessor): ...@@ -543,7 +540,7 @@ class ERP5ZoomifyZopeProcessor(ZoomifyZopeProcessor):
if w != 0 and h !=0: if w != 0 and h !=0:
tile_group_id = self.getAssignedTileContainerName() tile_group_id = self.getAssignedTileContainerName()
tile_group=self.document[tile_group_id] tile_group=self.document[tile_group_id]
tileImageData= StringIO() tileImageData= io.BytesIO()
image.save(tileImageData, 'JPEG', quality=self.qualitySetting) image.save(tileImageData, 'JPEG', quality=self.qualitySetting)
tileImageData.seek(0) tileImageData.seek(0)
if tile_group is None: if tile_group is None:
...@@ -556,11 +553,11 @@ class ERP5ZoomifyZopeProcessor(ZoomifyZopeProcessor): ...@@ -556,11 +553,11 @@ class ERP5ZoomifyZopeProcessor(ZoomifyZopeProcessor):
def saveXMLOutput(self): def saveXMLOutput(self):
"""save the xml file""" """save the xml file"""
my_string = StringIO() my_file = io.BytesIO()
my_string.write(self.getXMLOutput()) my_file.write(self.getXMLOutput())
my_string.seek(0) my_file.seek(0)
self.document.newContent(portal_type='Embedded File', self.document.newContent(portal_type='Embedded File',
id='ImageProperties.xml', file=my_string, id='ImageProperties.xml', file=my_file,
filename='ImageProperties.xml') filename='ImageProperties.xml')
return return
......
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
import transaction import transaction
from io import FileIO from io import BytesIO
import os import os
class FileUpload(FileIO): class FileUpload(BytesIO):
"""Act as an uploaded file. """Act as an uploaded file.
""" """
__allow_access_to_unprotected_subobjects__ = 1 __allow_access_to_unprotected_subobjects__ = 1
def __init__(self, path, name): def __init__(self, path, name):
self.filename = name self.filename = name
super(FileUpload, self).__init__(path) with open(path, 'rb') as f:
super(FileUpload, self).__init__(f.read())
self.headers = {} self.headers = {}
def makeFilePath(name):
#return os.path.join(os.path.dirname(__file__), 'tmp', name)
return name
def makeFileUpload(name, as_name=None):
if as_name is None:
as_name = name
path = makeFilePath(name)
return FileUpload(path, as_name)
class TestSafeImage(ERP5TypeTestCase): class TestSafeImage(ERP5TypeTestCase):
def afterSetUp(self): def afterSetUp(self):
portal = self.getPortalObject() portal = self.getPortalObject()
...@@ -38,14 +29,21 @@ class TestSafeImage(ERP5TypeTestCase): ...@@ -38,14 +29,21 @@ class TestSafeImage(ERP5TypeTestCase):
transaction.commit() transaction.commit()
self.tic() self.tic()
def makeFileUpload(self, name, as_name=None):
if as_name is None:
as_name = name
fu = FileUpload(name, as_name)
self.addCleanup(fu.close)
return fu
def _createImage(self): def _createImage(self):
portal = self.getPortalObject() portal = self.getPortalObject()
image = portal.restrictedTraverse('portal_skins/erp5_safeimage/img/image_unit_test.jpg') image = portal.restrictedTraverse('portal_skins/erp5_safeimage/img/image_unit_test.jpg')
path_image = "image_unit_test.jpg" path_image = "image_unit_test.jpg"
fd = os.open(path_image, os.O_CREAT | os.O_RDWR) fd = os.open(path_image, os.O_CREAT | os.O_RDWR)
os.write(fd,str(image.data)) os.write(fd, bytes(image.data))
os.close(fd) os.close(fd)
_image = makeFileUpload(path_image) _image = self.makeFileUpload(path_image)
image = self.image_module.newContent(portal_type='Image',title='testImage', image = self.image_module.newContent(portal_type='Image',title='testImage',
id='testImage',file=_image,filename='testImage') id='testImage',file=_image,filename='testImage')
return image return image
...@@ -55,9 +53,9 @@ class TestSafeImage(ERP5TypeTestCase): ...@@ -55,9 +53,9 @@ class TestSafeImage(ERP5TypeTestCase):
image = portal.restrictedTraverse('portal_skins/erp5_safeimage/img/image_unit_test.jpg') image = portal.restrictedTraverse('portal_skins/erp5_safeimage/img/image_unit_test.jpg')
path_image = "image_unit_test.jpg" path_image = "image_unit_test.jpg"
fd = os.open(path_image, os.O_CREAT | os.O_RDWR) fd = os.open(path_image, os.O_CREAT | os.O_RDWR)
os.write(fd,str(image.data)) os.write(fd, bytes(image.data))
os.close(fd) os.close(fd)
tile_image = makeFileUpload(path_image) tile_image = self.makeFileUpload(path_image)
tile = self.image_module.newContent(portal_type='Image Tile',title='testTile', tile = self.image_module.newContent(portal_type='Image Tile',title='testTile',
id='testTile',file=tile_image,filename='testTile') id='testTile',file=tile_image,filename='testTile')
return tile return tile
...@@ -67,9 +65,9 @@ class TestSafeImage(ERP5TypeTestCase): ...@@ -67,9 +65,9 @@ class TestSafeImage(ERP5TypeTestCase):
image = portal.restrictedTraverse('portal_skins/erp5_safeimage/img/image_unit_test.jpg') image = portal.restrictedTraverse('portal_skins/erp5_safeimage/img/image_unit_test.jpg')
path_image = "image_unit_test.jpg" path_image = "image_unit_test.jpg"
fd = os.open(path_image, os.O_CREAT | os.O_RDWR) fd = os.open(path_image, os.O_CREAT | os.O_RDWR)
os.write(fd,str(image.data)) os.write(fd, bytes(image.data))
os.close(fd) os.close(fd)
tile_image_transformed = makeFileUpload(path_image) tile_image_transformed = self.makeFileUpload(path_image)
tile_transformed = self.image_module.newContent(portal_type='Image Tile Transformed', tile_transformed = self.image_module.newContent(portal_type='Image Tile Transformed',
title='testTileTransformed',id='testTileTransformed', title='testTileTransformed',id='testTileTransformed',
file=tile_image_transformed,filename='testTileTransformed') file=tile_image_transformed,filename='testTileTransformed')
...@@ -97,7 +95,7 @@ class TestSafeImage(ERP5TypeTestCase): ...@@ -97,7 +95,7 @@ class TestSafeImage(ERP5TypeTestCase):
self.assertNotEqual(tile,None) self.assertNotEqual(tile,None)
image_property = getattr(tile, "ImageProperties.xml", None) image_property = getattr(tile, "ImageProperties.xml", None)
self.assertEqual(image_property.getData(), self.assertEqual(image_property.getData(),
"""<IMAGE_PROPERTIES WIDTH="660" HEIGHT="495" NUMTILES="9" NUMIMAGES="1" VERSION="1.8" TILESIZE="256" />""") b"""<IMAGE_PROPERTIES WIDTH="660" HEIGHT="495" NUMTILES="9" NUMIMAGES="1" VERSION="1.8" TILESIZE="256" />""")
self.assertNotEqual(image_property, None) self.assertNotEqual(image_property, None)
self.assertEqual("Embedded File", image_property.getPortalType()) self.assertEqual("Embedded File", image_property.getPortalType())
image_group = getattr(tile, "TileGroup0", None) image_group = getattr(tile, "TileGroup0", None)
...@@ -127,7 +125,7 @@ class TestSafeImage(ERP5TypeTestCase): ...@@ -127,7 +125,7 @@ class TestSafeImage(ERP5TypeTestCase):
self.assertNotEqual(tile_transformed,None) self.assertNotEqual(tile_transformed,None)
image_property = getattr(tile_transformed, "ImageProperties.xml", None) image_property = getattr(tile_transformed, "ImageProperties.xml", None)
self.assertEqual(image_property.getData(), self.assertEqual(image_property.getData(),
"""<IMAGE_PROPERTIES WIDTH="660" HEIGHT="495" NUMTILES="9" NUMIMAGES="1" VERSION="1.8" TILESIZE="256" />""") b"""<IMAGE_PROPERTIES WIDTH="660" HEIGHT="495" NUMTILES="9" NUMIMAGES="1" VERSION="1.8" TILESIZE="256" />""")
self.assertNotEqual(image_property, None) self.assertNotEqual(image_property, None)
self.assertEqual("Embedded File", image_property.getPortalType()) self.assertEqual("Embedded File", image_property.getPortalType())
image_transform = getattr(tile_transformed, "TransformFile.txt", None) image_transform = getattr(tile_transformed, "TransformFile.txt", None)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment