You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
68 lines
2.2 KiB
68 lines
2.2 KiB
"""Media compression before storage / upload (Pillow images; ffmpeg optional for A/V).""" |
|
|
|
from __future__ import annotations |
|
|
|
import io |
|
import tempfile |
|
from pathlib import Path |
|
|
|
from PIL import Image |
|
|
|
from imwald.core.database import Database |
|
from imwald.core.media_compress import ( |
|
SETTING_MEDIA_COMPRESS_STRENGTH, |
|
SETTING_MEDIA_MAX_IMAGE_WIDTH, |
|
compress_image_bytes, |
|
prepare_bytes_for_storage, |
|
read_compression_strength, |
|
read_max_image_width, |
|
) |
|
|
|
|
|
def _rgb_wide_png() -> bytes: |
|
im = Image.new("RGB", (1600, 400), color=(200, 30, 30)) |
|
buf = io.BytesIO() |
|
im.save(buf, format="PNG", compress_level=3) |
|
return buf.getvalue() |
|
|
|
|
|
def test_compress_image_scales_to_max_width() -> None: |
|
raw = _rgb_wide_png() |
|
out, mime, name = compress_image_bytes(raw, max_width=1000, strength=1, original_name="x.png") |
|
assert mime == "image/jpeg" |
|
assert name.endswith(".jpg") |
|
im = Image.open(io.BytesIO(out)) |
|
assert im.size[0] <= 1000 |
|
|
|
|
|
def test_strength_stronger_yields_smaller_or_equal_jpeg() -> None: |
|
raw = _rgb_wide_png() |
|
light, _, _ = compress_image_bytes(raw, max_width=1000, strength=0, original_name="w.png") |
|
strong, _, _ = compress_image_bytes(raw, max_width=1000, strength=2, original_name="w.png") |
|
assert len(strong) <= len(light) |
|
|
|
|
|
def test_read_settings_from_db() -> None: |
|
with tempfile.TemporaryDirectory() as td: |
|
db = Database(Path(td) / "m.sqlite") |
|
db.connect() |
|
assert read_compression_strength(db) == 1 |
|
assert read_max_image_width(db) == 1000 |
|
db.set_setting(SETTING_MEDIA_COMPRESS_STRENGTH, "2") |
|
db.set_setting(SETTING_MEDIA_MAX_IMAGE_WIDTH, "1200") |
|
assert read_compression_strength(db) == 2 |
|
assert read_max_image_width(db) == 1200 |
|
|
|
|
|
def test_prepare_bytes_image_round_trip() -> None: |
|
raw = _rgb_wide_png() |
|
with tempfile.TemporaryDirectory() as td: |
|
db = Database(Path(td) / "m2.sqlite") |
|
db.connect() |
|
db.set_setting(SETTING_MEDIA_MAX_IMAGE_WIDTH, "800") |
|
out, mime, _name = prepare_bytes_for_storage( |
|
raw, "wide.png", mime_hint="image/png", db=db, strength=1 |
|
) |
|
assert mime == "image/jpeg" |
|
im = Image.open(io.BytesIO(out)) |
|
assert im.size[0] <= 800
|
|
|