Two related bugs that surfaced on the first 13.3" device's first photo: 1) Web-UI portrait preview was 90° sideways. DeviceApiController:: renderBinToPng rotated whenever the device was Portrait — correct for V1 (landscape-native, Portrait => renderer rotated, so preview un-rotates) but wrong for V2 (portrait-native — the renderer doesn't rotate, so the preview shouldn't either). Now mirrors the render-pipeline check: rotate only when `orientation !== model->nativeOrientation()`. Two new functional tests pin the V2 portrait and V2 landscape PNG dimensions to guard against regressions. 2) Cropped photo letterboxed on the 13.3" panel. CropEditor / StickerCanvas / FrameCard had V1 dimensions hardcoded (1600×960 = 5:3 aspect). V2 is 4:3 (1200×1600 portrait / 1600×1200 landscape), so a "full crop" came out the wrong shape and the server's white-canvas composite added bars. New `panelDims(model, orientation)` helper in @/types is the single source of truth on the frontend; matches DeviceModel::width/height on the server. Threaded `model` through Device serializer → Device type → UploadView → CropEditor / StickerCanvas, and HomeView → FrameCard. FrameCard tests updated to cover all four model × orientation placeholders. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ use App\Entity\Device;
|
||||
use App\Entity\Image;
|
||||
use App\Entity\RenderedAsset;
|
||||
use App\Entity\User;
|
||||
use App\Enum\DeviceModel;
|
||||
use App\Enum\Orientation;
|
||||
use App\Enum\RenderStatus;
|
||||
use App\Enum\RotationMode;
|
||||
@@ -277,6 +278,7 @@ class DeviceApiController extends AbstractController
|
||||
$device->getModel()->nativeWidth(),
|
||||
$device->getModel()->nativeHeight(),
|
||||
$device->getOrientation(),
|
||||
$device->getModel(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -289,7 +291,7 @@ class DeviceApiController extends AbstractController
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function renderBinToPng(string $binPath, string $pngPath, int $width, int $height, Orientation $orientation): void
|
||||
private function renderBinToPng(string $binPath, string $pngPath, int $width, int $height, Orientation $orientation, DeviceModel $model): void
|
||||
{
|
||||
$bin = (string) file_get_contents($binPath);
|
||||
$len = strlen($bin);
|
||||
@@ -311,10 +313,14 @@ class DeviceApiController extends AbstractController
|
||||
$im = new \Imagick();
|
||||
$im->readImageBlob($ppm);
|
||||
|
||||
// The .bin is always laid out in EPD-native scan order. For portrait,
|
||||
// the renderer pre-rotated the photo 90° CCW; rotate 90° here so the
|
||||
// browser-side preview shows the photo upright.
|
||||
if ($orientation === Orientation::Portrait) {
|
||||
// The .bin is always panel-native scan order. The render pipeline
|
||||
// rotates the source 90° CCW only when the user's orientation differs
|
||||
// from the panel's native — see RenderImageMessageHandler. Mirror that
|
||||
// here so the preview un-rotates exactly when the renderer rotated:
|
||||
// V1 (landscape-native) + Portrait → renderer rotated, preview rotates back.
|
||||
// V2 (portrait-native) + Portrait → renderer did NOT rotate, no rotate here.
|
||||
// V2 (portrait-native) + Landscape → renderer rotated, preview rotates back.
|
||||
if ($orientation !== $model->nativeOrientation()) {
|
||||
$im->rotateImage(new \ImagickPixel('white'), 90);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ final class DeviceSerializer
|
||||
'id' => $d->getId(),
|
||||
'mac' => $d->getMac(),
|
||||
'name' => $d->getName(),
|
||||
'model' => $d->getModel()->value,
|
||||
'orientation' => $d->getOrientation()->value,
|
||||
'rotationIntervalMinutes' => $d->getRotationIntervalMinutes(),
|
||||
'wakeTimes' => $d->getWakeTimes(),
|
||||
|
||||
Reference in New Issue
Block a user