Compare commits

...

3 Commits

6 changed files with 95 additions and 8 deletions

View File

@ -21,7 +21,8 @@ class ConvertToComic implements ShouldQueue
{
$absolutePath = Storage::disk('public')->path($this->photoJob->image_path);
$photoprofile = Photoprofile::where('active', 1)->first();
$photoprofile = $this->photoJob->photoprofile
?? Photoprofile::where('active', 1)->first();
$photocommands = [];
foreach (explode(PHP_EOL, $photoprofile->commands) as $command) {
if (count($photocommands) > 0) $photocommands[] = ' && gmic ' . escapeshellarg($absolutePath) . ' ' . $command . ' -o ' . escapeshellarg($absolutePath);

View File

@ -4,6 +4,7 @@ namespace App\Livewire;
use App\Jobs\ConvertToComic;
use App\Models\PhotoJob;
use App\Models\Photoprofile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Livewire\Component;
@ -11,6 +12,12 @@ use Livewire\Component;
class CameraCapture extends Component
{
public string $status = '';
public ?int $photoprofileId = null;
public function mount(): void
{
$this->photoprofileId = Photoprofile::where('active', 1)->value('id');
}
public function delete(int $jobId): void
{
@ -39,6 +46,7 @@ class CameraCapture extends Component
$job = PhotoJob::create([
'image_path' => $filename,
'status' => 'processing',
'photoprofile_id' => $this->photoprofileId,
]);
ConvertToComic::dispatch($job);
@ -55,7 +63,8 @@ class CameraCapture extends Component
]);
$hasProcessing = $recentPhotos->contains('status', 'processing');
$photoprofiles = Photoprofile::where('active', 1)->pluck('name', 'id');
return view('livewire.camera-capture', compact('recentPhotos', 'hasProcessing'));
return view('livewire.camera-capture', compact('recentPhotos', 'hasProcessing', 'photoprofiles'));
}
}

View File

@ -3,8 +3,14 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\Photoprofile;
class PhotoJob extends Model
{
protected $fillable = ['image_path', 'status'];
protected $fillable = ['image_path', 'status', 'photoprofile_id'];
public function photoprofile()
{
return $this->belongsTo(Photoprofile::class);
}
}

View File

@ -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('photo_jobs', function (Blueprint $table) {
$table->foreignId('photoprofile_id')->nullable()->constrained('photoprofiles')->nullOnDelete();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('photo_jobs', function (Blueprint $table) {
$table->dropForeignIdFor(\App\Models\Photoprofile::class);
});
}
};

View File

@ -11,10 +11,41 @@ class PhotoprofileSeeder extends Seeder
{
$profiles = [
[
'name' => 'Standard',
'name' => 'Comic',
'active' => true,
'commands' => 'simplelocalcontrast_p 16,2,0,1,1,1,1,1,1,1,1,0
cl_comic 4,1,0,0,1,15,15,1,10,20,6,2,0,0,0,0,0,0,50,50',
],
[
'name' => 'Edges',
'active' => true,
'commands' => 'fx_canny 5,0.05,0.15,1',
],
[
'name' => 'Tron',
'active' => true,
'commands' => 'samj_chalkitup 5,2.5,1.5,50,1,5,5,0,0,7,0.8,1.9,7,0',
],
[
'name' => 'Warhol',
'active' => true,
'commands' => 'warhol 3,3,2,40',
],
[
'name' => 'SW-Comic',
'active' => true,
'commands' => 'simplelocalcontrast_p 16,2,0,1,1,1,1,1,1,1,1,0
cl_lineart 0,0,2,1,15,15,1,0,6,2,2,0,0,0,50,50',
],
[
'name' => 'Neon',
'active' => true,
'commands' => 'fx_gradient2rgb 0.58,0,5.8,0,0',
],
[
'name' => 'Neon 2',
'active' => true,
'commands' => 'fx_gcd_canny 1,0.05,0.15',
]
];

View File

@ -15,6 +15,15 @@
</div>
</div>
<div class="mt-6 w-full max-w-xs">
<select wire:model="photoprofileId"
class="w-full rounded-full bg-black/50 text-white border border-white/20 px-5 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-white/40 appearance-none text-center">
@foreach ($photoprofiles as $id => $name)
<option value="{{ $id }}">{{ $name }}</option>
@endforeach
</select>
</div>
<button id="capture-btn"
wire:loading.attr="disabled"
@disabled($hasProcessing)
@ -95,7 +104,10 @@
async function startCamera() {
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: { width: 640, height: 480 }, audio: false });
const stream = await navigator.mediaDevices.getUserMedia({
video: { width: { ideal: 4096 }, height: { ideal: 2160 } },
audio: false,
});
video.srcObject = stream;
} catch {
$wire.set('status', 'Camera access denied or unavailable.');
@ -129,9 +141,9 @@
triggerFlash();
canvas.width = 640;
canvas.height = 480;
canvas.getContext('2d').drawImage(video, 0, 0, 640, 480);
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
const imageData = canvas.toDataURL('image/jpeg', 0.9);
await $wire.capture(imageData);