register for sessions. photos with different settings, settings configurable
This commit is contained in:
1 parent
5fd29ef5f3
commit
17c1c2a521
14 files changed
+515
-71
No files matched your search
@@ -20,9 +20,12 @@ class ConvertToComic implements ShouldQueue
|
||||
{
|
||||
$absolutePath = Storage::disk('public')->path($this->photoJob->image_path);
|
||||
|
||||
$gmicOps = $this->photoJob->setting?->gmic_command
|
||||
?? 'cl_comic 4,1,0,0,1,15,15,1,10,20,6,2,0,0,0,0,0,0,50,50';
|
||||
|
||||
$result = Process::timeout(0)->run(
|
||||
'gmic ' . escapeshellarg($absolutePath) .
|
||||
' cl_comic 4,1,0,0,1,15,15,1,10,20,6,2,0,0,0,0,0,0,50,50' .
|
||||
' ' . $gmicOps .
|
||||
' -o ' . escapeshellarg($absolutePath)
|
||||
);
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace App\Livewire;
|
||||
|
||||
use App\Jobs\ConvertToComic;
|
||||
use App\Models\PhotoJob;
|
||||
use App\Models\PhotoSession;
|
||||
use App\Models\PhotoSetting;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
@@ -12,17 +14,6 @@ class CameraCapture extends Component
|
||||
{
|
||||
public string $status = '';
|
||||
|
||||
public function delete(int $jobId): void
|
||||
{
|
||||
$job = PhotoJob::find($jobId);
|
||||
if (!$job) return;
|
||||
|
||||
Storage::disk('public')->delete($job->image_path);
|
||||
$job->delete();
|
||||
|
||||
$this->status = "Job #{$jobId} deleted";
|
||||
}
|
||||
|
||||
public function capture(string $imageData): void
|
||||
{
|
||||
if (!preg_match('/^data:image\/(\w+);base64,/', $imageData, $type)) {
|
||||
@@ -31,31 +22,66 @@ class CameraCapture extends Component
|
||||
}
|
||||
|
||||
$extension = strtolower($type[1]);
|
||||
$filename = 'photos/' . Str::uuid() . '.' . $extension;
|
||||
$raw = base64_decode(substr($imageData, strpos($imageData, ',') + 1));
|
||||
|
||||
Storage::disk('public')->put($filename, $raw);
|
||||
$originalPath = 'photos/' . Str::uuid() . '.' . $extension;
|
||||
Storage::disk('public')->put($originalPath, $raw);
|
||||
|
||||
$job = PhotoJob::create([
|
||||
'image_path' => $filename,
|
||||
'status' => 'processing',
|
||||
]);
|
||||
$session = PhotoSession::create(['original_image_path' => $originalPath]);
|
||||
|
||||
ConvertToComic::dispatch($job);
|
||||
$settings = PhotoSetting::active()->get();
|
||||
|
||||
$this->status = "Processing photo…";
|
||||
foreach ($settings as $setting) {
|
||||
$variantPath = 'photos/' . Str::uuid() . '.' . $extension;
|
||||
Storage::disk('public')->put($variantPath, $raw);
|
||||
|
||||
$job = PhotoJob::create([
|
||||
'image_path' => $variantPath,
|
||||
'status' => 'processing',
|
||||
'photo_session_id' => $session->id,
|
||||
'photo_setting_id' => $setting->id,
|
||||
]);
|
||||
|
||||
ConvertToComic::dispatch($job);
|
||||
}
|
||||
|
||||
$this->status = count($settings) . ' Varianten werden erstellt…';
|
||||
}
|
||||
|
||||
public function selectVariant(int $sessionId, int $jobId): void
|
||||
{
|
||||
PhotoSession::where('id', $sessionId)->update(['selected_job_id' => $jobId]);
|
||||
}
|
||||
|
||||
public function deleteSession(int $sessionId): void
|
||||
{
|
||||
$session = PhotoSession::with('jobs')->find($sessionId);
|
||||
if (!$session) return;
|
||||
|
||||
foreach ($session->jobs as $job) {
|
||||
Storage::disk('public')->delete($job->image_path);
|
||||
$job->delete();
|
||||
}
|
||||
|
||||
Storage::disk('public')->delete($session->original_image_path);
|
||||
$session->delete();
|
||||
|
||||
$this->status = "Session #{$sessionId} gelöscht";
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
$recentPhotos = PhotoJob::latest()->take(10)->get()->map(fn($job) => [
|
||||
'id' => $job->id,
|
||||
'url' => Storage::disk('public')->url($job->image_path) . '?v=' . $job->updated_at->timestamp,
|
||||
'status' => $job->status,
|
||||
]);
|
||||
$sessions = PhotoSession::latest()->take(10)->get();
|
||||
|
||||
$hasProcessing = $recentPhotos->contains('status', 'processing');
|
||||
foreach ($sessions as $session) {
|
||||
$session->setRelation('jobs', $session->jobs()->with('setting')->orderBy('photo_setting_id')->get());
|
||||
}
|
||||
|
||||
return view('livewire.camera-capture', compact('recentPhotos', 'hasProcessing'));
|
||||
$currentSession = $sessions->first();
|
||||
$previousSessions = $sessions->skip(1);
|
||||
|
||||
$hasProcessing = $currentSession && $currentSession->jobs->contains('status', 'processing');
|
||||
|
||||
return view('livewire.camera-capture', compact('currentSession', 'previousSessions', 'hasProcessing'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\PhotoSetting;
|
||||
use Livewire\Component;
|
||||
|
||||
class PhotoSettings extends Component
|
||||
{
|
||||
public array $editingId = [];
|
||||
public array $editName = [];
|
||||
public array $editCommand = [];
|
||||
public bool $showForm = false;
|
||||
public string $newName = '';
|
||||
public string $newCommand = '';
|
||||
|
||||
public function toggleActive(int $id): void
|
||||
{
|
||||
$setting = PhotoSetting::findOrFail($id);
|
||||
$setting->update(['is_active' => !$setting->is_active]);
|
||||
}
|
||||
|
||||
public function startEdit(int $id, string $name, string $command): void
|
||||
{
|
||||
$this->editingId = [$id => true];
|
||||
$this->editName[$id] = $name;
|
||||
$this->editCommand[$id] = $command;
|
||||
}
|
||||
|
||||
public function saveEdit(int $id): void
|
||||
{
|
||||
PhotoSetting::findOrFail($id)->update([
|
||||
'name' => trim($this->editName[$id] ?? ''),
|
||||
'gmic_command' => trim($this->editCommand[$id] ?? ''),
|
||||
]);
|
||||
unset($this->editingId[$id]);
|
||||
}
|
||||
|
||||
public function cancelEdit(int $id): void
|
||||
{
|
||||
unset($this->editingId[$id]);
|
||||
}
|
||||
|
||||
public function addSetting(): void
|
||||
{
|
||||
$name = trim($this->newName);
|
||||
$command = trim($this->newCommand);
|
||||
|
||||
if (!$name || !$command) return;
|
||||
|
||||
$max = PhotoSetting::max('sort_order') ?? 0;
|
||||
PhotoSetting::create([
|
||||
'name' => $name,
|
||||
'gmic_command' => $command,
|
||||
'sort_order' => $max + 1,
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
$this->newName = '';
|
||||
$this->newCommand = '';
|
||||
$this->showForm = false;
|
||||
}
|
||||
|
||||
public function delete(int $id): void
|
||||
{
|
||||
PhotoSetting::findOrFail($id)->delete();
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.photo-settings', [
|
||||
'settings' => PhotoSetting::orderBy('sort_order')->get(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
+12
-1
@@ -3,8 +3,19 @@
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class PhotoJob extends Model
|
||||
{
|
||||
protected $fillable = ['image_path', 'status'];
|
||||
protected $fillable = ['image_path', 'status', 'photo_session_id', 'photo_setting_id'];
|
||||
|
||||
public function session(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(PhotoSession::class, 'photo_session_id');
|
||||
}
|
||||
|
||||
public function setting(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(PhotoSetting::class, 'photo_setting_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class PhotoSession extends Model
|
||||
{
|
||||
protected $fillable = ['original_image_path', 'selected_job_id'];
|
||||
|
||||
public function jobs(): HasMany
|
||||
{
|
||||
return $this->hasMany(PhotoJob::class)->with('setting')->orderBy('photo_setting_id');
|
||||
}
|
||||
|
||||
public function selectedJob(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(PhotoJob::class, 'selected_job_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class PhotoSetting extends Model
|
||||
{
|
||||
protected $fillable = ['name', 'gmic_command', 'sort_order', 'is_active'];
|
||||
|
||||
protected $casts = ['is_active' => 'boolean'];
|
||||
|
||||
public function jobs(): HasMany
|
||||
{
|
||||
return $this->hasMany(PhotoJob::class);
|
||||
}
|
||||
|
||||
public function scopeActive($query)
|
||||
{
|
||||
return $query->where('is_active', true)->orderBy('sort_order');
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user