thumbor/thumbor

View on GitHub
thumbor/url_composer.py

Summary

Maintainability
A
1 hr
Test Coverage
#!/usr/bin/python
# -*- coding: utf-8 -*-

# thumbor imaging service
# https://github.com/thumbor/thumbor/wiki

# Licensed under the MIT license:
# http://www.opensource.org/licenses/mit-license
# Copyright (c) 2011 globo.com thumbor@googlegroups.com

import optparse  # pylint: disable=deprecated-module
import sys
from urllib.parse import quote

from libthumbor import CryptoURL

from thumbor import __version__
from thumbor.config import Config


def get_parser():
    parser = optparse.OptionParser(
        usage="thumbor-url [options] imageurl or type thumbor-url -h (--help) for help",
        description=__doc__,
        version=__version__,
    )

    parser.add_option(
        "-l",
        "--key_file",
        dest="key_file",
        default=None,
        help="The file to read the security key from [default: %default].",
    )
    parser.add_option(
        "-k",
        "--key",
        dest="key",
        default=None,
        help="The security key to encrypt the url with [default: %default].",
    )
    parser.add_option(
        "-w",
        "--width",
        dest="width",
        type="int",
        default=0,
        help="The target width for the image [default: %default].",
    )
    parser.add_option(
        "-e",
        "--height",
        dest="height",
        type="int",
        default=0,
        help="The target height for the image [default: %default].",
    )
    parser.add_option(
        "-n",
        "--fitin",
        dest="fitin",
        action="store_true",
        default=False,
        help="Indicates that fit-in resizing should be performed.",
    )
    parser.add_option(
        "-m",
        "--meta",
        dest="meta",
        action="store_true",
        default=False,
        help="Indicates that meta information should be retrieved.",
    )
    parser.add_option(
        "",
        "--adaptive",
        action="store_true",
        dest="adaptive",
        default=False,
        help="Indicates that adaptive fit-in cropping should be used.",
    )
    parser.add_option(
        "",
        "--full",
        action="store_true",
        dest="full",
        default=False,
        help="Indicates that fit-full cropping should be used.",
    )
    parser.add_option(
        "-s",
        "--smart",
        action="store_true",
        dest="smart",
        default=False,
        help="Indicates that smart cropping should be used.",
    )
    parser.add_option(
        "-t",
        "--trim",
        action="store_true",
        default=False,
        help="Indicate that surrounding whitespace should be trimmed.",
    )
    parser.add_option(
        "-f",
        "--horizontal-flip",
        action="store_true",
        dest="horizontal_flip",
        default=False,
        help="Indicates that the image should be horizontally flipped.",
    )
    parser.add_option(
        "-v",
        "--vertical-flip",
        action="store_true",
        dest="vertical_flip",
        default=False,
        help="Indicates that the image should be vertically flipped.",
    )
    parser.add_option(
        "-a",
        "--halign",
        dest="halign",
        default="center",
        help="The horizontal alignment to use for cropping [default: %default].",
    )
    parser.add_option(
        "-i",
        "--valign",
        dest="valign",
        default="middle",
        help="The vertical alignment to use for cropping [default: %default].",
    )
    parser.add_option(
        "",
        "--filters",
        dest="filters",
        action="append",
        help="Filters to be applied to the image, e.g. brightness(10).",
    )

    parser.add_option(
        "-c",
        "--crop",
        dest="crop",
        default=None,
        help="The coordinates of the points to manual cropping in the format leftxtop:rightxbottom "
        "(100x200:400x500) [default: %default].",
    )

    return parser


def get_options(arguments):
    if arguments is None:
        arguments = sys.argv[1:]

    parser = get_parser()

    (parsed_options, arguments) = parser.parse_args(arguments)

    if not arguments:
        return None, None

    return parsed_options, arguments


def get_thumbor_params(image_url, params, config):
    if params.key_file:
        with open(params.key_file, "rb") as key_file:
            security_key = key_file.read().strip()
    else:
        security_key = config.SECURITY_KEY if not params.key else params.key

    crop_left = crop_top = crop_right = crop_bottom = 0
    if params.crop:
        crops = params.crop.split(":")
        crop_left, crop_top = crops[0].split("x")
        crop_right, crop_bottom = crops[1].split("x")

    options = {
        "width": params.width,
        "height": params.height,
        "smart": params.smart,
        "meta": params.meta,
        "horizontal_flip": params.horizontal_flip,
        "vertical_flip": params.vertical_flip,
        "halign": params.halign,
        "valign": params.valign,
        "trim": params.trim,
        "crop_left": crop_left,
        "crop_top": crop_top,
        "crop_right": crop_right,
        "crop_bottom": crop_bottom,
        "filters": params.filters,
        "image_url": image_url,
        "fit_in": False,
        "full_fit_in": False,
        "adaptive_fit_in": False,
        "adaptive_full_fit_in": False,
    }

    if params.fitin and params.full and params.adaptive:
        options["adaptive_full_fit_in"] = True
    elif params.fitin and params.full:
        options["full_fit_in"] = True
    elif params.fitin and params.adaptive:
        options["adaptive_fit_in"] = True
    elif params.fitin:
        options["fit_in"] = True

    return security_key, options


def main(arguments=None):
    """Converts a given url with the specified arguments."""

    parsed_options, arguments = get_options(arguments)

    if not arguments:
        sys.stdout.write(
            "Error: The image argument is mandatory. For more information type thumbor-url -h\n"
        )
        sys.exit(1)

    image_url = arguments[0]
    image_url = quote(image_url)

    try:
        config = Config.load(None)
    except Exception:  # pylint: disable=broad-except
        config = None

    if not parsed_options.key and not config:
        sys.stdout.write(
            "Error: The -k or --key argument is mandatory."
            " For more information type thumbor-url -h\n"
        )
        sys.exit(1)

    security_key, thumbor_params = get_thumbor_params(
        image_url, parsed_options, config
    )

    crypto = CryptoURL(key=security_key)
    url = crypto.generate(**thumbor_params)
    sys.stdout.write("URL:\n")
    sys.stdout.write(f"{url}\n")


if __name__ == "__main__":
    main(sys.argv[1:])