Skip to content

Commit

Permalink
[MUP-102] Upload image here text
Browse files Browse the repository at this point in the history
[MUP-102] Upload image here text
  • Loading branch information
pkong-ds authored Jun 27, 2024
2 parents 8532ab0 + d301ae8 commit db95f2e
Show file tree
Hide file tree
Showing 12 changed files with 319 additions and 31 deletions.
7 changes: 4 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@astrojs/image": "^0.17.2",
"@astrojs/ts-plugin": "^1.1.1",
"astro": "^2.8.3",
"image-size": "^1.1.1",
"localforage": "^1.10.0",
"zod": "^3.21.4"
},
Expand Down
125 changes: 113 additions & 12 deletions src/pages/model/[model].astro
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
---
import sizeOf from "image-size";
import { dirname, join } from "path";
import { fileURLToPath } from "url";
import ErrorPage from "../../components/ErrorPage.astro";
import RequestDeviceCard from "../../components/RequestDeviceCard/RequestDeviceCard.astro";
import DeviceBaseLayout from "../../layouts/BaseLayout.astro";
import "/src/styles/upload.css";
import "/src/styles/pyscript.css";
import { DEVICE_MANAGER } from "../../scripts/deviceManager";
import deviceJson from "../../scripts/device_info.json";
import type { ModelValue } from "../../scripts/model";
import ErrorPage from "../../components/ErrorPage.astro";
import { ModelEnum } from "../../scripts/parse";
import deviceJson from "../../scripts/device_info.json";
import RequestDeviceCard from "../../components/RequestDeviceCard/RequestDeviceCard.astro";
import "/src/styles/pyscript.css";
import "/src/styles/upload.css";
import * as Matrix from "../../scripts/utils/matrix";
import * as Rect from "../../scripts/utils/rect";
import * as Quad from "../../scripts/utils/quad";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export async function getStaticPaths() {
const allModels: {
Expand Down Expand Up @@ -38,6 +47,62 @@ const sameModelDevices = model.devices;
const deviceDetail = sameModelDevices[0];
const defaultColorId = deviceDetail.color?.id ?? "default";
function getImagePath(path: string) {
return join(__dirname, "../../../public", path);
}
function getImageRect(fullPath: string): Rect.Rect {
const { width = 0, height = 0 } = sizeOf(fullPath);
return Rect.fromDimension(width, height);
}
function computeDeviceScreenRect(
screenCoordQuad: Quad.Quad,
deviceImageRect: Rect.Rect,
templateImageRect: Rect.Rect | null,
): Rect.Rect {
// Assume horizontally center aligned. Try to compute the screen coord space size
// by adding margins to the screen rect width
const screenCoordMinX = Math.min(...screenCoordQuad.map((c) => c[0]));
const screenCoordMaxX = Math.max(...screenCoordQuad.map((c) => c[0]));
// Try to guess the space size from screen coord quad
const guessScreenCoordSpaceSize = screenCoordMaxX + screenCoordMinX;
const screenCoordSpaceSize =
templateImageRect?.width ?? guessScreenCoordSpaceSize;
const imgToScreenCoordSpaceRatio =
deviceImageRect.width / screenCoordSpaceSize;
const mat = Matrix.composeTransformation(
// Scale to image space
Matrix.scale(imgToScreenCoordSpaceRatio),
// Scale to percentage space
Matrix.scale(100 / deviceImageRect.width, 100 / deviceImageRect.height),
);
return Rect.fromQuad(Quad.transformWithMatrix(screenCoordQuad, mat));
}
let imgRect: Rect.Rect | null = null;
let deviceScreenRect: Rect.Rect | null = null;
if (deviceDetail.imagePath != null && deviceDetail.imagePath.length >= 1) {
const templateImageRect =
deviceDetail.orientations[0].template_image_size != null
? Rect.fromDimension(
deviceDetail.orientations[0].template_image_size[0],
deviceDetail.orientations[0].template_image_size[1],
)
: null;
imgRect = getImageRect(getImagePath(deviceDetail.imagePath[0][0]));
deviceScreenRect = computeDeviceScreenRect(
deviceDetail.orientations[0].coords,
imgRect,
templateImageRect,
);
}
---

<script>
Expand Down Expand Up @@ -103,13 +168,49 @@ const defaultColorId = deviceDetail.color?.id ?? "default";
<div class="mockup-lg-left">
<div class="device">
<div class="upload__inner-box" data-color-id={defaultColorId}>
<img
class="upload__device-image"
src={deviceDetail.imagePath?.[0][0]}
alt={deviceDetail.imagePath?.[0][1]}
/>
<div class="upload__device-hint">
Upload <br /> Image Here
<div class="upload__image-wrapper">
<img
class="upload__device-image"
src={deviceDetail.imagePath?.[0][0]}
alt={deviceDetail.imagePath?.[0][1]}
/>
{
imgRect != null && deviceScreenRect != null ? (
<div class="upload__device-image-rect-wrapper">
<div
class:list={[
"upload__device-image-rect",
{
"w-full": imgRect.width >= imgRect.height,
"h-full": imgRect.height > imgRect.width,
},
]}
style={{
aspectRatio: `${imgRect.width} / ${imgRect.height}`,
}}
>
<div
class="upload__device-image-rect__screen-rect"
style={{
width: `${deviceScreenRect.width}%`,
height: `${deviceScreenRect.height}%`,
top: `${deviceScreenRect.centerY}%`,
left: `${deviceScreenRect.centerX}%`,
transform: "translate(-50%, -50%)",
}}
>
<div class="upload__device-hint pl-2 pr-2">
Upload <br /> Image Here
</div>
</div>
</div>
</div>
) : (
<div class="upload__device-hint">
Upload <br /> Image Here
</div>
)
}
</div>
</div>
</div>
Expand Down
28 changes: 15 additions & 13 deletions src/scripts/device_info.json
Original file line number Diff line number Diff line change
Expand Up @@ -3370,7 +3370,8 @@
[384, 1651]
],
"legacy_file": "samsung_d8000_front.png",
"name": "front"
"name": "front",
"template_image_size": [2500, 2500]
},
{
"alt": "samsung tv mockup psd",
Expand Down Expand Up @@ -3650,7 +3651,8 @@
[680, 1603]
],
"legacy_file": "galaxys4_black_portrait.png",
"name": "portrait"
"name": "portrait",
"template_image_size": [2000, 2000]
},
{
"alt": "galaxy s7 mockup",
Expand Down Expand Up @@ -3683,17 +3685,6 @@
"name": "Samsung Galaxy S4",
"short_name": "S4",
"orientations": [
{
"alt": "Samsung galaxy mockup",
"coords": [
[1600, 680],
[1600, 1367],
[397, 1367],
[397, 680]
],
"legacy_file": "galaxys4_white_landscape.png",
"name": "landscape"
},
{
"alt": "galaxy s6 mockup",
"coords": [
Expand All @@ -3704,6 +3695,17 @@
],
"legacy_file": "galaxys4_white_portrait.png",
"name": "portrait"
},
{
"alt": "Samsung galaxy mockup",
"coords": [
[1600, 680],
[1600, 1367],
[397, 1367],
[397, 680]
],
"legacy_file": "galaxys4_white_landscape.png",
"name": "landscape"
}
],
"available_perspectives": ["Portrait", "Landscape"],
Expand Down
9 changes: 8 additions & 1 deletion src/scripts/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,21 @@ import * as schema from "./parse/index";
export interface Orientation {
alt?: string;
name?: string;
coords: [
[number, number],
[number, number],
[number, number],
[number, number],
];
template_image_size?: [number, number];
}

export interface Device {
credits: string;
color_str: string;
meta_title: string;
meta_description: string;
display_resolution: number[];
display_resolution: [number, number];
device_id: string;
device_type: string;
name: string;
Expand Down
10 changes: 8 additions & 2 deletions src/scripts/parse/parseDevice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const RawDevice = z.object({
color_str: z.string(),
meta_title: z.string(),
meta_description: z.string(),
display_resolution: z.number().array(),
display_resolution: z.tuple([z.number(), z.number()]),
device_type: z.string(),
device_id: z.string(),
name: z.string(),
Expand All @@ -17,7 +17,13 @@ const RawDevice = z.object({
alt: z.string(),
name: z.string(),
legacy_file: z.optional(z.string()),
coords: z.number().array().array(),
coords: z.tuple([
z.tuple([z.number(), z.number()]),
z.tuple([z.number(), z.number()]),
z.tuple([z.number(), z.number()]),
z.tuple([z.number(), z.number()]),
]),
template_image_size: z.tuple([z.number(), z.number()]).optional(),
})
.array(),
available_perspectives: z.array(z.string()),
Expand Down
83 changes: 83 additions & 0 deletions src/scripts/utils/matrix.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { V2 } from "./vector";

export type M3 = [
[number, number, number],
[number, number, number],
[number, number, number],
];

export function multiplyM3V2(mat: M3, v2: V2): V2 {
const [[a, b, u], [c, d, v], [e, f, w]] = mat;
const [x, y, z] = [...v2, 1];
const res = [
a * x + b * y + u * z,
c * x + d * y + v * z,
e * x + f * y + w * z,
];
return [res[0], res[1]];
}

export function multiplyM3M3(mat1: M3, mat2: M3, ...mats: M3[]): M3 {
let res: M3 = mat1;
for (const m of [mat2, ...mats]) {
const [[a1, b1, u1], [c1, d1, v1], [e1, f1, w1]] = res;
const [[a2, b2, u2], [c2, d2, v2], [e2, f2, w2]] = m;
res = [
[
a1 * a2 + b1 * c2 + u1 * e2,
a1 * b2 + b1 * d2 + u1 * f2,
a1 * u2 + b1 * v2 + u1 * w2,
],
[
c1 * a2 + d1 * c2 + v1 * e2,
c1 * b2 + d1 * d2 + v1 * f2,
c1 * u2 + d1 * v2 + v1 * w2,
],
[
e1 * a2 + f1 * c2 + w1 * e2,
e1 * b2 + f1 * d2 + w1 * f2,
e1 * u2 + f1 * v2 + w1 * w2,
],
];
}
return res;
}

/**
* Construct a matrix which apply transforms in reverse order
* @param mat1
* @param mat2
* @param mats
* @returns
*/
export function composeTransformation(mat1: M3, mat2: M3, ...mats: M3[]): M3 {
let _mat1 = mat2;
let _mat2 = mat1;
let remaining: M3[] = [];
if (mats.length >= 2) {
_mat1 = mats[mats.length - 1];
_mat2 = mats[mats.length - 2];
remaining = [...mats.slice(0, mats.length - 2), mat2, mat1];
} else if (mats.length === 1) {
_mat1 = mats[mats.length - 1];
_mat2 = mat2;
remaining = [mat1];
}
return multiplyM3M3(_mat1, _mat2, ...remaining);
}

export function translate(x: number, y: number): M3 {
return [
[1, 0, x],
[0, 1, y],
[0, 0, 1],
];
}

export function scale(x: number, y: number = x): M3 {
return [
[x, 0, 0],
[0, y, 0],
[0, 0, 1],
];
}
23 changes: 23 additions & 0 deletions src/scripts/utils/quad.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { M3, multiplyM3V2 } from "./matrix";
import { V2 } from "./vector";

type Point = V2;
export type Quad = [Point, Point, Point, Point];

export function center(quad: Quad): Point {
const minX = Math.min(...quad.map((c) => c[0]));
const maxX = Math.max(...quad.map((c) => c[0]));
const minY = Math.min(...quad.map((c) => c[1]));
const maxY = Math.max(...quad.map((c) => c[1]));
return [(minX + maxX) / 2, (minY + maxY) / 2];
}

export function transformWithMatrix(quad: Quad, mat: M3): Quad {
const [p1, p2, p3, p4] = quad;
return [
multiplyM3V2(mat, p1),
multiplyM3V2(mat, p2),
multiplyM3V2(mat, p3),
multiplyM3V2(mat, p4),
];
}
Loading

0 comments on commit db95f2e

Please sign in to comment.