22from PIL import Image , UnidentifiedImageError
33import pyexiv2
44import uuid
5+ import xml .dom .minidom
56import sys
7+ import subprocess
68import math
79import os
10+ import re
811
912sys .path .append ("/data/project/datbot/Tasks/NonFreeImageResizer" )
13+ svgMatch = re .compile (r"^\s*(-?\d+(?:\.\d+)?)\s*(px|in|cm|mm|pt|pc|%)?" )
1014
1115# CC-BY-SA Theopolisme, DatGuy
1216# Task 3 on DatBot
1317
1418
19+ def parseLength (value ):
20+ # Adapted from https://github.com/Zverik/svg-resize/blob/master/svg_resize.py
21+ if not value :
22+ return 0.0
23+ parts = svgMatch .match (value )
24+ if not parts :
25+ raise Exception ('Unknown length format: "{}"' .format (value ))
26+ num = float (parts .group (1 ))
27+ units = parts .group (2 ) or "px"
28+ if units == "px" :
29+ return num
30+ elif units == "pt" :
31+ return num * 1.25
32+ elif units == "pc" :
33+ return num * 15.0
34+ elif units == "in" :
35+ return num * 90.0
36+ elif units == "mm" :
37+ return num * 3.543307
38+ elif units == "cm" :
39+ return num * 35.43307
40+ elif units == "%" :
41+ return - num / 100.0
42+ else :
43+ raise Exception ("Unknown length units: {}" .format (units ))
44+
45+
46+ def calculateNewSize (origWidth , origHeight ):
47+ newWidth = int (math .sqrt ((100000.0 * origWidth ) / origHeight ))
48+ widthPercent = newWidth / origWidth
49+ newHeight = int (origHeight * widthPercent )
50+
51+ originalPixels = origWidth * origHeight
52+ modifiedPixels = newWidth * newHeight
53+ percentChange = 100.0 * (originalPixels - modifiedPixels ) / float (originalPixels )
54+ return newWidth , newHeight , percentChange
55+
56+
1557def updateMetadata (sourcePath , destPath , image ):
1658 """This function moves the metadata
1759 from the old image to the new, reduced
@@ -34,53 +76,81 @@ def downloadImage(randomName, origName, site):
3476 """
3577 extension = os .path .splitext (origName )[1 ]
3678 extensionLower = extension [1 :].lower ()
79+ fullName = randomName + extension
3780
38- if extensionLower == "jpg" :
39- extensionLower = "jpeg"
40- elif extensionLower == "gif" :
81+ if extensionLower == "gif" :
4182 return "SKIP"
42-
4383 mwImage = site .Images [origName ]
4484
4585 tempFile = str (uuid .uuid4 ()) + extension
4686 with open (tempFile , "wb" ) as f :
4787 mwImage .download (f )
48-
4988 try :
50- fullName = randomName + extension
51- img = Image .open (tempFile )
52- imgWidth = img .size [0 ]
53- imgHeight = img .size [1 ]
54- if (imgWidth * imgHeight ) > 80000000 :
55- img .close ()
56- return "BOMB"
57-
58- baseWidth = int (math .sqrt ((100000.0 * float (imgWidth )) / (imgHeight )))
59- widthPercent = baseWidth / float (imgWidth )
60- heightSize = int ((float (imgHeight ) * float (widthPercent )))
61-
62- originalPixels = imgWidth * imgHeight
63- modifiedPixels = baseWidth * heightSize
64- percentChange = 100.0 * (originalPixels - modifiedPixels ) / float (originalPixels )
65- if percentChange > 5 :
89+ # Maybe move this all to seperate functions?
90+ if extensionLower == "svg" :
91+ subprocess .check_call (
92+ "scour -i {} --enable-viewboxing --enable-id-stripping "
93+ "--shorten-ids --indent=none" .format (tempFile )
94+ )
95+ docElement = xml .dom .minidom .parse (tempFile ).documentElement
96+ oldWidth = parseLength (docElement .getAttribute ("width" ))
97+ oldHeight = parseLength (docElement .getAttribute ("height" ))
98+
99+ viewboxArray = re .split ("[ ,\t ]+" , docElement .getAttribute ("viewBox" ))
100+ viewboxOffsetX , viewboxOffsetY = 0 , 0
101+
102+ if oldHeight == 0.0 and oldWidth == 0.0 :
103+ viewboxOffsetX = parseLength (viewboxArray [0 ])
104+ viewboxOffsetY = parseLength (viewboxArray [1 ])
105+ oldHeight = parseLength (viewboxArray [2 ])
106+ oldWidth = parseLength (viewboxArray [3 ])
107+
108+ newWidth , newHeight , percentChange = calculateNewSize (oldWidth , oldHeight )
109+ if percentChange < 5 :
110+ print ("Looks like we'd have a less than 5% change "
111+ "in pixel counts. Skipping." )
112+ return "PIXEL"
113+
114+ docElement .setAttribute ("width" , str (newWidth ))
115+ docElement .setAttribute ("height" , str (newHeight ))
116+ docElement .setAttribute (
117+ "viewBox" ,
118+ "{} {} {} {}" .format (
119+ viewboxOffsetX , viewboxOffsetY , newWidth , newHeight
120+ ),
121+ )
122+
123+ with open (fullName , "wb" ) as f :
124+ docElement .writexml (f , encoding = "utf-8" )
125+
126+ else :
127+ img = Image .open (tempFile )
128+ imgWidth = img .size [0 ]
129+ imgHeight = img .size [1 ]
130+ if (imgWidth * imgHeight ) > 80000000 :
131+ img .close ()
132+ return "BOMB"
133+
134+ newWidth , newHeight = calculateNewSize (imgWidth , imgHeight )
135+ if percentChange < 5 :
136+ img .close ()
137+ print ("Looks like we'd have a less than 5% change in pixel counts. Skipping." )
138+ return "PIXEL"
139+
66140 originalMode = img .mode
67141 if originalMode in ["1" , "L" , "P" ]:
68142 img = img .convert ("RGBA" )
69143
70- img = img .resize ((int (baseWidth ), int (heightSize )), Image .ANTIALIAS )
144+ img = img .resize ((int (newWidth ), int (newHeight )), Image .ANTIALIAS )
71145 if originalMode in ["1" , "L" , "P" ]:
72146 img = img .convert (originalMode , palette = Image .ADAPTIVE )
73147
74148 img .save (fullName , ** img .info , quality = 95 )
75- else :
76- img .close ()
77- print ("Looks like we'd have a less than 5% change in pixel counts. Skipping." )
78- return "PIXEL"
149+
79150 except UnidentifiedImageError as e :
80151 print ("Unable to open image {0} - aborting ({1})" .format (origName , e ))
81152 return "ERROR"
82153 except IOError as e :
83- img .close ()
84154 print ("Unable to open image {0} - aborting ({1})" .format (origName , e ))
85155 return "ERROR"
86156
0 commit comments