1#!/usr/local/bin/python3.8
2# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
3
4
5__license__   = 'GPL v3'
6__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
7__docformat__ = 'restructuredtext en'
8
9import os
10
11from calibre.utils.magick import Image, create_canvas
12from calibre.utils.img import save_cover_data_to as _save_cover_data_to, image_to_data, add_borders_to_image as abti
13from calibre.utils.imghdr import identify as _identify
14from calibre import fit_image
15
16
17def _data_to_image(data):
18    if isinstance(data, Image):
19        img = data
20    else:
21        img = Image()
22        img.load(data)
23    return img
24
25
26def minify_image(data, minify_to=(1200, 1600), preserve_aspect_ratio=True):
27    '''
28    Minify image to specified size if image is bigger than specified
29    size and return minified image, otherwise, original image is
30    returned.
31
32    :param data: Image data as bytestring or Image object
33    :param minify_to: A tuple (width, height) to specify target size
34    :param preserve_aspect_ratio: whether preserve original aspect ratio
35    '''
36    img = _data_to_image(data)
37    owidth, oheight = img.size
38    nwidth, nheight = minify_to
39    if owidth <= nwidth and oheight <= nheight:
40        return img
41    if preserve_aspect_ratio:
42        scaled, nwidth, nheight = fit_image(owidth, oheight, nwidth, nheight)
43    img.size = (nwidth, nheight)
44    return img
45
46
47def save_cover_data_to(data, path, bgcolor='#ffffff', resize_to=None,
48        return_data=False, compression_quality=90, minify_to=None,
49        grayscale=False):
50    '''
51    Saves image in data to path, in the format specified by the path
52    extension. Removes any transparency. If there is no transparency and no
53    resize and the input and output image formats are the same, no changes are
54    made.
55
56    :param data: Image data as bytestring or Image object
57    :param compression_quality: The quality of the image after compression.
58        Number between 1 and 100. 1 means highest compression, 100 means no
59        compression (lossless).
60    :param bgcolor: The color for transparent pixels. Must be specified in hex.
61    :param resize_to: A tuple (width, height) or None for no resizing
62    :param minify_to: A tuple (width, height) to specify maximum target size.
63    :param grayscale: If True, the image is grayscaled
64    will be resized to fit into this target size. If None the value from the
65    tweak is used.
66
67    '''
68    fmt = os.path.splitext(path)[1]
69    if return_data:
70        path = None
71    if isinstance(data, Image):
72        data = data.img
73    return _save_cover_data_to(
74        data, path, bgcolor=bgcolor, resize_to=resize_to, compression_quality=compression_quality, minify_to=minify_to, grayscale=grayscale, data_fmt=fmt)
75
76
77def thumbnail(data, width=120, height=120, bgcolor='#ffffff', fmt='jpg',
78              preserve_aspect_ratio=True, compression_quality=70):
79    img = Image()
80    img.load(data)
81    owidth, oheight = img.size
82    if width is None:
83        width = owidth
84    if height is None:
85        height = oheight
86    if not preserve_aspect_ratio:
87        scaled = owidth > width or oheight > height
88        nwidth = width
89        nheight = height
90    else:
91        scaled, nwidth, nheight = fit_image(owidth, oheight, width, height)
92    if scaled:
93        img.size = (nwidth, nheight)
94    canvas = create_canvas(img.size[0], img.size[1], bgcolor)
95    canvas.compose(img)
96    data = image_to_data(canvas.img, compression_quality=compression_quality)
97    return (canvas.size[0], canvas.size[1], data)
98
99
100def identify_data(data):
101    '''
102    Identify the image in data. Returns a 3-tuple
103    (width, height, format)
104    or raises an Exception if data is not an image.
105    '''
106    fmt, width, height = _identify(data)
107    return width, height, fmt
108
109
110def identify(path):
111    '''
112    Identify the image at path. Returns a 3-tuple
113    (width, height, format)
114    or raises an Exception.
115    '''
116    with lopen(path, 'rb') as f:
117        fmt, width, height = _identify(f)
118    return width, height, fmt
119
120
121def add_borders_to_image(img_data, left=0, top=0, right=0, bottom=0,
122        border_color='#ffffff', fmt='jpg'):
123    img = abti(img_data, left=left, top=top, right=right, bottom=bottom, border_color=border_color)
124    return image_to_data(img, fmt=fmt)
125