diff --git a/app/Jobs/GenerateScreenJob.php b/app/Jobs/GenerateScreenJob.php
index 61e1305..b9661cc 100644
--- a/app/Jobs/GenerateScreenJob.php
+++ b/app/Jobs/GenerateScreenJob.php
@@ -29,10 +29,9 @@ class GenerateScreenJob implements ShouldQueue
*/
public function handle(): void
{
- $newImageUuid = ImageGenerationService::generateImage($this->markup);
+ $newImageUuid = ImageGenerationService::generateImage($this->markup, $this->deviceId);
Device::find($this->deviceId)->update(['current_screen_image' => $newImageUuid]);
- \Log::info("Device $this->deviceId: updated with new image: $newImageUuid");
if ($this->pluginId) {
// cache current image
diff --git a/app/Models/Device.php b/app/Models/Device.php
index 065793b..f7df91e 100644
--- a/app/Models/Device.php
+++ b/app/Models/Device.php
@@ -17,6 +17,9 @@ class Device extends Model
'proxy_cloud' => 'boolean',
'last_log_request' => 'json',
'proxy_cloud_response' => 'json',
+ 'width' => 'integer',
+ 'height' => 'integer',
+ 'rotate' => 'integer',
];
public function getBatteryPercentAttribute()
diff --git a/app/Models/User.php b/app/Models/User.php
index 5528c2c..ffe8c97 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -25,7 +25,7 @@ class User extends Authenticatable // implements MustVerifyEmail
'email',
'password',
'assign_new_devices',
- 'assign_new_device_id'
+ 'assign_new_device_id',
];
/**
diff --git a/app/Services/ImageGenerationService.php b/app/Services/ImageGenerationService.php
index a9e1b3b..faa90ba 100644
--- a/app/Services/ImageGenerationService.php
+++ b/app/Services/ImageGenerationService.php
@@ -5,13 +5,16 @@ namespace App\Services;
use App\Models\Device;
use App\Models\Plugin;
use Illuminate\Support\Facades\Storage;
+use ImagickPixel;
use Ramsey\Uuid\Uuid;
use Spatie\Browsershot\Browsershot;
use Wnx\SidecarBrowsershot\BrowsershotLambda;
class ImageGenerationService
{
- public static function generateImage(string $markup): string {
+ public static function generateImage(string $markup, $deviceId): string
+ {
+ $device = Device::find($deviceId);
$uuid = Uuid::uuid4()->toString();
$pngPath = Storage::disk('public')->path('/images/generated/'.$uuid.'.png');
$bmpPath = Storage::disk('public')->path('/images/generated/'.$uuid.'.bmp');
@@ -20,7 +23,7 @@ class ImageGenerationService
if (config('app.puppeteer_mode') === 'sidecar-aws') {
try {
BrowsershotLambda::html($markup)
- ->windowSize($device->width ?? 800, $device->height ?? 480)
+ ->windowSize(800, 480)
->save($pngPath);
} catch (\Exception $e) {
throw new \RuntimeException('Failed to generate PNG: '.$e->getMessage(), 0, $e);
@@ -29,18 +32,30 @@ class ImageGenerationService
try {
Browsershot::html($markup)
->setOption('args', config('app.puppeteer_docker') ? ['--no-sandbox', '--disable-setuid-sandbox', '--disable-gpu'] : [])
- ->windowSize($device->width ?? 800, $device->height ?? 480)
+ ->windowSize(800, 480)
->save($pngPath);
} catch (\Exception $e) {
throw new \RuntimeException('Failed to generate PNG: '.$e->getMessage(), 0, $e);
}
}
- try {
- ImageGenerationService::convertToBmpImageMagick($pngPath, $bmpPath);
- } catch (\ImagickException $e) {
- throw new \RuntimeException('Failed to convert image to BMP: '.$e->getMessage(), 0, $e);
+ if (isset($device->last_firmware_version)
+ && version_compare($device->last_firmware_version, '1.5.2', '<')) {
+ try {
+ ImageGenerationService::convertToBmpImageMagick($pngPath, $bmpPath);
+ } catch (\ImagickException $e) {
+ throw new \RuntimeException('Failed to convert image to BMP: '.$e->getMessage(), 0, $e);
+ }
+ } else {
+ try {
+ ImageGenerationService::convertToPngImageMagick($pngPath, $device->width, $device->height, $device->rotate);
+ } catch (\ImagickException $e) {
+ throw new \RuntimeException('Failed to convert image to PNG: '.$e->getMessage(), 0, $e);
+ }
}
+ $device->update(['current_screen_image' => $uuid]);
+ \Log::info("Device $device->id: updated with new image: $uuid");
+
return $uuid;
}
@@ -59,6 +74,28 @@ class ImageGenerationService
$imagick->clear();
}
+ /**
+ * @throws \ImagickException
+ */
+ private static function convertToPngImageMagick(string $pngPath, ?int $width, ?int $height, ?int $rotate): void
+ {
+ $imagick = new \Imagick($pngPath);
+ if ($width !== 800 || $height !== 480) {
+ $imagick->resizeImage($width, $height, \Imagick::FILTER_LANCZOS, 1, true);
+ }
+ if ($rotate !== null && $rotate !== 0) {
+ $imagick->rotateImage(new ImagickPixel('black'), $rotate);
+ }
+ $imagick->setImageType(\Imagick::IMGTYPE_GRAYSCALE);
+ $imagick->quantizeImage(2, \Imagick::COLORSPACE_GRAY, 0, true, false);
+ $imagick->setImageDepth(8);
+ $imagick->stripImage();
+
+ $imagick->setFormat('png');
+ $imagick->writeImage($pngPath);
+ $imagick->clear();
+ }
+
public static function cleanupFolder(): void
{
$activeDeviceImageUuids = Device::pluck('current_screen_image')->filter()->toArray();
diff --git a/config/app.php b/config/app.php
index e5b3078..444d0ac 100644
--- a/config/app.php
+++ b/config/app.php
@@ -130,7 +130,7 @@ return [
'force_https' => env('FORCE_HTTPS', false),
'puppeteer_docker' => env('PUPPETEER_DOCKER', false),
'puppeteer_mode' => env('PUPPETEER_MODE', 'local'),
-
+
/*
|--------------------------------------------------------------------------
| Application Version
diff --git a/database/migrations/2025_05_10_202133_add_rotate_to_devices_table.php b/database/migrations/2025_05_10_202133_add_rotate_to_devices_table.php
new file mode 100644
index 0000000..e439b1b
--- /dev/null
+++ b/database/migrations/2025_05_10_202133_add_rotate_to_devices_table.php
@@ -0,0 +1,22 @@
+integer('rotate')->nullable()->default(0)->after('width');
+ });
+ }
+
+ public function down(): void
+ {
+ Schema::table('devices', function (Blueprint $table) {
+ $table->dropColumn('rotate');
+ });
+ }
+};
diff --git a/resources/views/livewire/device-dashboard.blade.php b/resources/views/livewire/device-dashboard.blade.php
index f7720c0..e21428d 100644
--- a/resources/views/livewire/device-dashboard.blade.php
+++ b/resources/views/livewire/device-dashboard.blade.php
@@ -59,7 +59,7 @@ new class extends Component {
@elseif($current_image_path)
+
@endif
diff --git a/resources/views/livewire/devices/configure.blade.php b/resources/views/livewire/devices/configure.blade.php
index 05573cc..ffd2ebc 100644
--- a/resources/views/livewire/devices/configure.blade.php
+++ b/resources/views/livewire/devices/configure.blade.php
@@ -15,6 +15,7 @@ new class extends Component {
public $default_refresh_interval;
public $width;
public $height;
+ public $rotate;
// Playlist properties
public $playlists;
@@ -39,6 +40,7 @@ new class extends Component {
$this->default_refresh_interval = $device->default_refresh_interval;
$this->width = $device->width;
$this->height = $device->height;
+ $this->rotate = $device->rotate;
$this->playlists = $device->playlists()->with('items.plugin')->orderBy('created_at')->get();
return view('livewire.devices.configure', [
@@ -65,6 +67,7 @@ new class extends Component {
'default_refresh_interval' => 'required|integer|min:1',
'width' => 'required|integer|min:1',
'height' => 'required|integer|min:1',
+ 'rotate' => 'required|integer|min:0|max:359',
]);
$this->device->update([
@@ -74,6 +77,7 @@ new class extends Component {
'default_refresh_interval' => $this->default_refresh_interval,
'width' => $this->width,
'height' => $this->height,
+ 'rotate' => $this->rotate,
]);
Flux::modal('edit-device')->close();
@@ -215,7 +219,7 @@ new class extends Component {