diff options
Diffstat (limited to 'cgi/img.py')
-rw-r--r-- | cgi/img.py | 133 |
1 files changed, 76 insertions, 57 deletions
@@ -4,6 +4,7 @@ import math #import random import os import subprocess +import logging from StringIO import StringIO from settings import Settings @@ -30,6 +31,7 @@ def processImage(post, data, t, originalname, spoiler=False): # get image information content_type, width, height, size, extra = getImageInfo(data) + logging.info("{} {} {}".format(content_type, width, height)) # check the size is fine if size > int(board["maxsize"])*1024: @@ -87,66 +89,63 @@ def processImage(post, data, t, originalname, spoiler=False): # Do we need to thumbnail it? if not used_filetype['image']: # make thumbnail + logging.debug("Generating thumbnail") file_thumb_width, file_thumb_height = getThumbDimensions( width, height, maxsize) - - if used_filetype['ffmpeg_thumb'] == '1': - # use ffmpeg to make thumbnail - logTime("Generating thumbnail") - - if used_filetype['mime'][:5] == 'video': - retcode = subprocess.call([ - Settings.FFMPEG_PATH, '-strict', '-2', '-ss', '0', '-i', file_path, - '-v', 'quiet', '-an', '-vframes', '1', '-f', 'mjpeg', '-vf', 'scale=%d:%d' % ( - file_thumb_width, file_thumb_height), - '-threads', '1', file_thumb_path]) - if spoiler: - args = [Settings.CONVERT_PATH, file_thumb_path, "-limit", "thread", "1", "-background", "white", "-flatten", "-resize", "%dx%d" % (file_thumb_width, file_thumb_height), "-blur", "0x12", "-gravity", "center", "-fill", "rgba(0,0,0, .6)", "-draw", "rectangle 0,%d,%d,%d" % ( - (file_thumb_height/2)-10, file_thumb_width, (file_thumb_height/2)+7), "-fill", "white", "-annotate", "0", "Alerta de spoiler", "-quality", str(Settings.THUMB_QUALITY), file_thumb_path] - retcode = subprocess.call(args) - elif used_filetype['mime'][:5] == 'audio': - # we do an exception and use png for audio waveform thumbnails since they - # 1. are smaller 2. allow for transparency - file_thumb_name = file_thumb_name[:-3] + "png" - file_thumb_path = file_thumb_path[:-3] + "png" - file_mobile_path = file_mobile_path[:-3] + "png" - file_cat_path = file_cat_path[:-3] + "png" - - if int(board['thumb_px']) > 149: - file_thumb_width = board['thumb_px'] - file_thumb_height = float(int(board['thumb_px'])/2) - else: - file_thumb_width = 150 - file_thumb_height = 75 - - retcode = subprocess.call([ - Settings.FFMPEG_PATH, '-t', '300', '-i', file_path, - '-filter_complex', 'showwavespic=s=%dx%d:split_channels=1' % ( + + try: + if used_filetype['ffmpeg_thumb'] == '1': + # use ffmpeg to make thumbnail + if used_filetype['mime'][:5] == 'video': + # Create preview for video AND spoiler it if necessary + call_wrap([ + Settings.FFMPEG_PATH, '-strict', '-2', '-ss', '0', '-i', file_path, + '-v', 'quiet', '-an', '-vframes', '1', '-f', 'mjpeg', '-vf', 'scale=%d:%d' % ( + file_thumb_width, file_thumb_height), + '-threads', '1', file_thumb_path]) + if spoiler: + call_wrap([Settings.CONVERT_PATH, file_thumb_path, "-limit", "thread", + "1", "-background", "white", "-flatten", "-resize", + "%dx%d" % (file_thumb_width, file_thumb_height), "-blur", "0x12", + "-gravity", "center", "-fill", "rgba(0,0,0, .6)", + "-draw", "rectangle 0,%d,%d,%d" % ((file_thumb_height/2)-10, file_thumb_width, (file_thumb_height/2)+7), + "-fill", "white", "-font", "Liberation-Sans", "-annotate", "0", "Alerta de spoiler", + "-quality", str(Settings.THUMB_QUALITY), file_thumb_path]) + elif used_filetype['mime'][:5] == 'audio': + # we do an exception and use png for audio waveform thumbnails since they + # 1. are smaller 2. allow for transparency + file_thumb_name = file_thumb_name[:-3] + "png" + file_thumb_path = file_thumb_path[:-3] + "png" + file_mobile_path = file_mobile_path[:-3] + "png" + file_cat_path = file_cat_path[:-3] + "png" + + if int(board['thumb_px']) > 149: + file_thumb_width = board['thumb_px'] + file_thumb_height = float(int(board['thumb_px'])/2) + else: + file_thumb_width = 150 + file_thumb_height = 75 + + call_wrap([Settings.FFMPEG_PATH, '-t', '300', '-i', file_path, + '-filter_complex', 'showwavespic=s=%dx%d:split_channels=1' % ( int(file_thumb_width), int(file_thumb_height)), - '-frames:v', '1', '-threads', '1', file_thumb_path]) -# elif used_filetype['mime'] == 'application/x-shockwave-flash' or used_filetype['mime'] == 'mime/x-shockwave-flash': -# retcode = subprocess.call([ -# './ffmpeg', '-i', file_path, '-vcodec', 'mjpeg', '-vframes', '1', '-an', '-f', 'rawvideo', -# '-vf', 'scale=%d:%d' % (file_thumb_width, file_thumb_height), '-threads', '1', file_thumb_path]) - - if retcode != 0: - os.remove(file_path) - raise UserError, _("Thumbnail creation failure.") + ' ('+str(retcode)+')' - else: - # use imagemagick to make thumbnail - args = [Settings.CONVERT_PATH, file_path, "-limit", "thread", "1", "-background", - "white", "-flatten", "-resize", "%dx%d" % (file_thumb_width, file_thumb_height)] - if spoiler: - args += ["-blur", "0x12", "-gravity", "center", "-fill", "rgba(0,0,0, .6)", "-draw", "rectangle 0,%d,%d,%d" % ( - (file_thumb_height/2)-10, file_thumb_width, (file_thumb_height/2)+7), "-fill", "white", "-annotate", "0", "Alerta de spoiler"] - args += ["-quality", str(Settings.THUMB_QUALITY), file_thumb_path] - - # generate thumbnails - logTime("Generating thumbnail") - retcode = subprocess.call(args) - if retcode != 0: - os.remove(file_path) - raise UserError, _("Thumbnail creation failure.") + ' ('+str(retcode)+')' + '-frames:v', '1', '-threads', '1', file_thumb_path]) + else: + # use imagemagick to make thumbnail + args = [Settings.CONVERT_PATH, file_path, "-limit", "thread", "1", "-background", + "white", "-flatten", "-resize", "%dx%d" % (file_thumb_width, file_thumb_height)] + if spoiler: + args += ["-blur", "0x12", "-gravity", "center", "-fill", "rgba(0,0,0, .6)", "-draw", "rectangle 0,%d,%d,%d" % ( + (file_thumb_height/2)-10, file_thumb_width, (file_thumb_height/2)+7), "-fill", "white", + "-font", "Liberation-Sans", "-annotate", "0", "Alerta de spoiler"] + args += ["-quality", str(Settings.THUMB_QUALITY), file_thumb_path] + + # generate thumbnails + call_wrap(args) + except subprocess.CalledProcessError, e: + os.remove(file_path) + logging.error("Thumbnail creation failure: " + e.output) + raise UserError, _("Thumbnail creation failure.") + ' ('+str(e.returncode)+')' # check if thumbnail was truly created try: @@ -293,6 +292,22 @@ def getImageInfo(data): except ValueError: pass + # handle WebP + if data[:4] == b'RIFF' and data[8:12] == b'WEBP': + chunk = data[12:] + if chunk[:4] == b"VP8 " and chunk[11:14] == b"\x9d\x01\x2a": + # Lossy VP8 + w, h = struct.unpack("HH", chunk[14:18]) + width = w & 0x3fff + height = h & 0x3fff + content_type = "image/webp" + elif chunk[:4] == b"VP8L": + # Lossless VP8 + b0, b1, b2, b3 = struct.unpack("BBBB", chunk[9:13]) + width = 1 + (((b1 & 0x3F) << 8) | b0) + height = 1 + (((b3 & 0xF) << 10) | (b2 << 2) | ((b1 & 0xC0) >> 6)) + content_type = "image/webp" + # handle WebM elif (size >= 4) and data.startswith("\x1A\x45\xDF\xA3"): content_type = "video/webm" @@ -371,6 +386,10 @@ def ffprobe_f(filename): return json.loads(out) +def call_wrap(args): + subprocess.check_output(args, stderr=subprocess.STDOUT) + + def getThumbDimensions(width, height, maxsize): """ Calculate dimensions to use for a thumbnail with maximum width/height of |