Force bgcolor for JPG output images, allow PNG images w/trans in CLI,

ribbon cover exclusion for dramione.org
This commit is contained in:
Jim Miller
2012-12-05 13:36:48 -06:00
parent 437f139283
commit a4b7cafe29
3 changed files with 81 additions and 33 deletions
+16 -1
View File
@@ -386,9 +386,20 @@ output_css:
image_max_size: 580, 725
## Change image to grayscale, if graphics library allows, to save
## space.
## space. Transparency removed as if remove_transparency: true
#grayscale_images: false
## jpg or png
## -- jpg produces smaller images, and may be supported by more
## readers, but it's older and doesn't allow transparency.
## Transparency removed as if remove_transparency: true
## -- png is newer but does allow transparency, but only in CLI.
## It doesn't work in calibre PI due to limitations of the API.
convert_images_to: jpg
## Remove transparency and fill with background_color if true.
remove_transparency: true
## if the <img> tag doesn't have a div or a p around it, nook gets
## confused and displays it on every page after that under the text
## for the rest of the chapter. I doubt adding a div around the img
@@ -559,6 +570,10 @@ extraships:Draco Malfoy/Hermione Granger
## personal.ini, not defaults.ini.
#is_adult:true
## some sites include images that we don't ever want becoming the
## cover image. This lets you exclude them.
cover_exclusion_regexp:/images/.*?ribbon.gif
## Some adapters collect additional meta information beyond the
## standard ones. They need to be defined in extra_valid_entries to
## tell the rest of the FFDL system about them. They can be used in
+61 -32
View File
@@ -21,6 +21,7 @@ import string
from math import floor
from functools import partial
import logging
logger = logging.getLogger(__name__)
import urlparse as up
import exceptions
@@ -29,10 +30,21 @@ from configurable import Configurable
# Create convert_image method depending on which graphics lib we can
# load. Preferred: calibre, PIL, none
imagetypes = {
'jpg':'image/jpeg',
'jpeg':'image/jpeg',
'png':'image/png',
'gif':'image/gif',
'svg':'image/svg+xml',
}
try:
from calibre.utils.magick import Image
convtype = {'jpg':'JPG', 'png':'PNG'}
def convert_image(url,data,sizes,grayscale):
def convert_image(url,data,sizes,grayscale,
removetrans,imgtype="jpg",background='#ffffff'):
export = False
img = Image()
img.load(data)
@@ -44,18 +56,25 @@ try:
img.size = (nwidth, nheight)
export = True
if normalize_format_name(img.format) != imgtype:
export = True
if removetrans and img.has_transparent_pixels():
canvas = Image()
canvas.create_canvas(int(img.size[0]), int(img.size[1]), str(background))
canvas.compose(img)
img = canvas
export = True
if grayscale and img.type != "GrayscaleType":
img.type = "GrayscaleType"
export = True
if normalize_format_name(img.format) != "jpg":
export = True
if export:
return (img.export('JPG'),'jpg','image/jpeg')
return (img.export(convtype[imgtype]),imgtype,imagetypes[imgtype])
else:
logging.debug("image used unchanged")
return (data,'jpg','image/jpeg')
logger.debug("image used unchanged")
return (data,imgtype,imagetypes[imgtype])
except:
@@ -63,8 +82,9 @@ except:
try:
import Image
from StringIO import StringIO
def convert_image(url,data,sizes,grayscale):
convtype = {'jpg':'JPEG', 'png':'PNG'}
def convert_image(url,data,sizes,grayscale,
removetrans,imgtype="jpg",background='#ffffff'):
export = False
img = Image.open(StringIO(data))
@@ -75,36 +95,36 @@ except:
img = img.resize((nwidth, nheight),Image.ANTIALIAS)
export = True
if grayscale and img.mode != "L":
img = img.convert("L")
export = True
if normalize_format_name(img.format) != "jpg":
if normalize_format_name(img.format) != imgtype:
if img.mode == "P":
# convert pallete gifs to RGB so jpg save doesn't fail.
img = img.convert("RGB")
export = True
if removetrans and img.mode == "RGBA":
background = Image.new('RGBA', img.size, background)
# Paste the image on top of the background
background.paste(img, img)
img = background.convert('RGB')
export = True
if grayscale and img.mode != "L":
img = img.convert("L")
export = True
if export:
outsio = StringIO()
img.save(outsio,'JPEG')
return (outsio.getvalue(),'jpg','image/jpeg')
img.save(outsio,convtype[imgtype])
return (outsio.getvalue(),imgtype,imagetypes[imgtype])
else:
logging.debug("image used unchanged")
return (data,'jpg','image/jpeg')
logger.debug("image used unchanged")
return (data,imgtype,imagetypes[imgtype])
except:
# No calibre or PIL, simple pass through with mimetype.
def convert_image(url,data,sizes,grayscale):
def convert_image(url,data,sizes,grayscale,
removetrans,imgtype="jpg",background='#ffffff'):
return no_convert_image(url,data)
imagetypes = {
'jpg':'image/jpeg',
'jpeg':'image/jpeg',
'png':'image/png',
'gif':'image/gif',
'svg':'image/svg+xml',
}
## also used for explicit no image processing.
def no_convert_image(url,data):
@@ -113,7 +133,7 @@ def no_convert_image(url,data):
ext=parsedUrl.path[parsedUrl.path.rfind('.')+1:].lower()
if ext not in imagetypes:
logging.debug("no_convert_image url:%s - no known extension"%url)
logger.debug("no_convert_image url:%s - no known extension"%url)
# doesn't have extension? use jpg.
ext='jpg'
@@ -519,18 +539,27 @@ class Story(Configurable):
try:
if self.getConfig('no_image_processing'):
(data,ext,mime) = no_convert_image(imgurl,
fetch(imgurl))
fetch(imgurl))
else:
try:
sizes = [ int(x) for x in self.getConfigList('image_max_size') ]
except Exception, e:
raise exceptions.FailedToDownload("Failed to parse image_max_size from personal.ini:%s\nException: %s"%(self.getConfigList('image_max_size'),e))
grayscale = self.getConfig('grayscale_images')
imgtype = self.getConfig('convert_images_to')
if not imgtype:
imgtype = "jpg"
removetrans = self.getConfig('remove_transparency')
removetrans = removetrans or grayscale or imgtype=="jpg"
(data,ext,mime) = convert_image(imgurl,
fetch(imgurl),
sizes,
self.getConfig('grayscale_images'))
grayscale,
removetrans,
imgtype,
background="#"+self.getConfig('background_color'))
except Exception, e:
logging.info("Failed to load or convert image, skipping:\n%s\nException: %s"%(imgurl,e))
logger.info("Failed to load or convert image, skipping:\n%s\nException: %s"%(imgurl,e))
return "failedtoload"
# explicit cover, make the first image.
@@ -565,7 +594,7 @@ class Story(Configurable):
ext)
self.imgtuples.append({'newsrc':newsrc,'mime':mime,'data':data})
logging.debug("\nimgurl:%s\nnewsrc:%s\nimage size:%d\n"%(imgurl,newsrc,len(data)))
logger.debug("\nimgurl:%s\nnewsrc:%s\nimage size:%d\n"%(imgurl,newsrc,len(data)))
else:
newsrc = self.imgtuples[self.imgurls.index(imgurl)]['newsrc']
+4
View File
@@ -534,6 +534,10 @@ extraships:Draco Malfoy/Hermione Granger
## personal.ini, not defaults.ini.
#is_adult:true
## some sites include images that we don't ever want becoming the
## cover image. This lets you exclude them.
cover_exclusion_regexp:/images/.*?ribbon.gif
## Some adapters collect additional meta information beyond the
## standard ones. They need to be defined in extra_valid_entries to
## tell the rest of the FFDL system about them. They can be used in