mirror of
https://github.com/usetrmnl/byos_laravel.git
synced 2026-01-13 23:18:10 +00:00
feat: support for additional devices
This commit is contained in:
parent
27ea7d1496
commit
d75d099490
4 changed files with 96 additions and 16 deletions
21
app/Enums/ImageFormat.php
Normal file
21
app/Enums/ImageFormat.php
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
enum ImageFormat: string
|
||||||
|
{
|
||||||
|
case AUTO = 'auto';
|
||||||
|
case PNG_8BIT_GRAYSCALE = 'png_8bit_grayscale';
|
||||||
|
case BMP3_1BIT_SRGB = 'bmp3_1bit_srgb';
|
||||||
|
case PNG_8BIT_256C = 'png_8bit_256c';
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::AUTO => 'Auto',
|
||||||
|
self::PNG_8BIT_GRAYSCALE => 'PNG 8-bit Grayscale Gray 2c',
|
||||||
|
self::BMP3_1BIT_SRGB => 'BMP3 1-bit sRGB 2c',
|
||||||
|
self::PNG_8BIT_256C => 'PNG 8-bit Grayscale Gray 256c',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Enums\ImageFormat;
|
||||||
use App\Models\Device;
|
use App\Models\Device;
|
||||||
use App\Models\Plugin;
|
use App\Models\Plugin;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
@ -38,21 +39,40 @@ class ImageGenerationService
|
||||||
throw new \RuntimeException('Failed to generate PNG: '.$e->getMessage(), 0, $e);
|
throw new \RuntimeException('Failed to generate PNG: '.$e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
switch ($device->image_format) {
|
||||||
if (isset($device->last_firmware_version)
|
case ImageFormat::BMP3_1BIT_SRGB->value:
|
||||||
&& version_compare($device->last_firmware_version, '1.5.2', '<')) {
|
try {
|
||||||
try {
|
ImageGenerationService::convertToBmpImageMagick($pngPath, $bmpPath);
|
||||||
ImageGenerationService::convertToBmpImageMagick($pngPath, $bmpPath);
|
} catch (\ImagickException $e) {
|
||||||
} catch (\ImagickException $e) {
|
throw new \RuntimeException('Failed to convert image to BMP: '.$e->getMessage(), 0, $e);
|
||||||
throw new \RuntimeException('Failed to convert image to BMP: '.$e->getMessage(), 0, $e);
|
}
|
||||||
}
|
break;
|
||||||
} else {
|
case ImageFormat::PNG_8BIT_GRAYSCALE->value:
|
||||||
try {
|
case ImageFormat::PNG_8BIT_256C->value:
|
||||||
ImageGenerationService::convertToPngImageMagick($pngPath, $device->width, $device->height, $device->rotate);
|
try {
|
||||||
} catch (\ImagickException $e) {
|
ImageGenerationService::convertToPngImageMagick($pngPath, $device->width, $device->height, $device->rotate, quantize: $device->image_format === ImageFormat::PNG_8BIT_GRAYSCALE);
|
||||||
throw new \RuntimeException('Failed to convert image to PNG: '.$e->getMessage(), 0, $e);
|
} catch (\ImagickException $e) {
|
||||||
}
|
throw new \RuntimeException('Failed to convert image to PNG: '.$e->getMessage(), 0, $e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ImageFormat::AUTO->value:
|
||||||
|
default:
|
||||||
|
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]);
|
$device->update(['current_screen_image' => $uuid]);
|
||||||
\Log::info("Device $device->id: updated with new image: $uuid");
|
\Log::info("Device $device->id: updated with new image: $uuid");
|
||||||
|
|
||||||
|
|
@ -77,7 +97,7 @@ class ImageGenerationService
|
||||||
/**
|
/**
|
||||||
* @throws \ImagickException
|
* @throws \ImagickException
|
||||||
*/
|
*/
|
||||||
private static function convertToPngImageMagick(string $pngPath, ?int $width, ?int $height, ?int $rotate): void
|
private static function convertToPngImageMagick(string $pngPath, ?int $width, ?int $height, ?int $rotate, $quantize = true): void
|
||||||
{
|
{
|
||||||
$imagick = new \Imagick($pngPath);
|
$imagick = new \Imagick($pngPath);
|
||||||
if ($width !== 800 || $height !== 480) {
|
if ($width !== 800 || $height !== 480) {
|
||||||
|
|
@ -87,7 +107,9 @@ class ImageGenerationService
|
||||||
$imagick->rotateImage(new ImagickPixel('black'), $rotate);
|
$imagick->rotateImage(new ImagickPixel('black'), $rotate);
|
||||||
}
|
}
|
||||||
$imagick->setImageType(\Imagick::IMGTYPE_GRAYSCALE);
|
$imagick->setImageType(\Imagick::IMGTYPE_GRAYSCALE);
|
||||||
$imagick->quantizeImage(2, \Imagick::COLORSPACE_GRAY, 0, true, false);
|
if ($quantize) {
|
||||||
|
$imagick->quantizeImage(2, \Imagick::COLORSPACE_GRAY, 0, true, false);
|
||||||
|
}
|
||||||
$imagick->setImageDepth(8);
|
$imagick->setImageDepth(8);
|
||||||
$imagick->stripImage();
|
$imagick->stripImage();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('devices', function (Blueprint $table) {
|
||||||
|
$table->string('image_format')->default('auto')->after('rotate');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('devices', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('image_format');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -16,6 +16,7 @@ new class extends Component {
|
||||||
public $width;
|
public $width;
|
||||||
public $height;
|
public $height;
|
||||||
public $rotate;
|
public $rotate;
|
||||||
|
public $image_format;
|
||||||
|
|
||||||
// Playlist properties
|
// Playlist properties
|
||||||
public $playlists;
|
public $playlists;
|
||||||
|
|
@ -41,6 +42,7 @@ new class extends Component {
|
||||||
$this->width = $device->width;
|
$this->width = $device->width;
|
||||||
$this->height = $device->height;
|
$this->height = $device->height;
|
||||||
$this->rotate = $device->rotate;
|
$this->rotate = $device->rotate;
|
||||||
|
$this->image_format = $device->image_format;
|
||||||
$this->playlists = $device->playlists()->with('items.plugin')->orderBy('created_at')->get();
|
$this->playlists = $device->playlists()->with('items.plugin')->orderBy('created_at')->get();
|
||||||
|
|
||||||
return view('livewire.devices.configure', [
|
return view('livewire.devices.configure', [
|
||||||
|
|
@ -68,6 +70,7 @@ new class extends Component {
|
||||||
'width' => 'required|integer|min:1',
|
'width' => 'required|integer|min:1',
|
||||||
'height' => 'required|integer|min:1',
|
'height' => 'required|integer|min:1',
|
||||||
'rotate' => 'required|integer|min:0|max:359',
|
'rotate' => 'required|integer|min:0|max:359',
|
||||||
|
'image_format' => 'required|string',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->device->update([
|
$this->device->update([
|
||||||
|
|
@ -78,6 +81,7 @@ new class extends Component {
|
||||||
'width' => $this->width,
|
'width' => $this->width,
|
||||||
'height' => $this->height,
|
'height' => $this->height,
|
||||||
'rotate' => $this->rotate,
|
'rotate' => $this->rotate,
|
||||||
|
'image_format' => $this->image_format,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Flux::modal('edit-device')->close();
|
Flux::modal('edit-device')->close();
|
||||||
|
|
@ -288,6 +292,11 @@ new class extends Component {
|
||||||
<flux:input label="Height (px)" wire:model="height" type="number"/>
|
<flux:input label="Height (px)" wire:model="height" type="number"/>
|
||||||
<flux:input label="Rotate °" wire:model="rotate" type="number"/>
|
<flux:input label="Rotate °" wire:model="rotate" type="number"/>
|
||||||
</div>
|
</div>
|
||||||
|
<flux:select label="Image Format" wire:model="image_format">
|
||||||
|
@foreach(\App\Enums\ImageFormat::cases() as $format)
|
||||||
|
<flux:select.option value="{{ $format->value }}">{{$format->label()}}</flux:select.option>
|
||||||
|
@endforeach
|
||||||
|
</flux:select>
|
||||||
<flux:input label="Default Refresh Interval (seconds)" wire:model="default_refresh_interval"
|
<flux:input label="Default Refresh Interval (seconds)" wire:model="default_refresh_interval"
|
||||||
type="number"/>
|
type="number"/>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue