-
Notifications
You must be signed in to change notification settings - Fork 24
/
image.py
107 lines (90 loc) · 3.8 KB
/
image.py
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project : xadmin-server
# filename : image
# author : ly_13
# date : 1/17/2024
import os
from django.db import models
from django.db.models.fields.files import ImageFieldFile
from imagekit.cachefiles import ImageCacheFile
from imagekit.models.fields import SpecHostField
from imagekit.specs import SpecHost
from imagekit.utils import generate
from pilkit.processors import ResizeToFill
from pilkit.utils import suggest_extension
def source_name(generator, index):
source_filename = getattr(generator.source, 'name', None)
ext = suggest_extension(source_filename or '', generator.format)
return f"{os.path.splitext(source_filename)[0]}_{index}{ext}"
def get_thumbnail(source, index, force=False):
scales = source.field.scales
# spec = ImageSpec(source)
spec = source.field.get_spec(source=source)
width = spec.processors[0].width
height = spec.processors[0].height
spec.format = 'JPEG'
spec.options = {'quality': 90}
if index not in scales:
index = scales[-1]
spec.processors = [ResizeToFill(int(width / index), int(height / index))]
file = ImageCacheFile(spec, name=source_name(spec, index))
file.generate(force=force)
return file.name
class ProcessedImageFieldFile(ImageFieldFile):
def save(self, name, content, save=True):
filename, ext = os.path.splitext(name)
spec = self.field.get_spec(source=content)
ext = suggest_extension(name, spec.format)
new_name = '%s%s' % (filename, ext)
content = generate(spec)
return super().save(new_name, content, save)
def delete(self, save=True):
# Clear the image dimensions cache
if hasattr(self, "_dimensions_cache"):
del self._dimensions_cache
name = self.name
try:
for i in self.field.scales:
self.name = f"{name.split('.')[0]}_{i}.jpg"
super().delete(False)
except Exception as e:
pass
self.name = name
super().delete(save)
@property
def url(self):
url: str = super().url
if url.endswith('.png'):
return url.replace('.png', '_1.jpg')
return url
class ProcessedImageField(models.ImageField, SpecHostField):
"""
ProcessedImageField is an ImageField that runs processors on the uploaded
image *before* saving it to storage. This is in contrast to specs, which
maintain the original. Useful for coercing fileformats or keeping images
within a reasonable size.
"""
attr_class = ProcessedImageFieldFile
def __init__(self, processors=None, format=None, options=None, scales=None,
verbose_name=None, name=None, width_field=None, height_field=None,
autoconvert=None, spec=None, spec_id=None, **kwargs):
"""
The ProcessedImageField constructor accepts all of the arguments that
the :class:`django.db.models.ImageField` constructor accepts, as well
as the ``processors``, ``format``, and ``options`` arguments of
:class:`imagekit.models.ImageSpecField`.
"""
# if spec is not provided then autoconvert will be True by default
if spec is None and autoconvert is None:
autoconvert = True
self.scales = scales if scales is not None else [1]
self.format = format if format else 'png'
SpecHost.__init__(self, processors=processors, format=self.format,
options=options, autoconvert=autoconvert, spec=spec,
spec_id=spec_id)
models.ImageField.__init__(self, verbose_name, name, width_field,
height_field, **kwargs)
def contribute_to_class(self, cls, name):
self._set_spec_id(cls, name)
return super().contribute_to_class(cls, name)