diff --git a/src/Enum/DeviceModel.php b/src/Enum/DeviceModel.php index a046339..abad0ad 100644 --- a/src/Enum/DeviceModel.php +++ b/src/Enum/DeviceModel.php @@ -39,6 +39,25 @@ enum DeviceModel: string }; } + /** + * Extra rotation in degrees applied AFTER the orientation-fit rotation, + * compensating for how the panel is physically mounted in its frame + * relative to the panel's scan-zero corner. + * + * V2 (13.3" Spectra-6): mounted with the ribbon at the bottom of a + * portrait photo (chosen physical mounting), opposite the panel's + * scan-zero corner. Needs a 180° flip so images render right-side-up. + * + * V1: no compensation — physical mount matches scan-zero. + */ + public function physicalRotationDegrees(): int + { + return match ($this) { + self::V1 => 0, + self::V2 => 180, + }; + } + /** User-facing width (pre-rotation) for the given orientation. */ public function width(Orientation $orientation): int { diff --git a/src/MessageHandler/RenderImageMessageHandler.php b/src/MessageHandler/RenderImageMessageHandler.php index f95a96c..92ce3f4 100644 --- a/src/MessageHandler/RenderImageMessageHandler.php +++ b/src/MessageHandler/RenderImageMessageHandler.php @@ -148,6 +148,14 @@ final class RenderImageMessageHandler $imagick->rotateImage(new \ImagickPixel('white'), -90); } + // Compensate for how the panel is physically mounted in its frame + // relative to its scan-zero corner. V2 ships ribbon-at-bottom of + // portrait, opposite scan-zero → needs 180° flip. V1 → 0. + $physRot = $model->physicalRotationDegrees(); + if ($physRot !== 0) { + $imagick->rotateImage(new \ImagickPixel('white'), $physRot); + } + // Build a strip of 6 palette pixels for remapImage $palImagick = new \Imagick(); foreach (self::PALETTE as $rgb) {