From a89cec6844b6677ced6fe689c15ae0517072e801 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Sat, 25 Feb 2012 16:14:27 -0600 Subject: [PATCH] Image resize and grayscale support for CLI when PIL is installed. CLI warning. --- defaults.ini | 17 ++++++++++ downloader.py | 10 ++++++ fanficdownloader/story.py | 67 ++++++++++++++++++++++++++++++++------- plugin-defaults.ini | 32 +++++++------------ 4 files changed, 95 insertions(+), 31 deletions(-) diff --git a/defaults.ini b/defaults.ini index 5b623f9..046af0a 100644 --- a/defaults.ini +++ b/defaults.ini @@ -231,6 +231,23 @@ output_css: .u {text-decoration: underline;} .bold {font-weight: bold;} +## If not set, the summary will have all html stripped for safety. +## Both this and include_images must be true to get images in the +## summary. +#keep_summary_html:false + +## include images from img tags in the body and summary of +## stories. Images will be converted to jpg for size if possible. +#include_images:false + +## Resize images down to width, height, preserving aspect ratio. +## Nook size, with margin. +image_max_size: 580, 725 + +## Change image to grayscale, if graphics library allows, to save +## space. +#grayscale_images: false + [mobi] ## mobi TOC cannot be turned off right now. #include_tocpage: true diff --git a/downloader.py b/downloader.py index 6a6c07b..331c8c2 100644 --- a/downloader.py +++ b/downloader.py @@ -130,6 +130,16 @@ def main(): adapter = adapters.getAdapter(config,url,options.format) + ## Check for include_images and absence of PIL, give warning. + if adapter.getConfig('include_images'): + try: + import Image + except: + print "You have include_images enabled, but Python Image Library(PIL) isn't found.\nImages will be included full size in original format.\nContinue? (y/n)?" + if not sys.stdin.readline().strip().lower().startswith('y'): + return + + ## three tries, that's enough if both user/pass & is_adult needed, ## or a couple tries of one or the other for x in range(0,2): diff --git a/fanficdownloader/story.py b/fanficdownloader/story.py index 6d9f776..b59b08b 100644 --- a/fanficdownloader/story.py +++ b/fanficdownloader/story.py @@ -31,18 +31,63 @@ try: img.type = "GrayscaleType" return (img.export('JPG'),'jpg','image/jpeg') except: - imagetypes = { - 'jpg':'image/jpeg', - 'jpeg':'image/jpeg', - 'png':'image/png', - 'gif':'image/gif', - 'svg':'image/svg+xml', - } - # Problem: writer_epub assumes image is jpg. - def convert_image(url,data,sizes,grayscale): - ext=url[url.rfind('.')+1:].lower() - return (data,ext,imagetypes[ext]) + # No calibre routines, try for PIL for CLI. + try: + import Image + from StringIO import StringIO + from math import floor + def convert_image(url,data,sizes,grayscale): + img = Image.open(StringIO(data)) + outsio = StringIO() + + owidth, oheight = img.size + nwidth, nheight = sizes + scaled, nwidth, nheight = fit_image(owidth, oheight, nwidth, nheight) + if scaled: + img = img.resize((nwidth, nheight),Image.ANTIALIAS) + + if grayscale: + img = img.convert("L") + + img.save(outsio,'JPEG') + return (outsio.getvalue(),'jpg','image/jpeg') + + def fit_image(width, height, pwidth, pheight): + ''' + Fit image in box of width pwidth and height pheight. + @param width: Width of image + @param height: Height of image + @param pwidth: Width of box + @param pheight: Height of box + @return: scaled, new_width, new_height. scaled is True iff new_width and/or new_height is different from width or height. + ''' + scaled = height > pheight or width > pwidth + if height > pheight: + corrf = pheight/float(height) + width, height = floor(corrf*width), pheight + if width > pwidth: + corrf = pwidth/float(width) + width, height = pwidth, floor(corrf*height) + if height > pheight: + corrf = pheight/float(height) + width, height = floor(corrf*width), pheight + + return scaled, int(width), int(height) + except: + + # No calibre or PIL, simple pass through with mimetype. + imagetypes = { + 'jpg':'image/jpeg', + 'jpeg':'image/jpeg', + 'png':'image/png', + 'gif':'image/gif', + 'svg':'image/svg+xml', + } + + def convert_image(url,data,sizes,grayscale): + ext=url[url.rfind('.')+1:].lower() + return (data,ext,imagetypes[ext]) try: # doesn't really matter what, just checking for appengine. diff --git a/plugin-defaults.ini b/plugin-defaults.ini index c73ac4f..51531cb 100644 --- a/plugin-defaults.ini +++ b/plugin-defaults.ini @@ -160,13 +160,6 @@ titlepage_entries: series,category,genre,language,status,datePublished,dateUpdat ## use \r\n for line endings, the windows convention. text output only. windows_eol: true -[txt] -## Add URLs since there aren't links. -titlepage_entries: series,category,genre,status,datePublished,dateUpdated,dateCreated,rating,warnings,numChapters,numWords,site,storyUrl, authorUrl, description - -## use \r\n for line endings, the windows convention. text output only. -windows_eol: true - [epub] ## epub carries the TOC in metadata. @@ -213,28 +206,27 @@ output_css: .u {text-decoration: underline;} .bold {font-weight: bold;} -## include images from img tags in the body and summary of -## stories -#include_images:false - -## Resize images down to width, height, preserving aspect ratio. -## Nook size, with margin. -#image_max_size: 580, 725 - -## Change image to grayscale, if graphics library allows, to save -## space. -#grayscale_images: false - ## If not set, the summary will have all html stripped for safety. ## Both this and include_images must be true to get images in the ## summary. #keep_summary_html:false +## include images from img tags in the body and summary of +## stories. Images will be converted to jpg for size if possible. +#include_images:false + +## Resize images down to width, height, preserving aspect ratio. +## Nook size, with margin. +image_max_size: 580, 725 + +## Change image to grayscale, if graphics library allows, to save +## space. +#grayscale_images: false + [mobi] ## mobi TOC cannot be turned off right now. #include_tocpage: true - ## Each site has a section that overrides [defaults] *and* the format ## sections test1.com specifically is not a real story site. Instead, ## it is a fake site for testing configuration and output. It uses