-
Notifications
You must be signed in to change notification settings - Fork 5
/
img.py
174 lines (148 loc) · 5.29 KB
/
img.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import struct
import math
import random
import os
from StringIO import StringIO
from settings import Settings
from database import *
from framework import *
def processImage(post, data, t):
"""
Take all post data from <post>, process uploaded file in <data>, and calculate
file names using datetime <t>
Returns updated <post> with file and thumb values
"""
board = Settings._.BOARD
content_type, width, height = getImageInfo(data)
if content_type in ["image/png", "image/jpeg", "image/gif"]:
is_not_duplicate = checkFileNotDuplicate(data)
if is_not_duplicate[0]:
if content_type == "image/png":
file_extension = ".png"
elif content_type == "image/jpeg":
file_extension = ".jpg"
elif content_type == "image/gif":
file_extension = ".gif"
file_name = str(timestamp(t)) + str(random.randint(10, 99))
file_thumb_name = file_name + "s" + file_extension
file_name += file_extension
file_path = Settings.ROOT_DIR + board["dir"] + "/src/" + file_name
file_thumb_path = Settings.ROOT_DIR + board["dir"] + "/thumb/" + file_thumb_name
f = open(file_path, "w")
try:
f.write(data)
finally:
f.close()
if post["parentid"] == 0:
maxsize = Settings.MAX_DIMENSION_FOR_OP_IMAGE
else:
maxsize = Settings.MAX_DIMENSION_FOR_REPLY_IMAGE
file_thumb_width, file_thumb_height = getThumbDimensions(width, height, maxsize)
logTime("Generating thumbnail")
os.system("convert %s -resize %dx%d -quality 90 %s" % (file_path, file_thumb_width, file_thumb_height, file_thumb_path))
try:
open(file_thumb_path)
except:
raise Exception, "Thumbnail creation failed"
post["file"] = file_name
post["image_width"] = width
post["image_height"] = height
post["thumb"] = file_thumb_name
post["thumb_width"] = file_thumb_width
post["thumb_height"] = file_thumb_height
post["file_size"] = len(data)
if Settings.IMAGE_SIZE_UNIT == "B":
post["file_size_formatted"] = str(post["file_size"]) + " B"
else:
post["file_size_formatted"] = str(long(post["file_size"] / 1024)) + " KB"
post["file_hex"] = getMD5(data)
return post
else:
raise Exception, 'That image has already been posted <a href="' + Settings.BOARDS_URL + board['dir'] + '/res/' + str(is_not_duplicate[1]) + '.html#' + str(is_not_duplicate[2]) + '">here</a>.'
else:
raise Exception, "Invalid file type"
def getImageInfo(data):
data = str(data)
size = len(data)
height = -1
width = -1
content_type = ""
# handle GIFs
if (size >= 10) and data[:6] in ("GIF87a", "GIF89a"):
# Check to see if content_type is correct
content_type = "image/gif"
w, h = struct.unpack("<HH", data[6:10])
width = int(w)
height = int(h)
# See PNG 2. Edition spec (http://www.w3.org/TR/PNG/)
# Bytes 0-7 are below, 4-byte chunk length, then 'IHDR'
# and finally the 4-byte width, height
elif ((size >= 24) and data.startswith("\211PNG\r\n\032\n")
and (data[12:16] == "IHDR")):
content_type = "image/png"
w, h = struct.unpack(">LL", data[16:24])
width = int(w)
height = int(h)
# Maybe this is for an older PNG version.
elif (size >= 16) and data.startswith("\211PNG\r\n\032\n"):
# Check to see if we have the right content type
content_type = "image/png"
w, h = struct.unpack(">LL", data[8:16])
width = int(w)
height = int(h)
# handle JPEGs
elif (size >= 2) and data.startswith("\377\330"):
content_type = "image/jpeg"
jpeg = StringIO(data)
jpeg.read(2)
b = jpeg.read(1)
try:
while (b and ord(b) != 0xDA):
while (ord(b) != 0xFF): b = jpeg.read
while (ord(b) == 0xFF): b = jpeg.read(1)
if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
jpeg.read(3)
h, w = struct.unpack(">HH", jpeg.read(4))
break
else:
jpeg.read(int(struct.unpack(">H", jpeg.read(2))[0])-2)
b = jpeg.read(1)
width = int(w)
height = int(h)
except struct.error:
pass
except ValueError:
pass
return content_type, width, height
def getThumbDimensions(width, height, maxsize):
"""
Calculate dimensions to use for a thumbnail with maximum width/height of
<maxsize>, keeping aspect ratio
"""
wratio = (float(maxsize) / float(width))
hratio = (float(maxsize) / float(height))
if (width <= maxsize) and (height <= maxsize):
return width, height
else:
if (wratio * height) < maxsize:
thumb_height = math.ceil(wratio * height)
thumb_width = maxsize
else:
thumb_width = math.ceil(hratio * width)
thumb_height = maxsize
return int(thumb_width), int(thumb_height)
def checkFileNotDuplicate(data):
"""
Check that the file <data> does not already exist in a live post on the
current board by calculating its hex and checking it against the database
"""
board = Settings._.BOARD
file_hex = getMD5(data)
post = FetchOne("SELECT `id`, `parentid` FROM `posts` WHERE `file_hex` = '%s' AND `boardid` = %s LIMIT 1" % (file_hex, board['id']))
if post:
if int(post["parentid"]) != 0:
return False, post["parentid"], post["id"]
else:
return False, post["id"], post["id"]
else:
return True, 0, 0