Skip to content

Commit

Permalink
Production Deployment
Browse files Browse the repository at this point in the history
Production Deployment
  • Loading branch information
YayunHuang authored Aug 23, 2024
2 parents d084867 + c159054 commit 25a8689
Show file tree
Hide file tree
Showing 67 changed files with 916 additions and 241 deletions.
19 changes: 19 additions & 0 deletions docs/generate_mockup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## Why add padding in `create_fit_coord_image`

Because there will see weird triangle in the corner for some deivces because there is a black area between the phone frame and the display area

![samsung-s24-ultra-right](https://github.com/user-attachments/assets/75936a3a-89b9-4885-874f-dfac4a0d1d0d)

| type | Before | After |
| --------- | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| landscape | ![samsung-s24-ultra-landscape](https://github.com/user-attachments/assets/b3ec7528-20a7-4508-b8c2-f7b6308e59c8) | ![samsung-s24-ultra-landscape](https://github.com/user-attachments/assets/bb508211-edd4-4dc3-b5d1-ed228150c12b) |
| portrait | ![samsung-s24-ultra-portrait](https://github.com/user-attachments/assets/a9f56fec-6524-4983-9d21-2c598e1094a5) | ![samsung-s24-ultra-portrait](https://github.com/user-attachments/assets/96c6046e-be8e-4b36-8a2f-b374ffbe7d79) |
| left | ![samsung-s24-ultra-left](https://github.com/user-attachments/assets/5e90d39b-40ff-44b8-96c1-e8479a17a9f5) | ![samsung-s24-ultra-left](https://github.com/user-attachments/assets/e33e5a43-69d9-494c-acae-dc371abe7406) |
| right | ![samsung-s24-ultra-right](https://github.com/user-attachments/assets/8d258f18-bfd9-47a9-8258-3285f1a01b8a) | ![samsung-s24-ultra-right](https://github.com/user-attachments/assets/15768da2-e0af-442e-9c62-f99510c485e4) |

For the portrait one, the gray area on the top disappear after the update, but I think that should be expected, I guess the `coords` in `device_info.json` is incorrect so the image is pasted slightly to the bottom than expected , but it is not related to the current issue. (not sure if we need to spend some time checking that all model templates and configurations are correct)

## why shift mask position in `create_mockup_image`

After adding padding in `create_fit_coord_image`, we need to shift mask too get correct mockup
![image](https://github.com/user-attachments/assets/c751f8a2-4ff5-4a53-8eff-d58432b2f48a)
1 change: 1 addition & 0 deletions mockup_package/mockup/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from .image import mockup as startMockup # noqa: F401
from .image import previewMockup # noqa: F401
91 changes: 63 additions & 28 deletions mockup_package/mockup/image.py
Original file line number Diff line number Diff line change
@@ -1,49 +1,84 @@
import base64
import sys
from pathlib import Path
from typing import Any
from pyodide.http import pyfetch
from mockup.image_generator import ImageGenerator as IG
import os


async def mockup(location, device_id, original_img_path_list, device_info):
device_path_prefix = f"{location.split('/')[0]}//{location.split('/')[2]}"
device_mask_path_prefix = device_path_prefix + "/images/mockup_mask_templates/"
async def generate(
location: str,
original_img_path: str,
spec: dict[str, Any],
ig: IG,
) -> tuple[str, str, str]:
device_path_prefix: str = f"{location.split('/')[0]}//{location.split('/')[2]}"
device_mask_path_prefix: str = device_path_prefix + "/images/mockup_mask_templates/"
device_path_prefix += "/images/mockup_templates/"
device_path = "./device.png"
device_mask_path = "./device_mask.png"
output_img_path_list = []
device_path: str = "./device.png"
device_mask_path: str = "./device_mask.png"

try:
await process_response(
device_path_prefix + str(spec["image"]),
device_path,
)
await process_response(
device_mask_path_prefix + str(spec["image"]),
device_mask_path,
)
except Exception as e:
print(e, file=sys.stderr)
# js.errorBox(e)
raise
ig.create_fit_coord_image(spec)
deviceView = str(spec["image"]).split("-")[-1].split(".")[0]
path = (
f"{os.path.splitext(os.path.basename(original_img_path))[0]}"
+ f"-{deviceView}.png"
)
ig.create_mockup_image(device_path, device_mask_path, path)
return (path, original_img_path, deviceView)


async def mockup(
location: str,
device_id: str,
original_img_path_list: list[str],
device_info: dict[str, Any],
):
output_img_path_list: list[tuple[str, str, str]] = []
for original_img_path in original_img_path_list:
ig = IG(original_img_path, device_id, device_info)
ig.create_fit_resolution_image()
for spec in ig.phone_models.get(device_id).get("mockups").values():
try:
await process_response(
device_path_prefix + str(spec["image"]),
device_path,
)
await process_response(
device_mask_path_prefix + str(spec["image"]),
device_mask_path,
)
except Exception as e:
print(e, file=sys.stderr)
# js.errorBox(e)
raise
ig.create_fit_coord_image(spec)
deviceView = str(spec["image"]).split("-")[-1].split(".")[0]
path = (
f"{os.path.splitext(os.path.basename(original_img_path))[0]}"
+ f"-{deviceView}.png"
output_img_path_list.append(
await generate(location, original_img_path, spec, ig)
)
ig.create_mockup_image(device_path, device_mask_path, path)
output_img_path_list.append([path, original_img_path, deviceView])

original_img_path_list.clear()
return output_img_path_list


async def download(url):
async def previewMockup(
location: str,
device_id: str,
original_img_path: str,
device_info: dict[str, Any],
preview_orientation_index: int = 0,
):
ig = IG(original_img_path, device_id, device_info)
ig.create_fit_resolution_image()
spec = list(ig.phone_models.get(device_id).get("mockups").values())[
preview_orientation_index
]
output_img_path = await generate(location, original_img_path, spec, ig)

return output_img_path


async def download(url: str):
filename = Path(url).name
response = await pyfetch(url)
if response.status == 200:
Expand All @@ -57,7 +92,7 @@ async def download(url):
return filename, status


async def process_response(url, path):
async def process_response(url: str, path: str):
response_content = await download(url)
if response_content[1] == 200:
data = base64.b64encode(open(response_content[0], "rb").read())
Expand Down
36 changes: 32 additions & 4 deletions mockup_package/mockup/image_generator.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os
import mockup.helpers as h
from PIL import Image
from PIL import Image, ExifTags
import cv2
import numpy as np

Expand Down Expand Up @@ -38,6 +38,31 @@ def __init__(self, original_img_path, phone_slug, device_info):
def create_fit_resolution_image(self):
device_ratio = self.d_size[0] / self.d_size[1]
image = Image.open(self.original_img_path).convert("RGBA")

# Solve image orientation issue:
# some picture has orientation property, which the browser knows and can automatically rotate the image # noqa: E501
# but the property is lost when we mockup the image, so need to fix it manually. # noqa: E501
# ref: https://stackoverflow.com/questions/13872331/rotating-an-image-with-orientation-specified-in-exif-using-python-without-pil-in # noqa: E501
try:
for orientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[orientation] == "Orientation":
break

exif = image.getexif()
if exif[orientation] == 3:
image = image.rotate(180, expand=True)
elif exif[orientation] == 6:
image = image.rotate(270, expand=True)
elif exif[orientation] == 8:
image = image.rotate(90, expand=True)
except KeyError as ex:
if ex.args == (274,):
# image does not have orientation, expected case, will silent error
# ref https://github.com/python-pillow/Pillow/blob/0ec1153a627a46b978022c68c2adce89ff81f40d/src/PIL/TiffTags.py#L145
pass
else:
raise

find_original_image_dim_process = str(image.size[0]) + "x" + str(image.size[1])
original_image_dim = tuple(
map(
Expand Down Expand Up @@ -165,15 +190,16 @@ def create_mockup_image(self, device_path, device_mask_path_prefix, result_path)
tmp = self.target_points[0].copy()
self.target_points[0] = self.target_points[1]
self.target_points[1] = tmp
shifted_points = self.target_points + np.array([PADDING, PADDING])
mask = np.zeros(basemap.shape[:2], np.uint8)
cv2.polylines(
mask,
pts=[self.target_points],
pts=[shifted_points],
isClosed=True,
color=(255, 0, 0),
thickness=3,
)
cv2.fillPoly(mask, [self.target_points], 255)
cv2.fillPoly(mask, [shifted_points], 255)
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2RGBA)
mask = Image.fromarray(mask)

Expand All @@ -184,7 +210,9 @@ def create_mockup_image(self, device_path, device_mask_path_prefix, result_path)
# If you want to use the mask directly with the first argument of the "paste" function, # noqa: E501
# you need to convert it to the "L" mode and ensure that it has the same size as the first argument. # noqa: E501
device_image.paste(
tmp_result_image, (self.xyset[0], self.xyset[2]), mask.convert("L")
tmp_result_image,
(self.xyset[0] - PADDING, self.xyset[2] - PADDING),
mask.convert("L"),
)
device_image.save(result_path)

Expand Down
47 changes: 44 additions & 3 deletions public/image_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
from PIL import Image


async def upload_single_image(origin_image, file_name, original_img_path_list):
async def upload_single_image_and_save_to_list(
origin_image, file_name, original_img_path_list
):
array_buf = Uint8Array.new(await origin_image.arrayBuffer())
bytes_list = bytearray(array_buf)
origin_bytes = io.BytesIO(bytes_list)
Expand All @@ -16,17 +18,56 @@ async def upload_single_image(origin_image, file_name, original_img_path_list):
my_image.save(filePath)


async def upload_single_image(origin_image, file_name):
array_buf = Uint8Array.new(await origin_image.arrayBuffer())
bytes_list = bytearray(array_buf)
origin_bytes = io.BytesIO(bytes_list)
my_image = Image.open(origin_bytes)
filePath = f"./{file_name}.png"
my_image.save(filePath)
return filePath


async def upload_file():
from js import imageUpload

# Since we will update `imageUpload` when calling this function,
# need to re-import it to force update to new value
# or we will always generate first uploaded image
basename, ext = os.path.splitext(imageUpload.name)
if ext.lower() not in [".psd", ".jpg", ".jpeg", ".png"]:
return
original_img_path = await upload_single_image(imageUpload, basename)
return original_img_path


async def upload_files():
original_img_path_list = []
for fileItem in imageUploadList:
basename, ext = os.path.splitext(fileItem.name)
if ext.lower() not in [".psd", ".jpg", ".jpeg", ".png"]:
return
await upload_single_image(fileItem, basename, original_img_path_list)
await upload_single_image_and_save_to_list(
fileItem, basename, original_img_path_list
)
return original_img_path_list


def save_image(imageList):
def save_image(image):
print("image", image)
path = image[0]
my_image = Image.open(path)
my_stream = io.BytesIO()
my_image.save(my_stream, format="PNG")
binary_fc = open(path, "rb").read()
base64_utf8_str = base64.b64encode(binary_fc).decode("utf-8")
basename, ext = os.path.splitext(path)
dataurl = f"data:image/{ext};base64,{base64_utf8_str}"
print(basename)
return [f"img{basename}", dataurl]


def save_images(imageList):
returnList = []
for image in imageList:
path = image[0]
Expand Down
Binary file modified public/images/devices_picture/apple-imac2013-front.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/images/devices_picture/apple-imac2013-left.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/images/devices_picture/apple-imac2013-right.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/images/devices_picture/apple-imac2015-front.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/images/devices_picture/apple-imac2015retina-front.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/images/devices_picture/apple-macbook-gold-front.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/images/devices_picture/apple-macbook-grey-front.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/images/devices_picture/lg-55lw5600-front.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/images/devices_picture/lg-55lw5600-side.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/images/devices_picture/lg-tm2792-front.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/images/devices_picture/lg-tm2792-side.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/images/devices_picture/samsung-d8000-front.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/images/devices_picture/samsung-d8000-side.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/images/devices_picture/samsung-es8000-front.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/images/devices_picture/samsung-es8000-side.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/images/preview-gray.svg
3 changes: 3 additions & 0 deletions public/images/preview-white.svg
Binary file added public/images/spinner-blue-2.png
Binary file modified public/mockup.zip
Binary file not shown.
3 changes: 0 additions & 3 deletions public/scripts/menu.js

This file was deleted.

Loading

0 comments on commit 25a8689

Please sign in to comment.