summaryrefslogtreecommitdiffstats
path: root/app/imutil.py
blob: 015a2c146c061e6472c17d1812b1c7a4304c5929 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
from PIL import Image
from app import blure
from sanic.response import raw
from pathlib import Path
from io import BytesIO

_IMAGE_URL = blure.config.NGX_IMAGE_URL
_IMAGE_PATH = blure.config.NGX_IMAGE_PATH
_NOT_FOUND_IMAGE = blure.config.NOT_FOUND_IMAGE
_NOT_FOUND_IMAGE_CONTENT_TYPE = blure.config.NOT_FOUND_IMAGE_CONTENT_TYPE


class InvalidImageFormat(ValueError):
    pass


class NGXImage:
    def __init__(self, id: int):
        self.filename = blure.url.to_url(id)

    @staticmethod
    def _load_pic(filename):
        p = Path(_IMAGE_PATH.format(filename))
        if not p.is_file():
            return NGXImage.not_found()

        return raw(b'',
                   content_type='image',
                   headers={'X-Accel-Redirect': _IMAGE_URL.format(filename)},
                   status=200)

    def orig(self):
        return self._load_pic(self.filename)

    def thumb(self):
        return self._load_pic(self.filename + '_thumb')

    @staticmethod
    def not_found():
        return raw(_NOT_FOUND_IMAGE,
                   content_type=_NOT_FOUND_IMAGE_CONTENT_TYPE,
                   status=404)

    @staticmethod
    def pillow_format(content_type: str):
        mapping = {
            '': 'PNG',  # try png if content type is not available
            'image/bmp': 'BMP',
            'image/gif': 'GIF',
            'image/jpeg': 'JPEG',
            'image/png': 'PNG'
        }
        if content_type in mapping.keys():
            return mapping[content_type]
        else:
            raise InvalidImageFormat(f'{content_type} is not supported')

    def save(self, body: BytesIO, content_type: str):
        image_path = Path(_IMAGE_PATH.format(self.filename))
        thumb_path = Path(_IMAGE_PATH.format(self.filename + '_thumb'))

        with image_path.open('wb') as f:
            f.write(body.getvalue())

        with thumb_path.open('wb') as f:
            im = Image.open(body)
            thumb_stream = BytesIO()
            im.thumbnail(blure.config.CUT_SIZES[2])
            im.save(thumb_stream, format=self.pillow_format(content_type))
            f.write(thumb_stream.getvalue())

    def delete_from_disk(self):
        image_path = Path(_IMAGE_PATH.format(self.filename))
        thumb_path = Path(_IMAGE_PATH.format(self.filename + '_thumb'))

        if image_path.exists():
            image_path.unlink()
        if thumb_path.exists():
            thumb_path.unlink()