Teknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor HaberleriTeknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor HaberleriTeknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor Haberleri
Yazı Tipi BoyutlandırıcıAa
  • Anasayfa
  • Teknoloji
    • Siber Güvenlik
    • Yapay Zeka
    • Donanım
    • Bilim
  • Yazılım
  • Savunma & İstihbarat
  • Oyun
  • Yaşam
    • Finans
    • Sinema
    • Dünyadan Haberler
  • İş Birliği
Okuma: Laravel’de HTML Faturayı Görsele Dönüştürme
Paylaş
Yazı Tipi BoyutlandırıcıAa
Teknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor HaberleriTeknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor Haberleri
Ara
Bizi Takip Et
  • Hakkımızda
  • Gizlilik politikası
  • Tanıtım Yazısı ve Backlink Hizmeti
© 2026 Teknomers. All Rights Reserved.

Anasayfa » Laravel’de HTML Faturayı Görsele Dönüştürme

Yazılım

Laravel’de HTML Faturayı Görsele Dönüştürme

teknomers
Son güncelleme: 5 Mayıs 2026 13:54
teknomers
Paylaş
Paylaş

PDF fatura oluşturmak için DomPDF ve wkhtmltopdf ile Snappy kullandım. Her ikisi de çalışıyor, ancak her biri istediğim görünümü sağlamıyor. DomPDF’nin CSS desteği 2012 civarında takılı kaldı ve Snappy, fontları Windows XP’de gibi render ediyor.

Beni iki kütüphaneden de uzaklaştıran, bir müşterinin faturalarının marka kılavuzuna uymasını istemesiydi. Inter fontu, aksan rengi için belirli bir hex, toplam satırında yuvarlak köşeler, satır öğelerinin altında hafif bir gölge ve sol üstte küçük bir logo gerekiyordu. DomPDF, Inter fontunu Times New Roman olarak renderladı. Snappy fontu doğru render etti ama border-radius’u bozdu. İkisinin de CSS grid desteği yoktu, bu yüzden billing ve shipping adreslerinin yan yana olduğu iki sütunlu header için istemediğim bir float hack yazmam gerekiyordu.

Aslında istediğim, bir Laravel Blade şablonunu Chrome’un render ettiği gibi görüntülemekti ve daha sonra e-posta atabileceğim, bir gösterge panosuna gömebileceğim veya PDF’ye koyabileceğim bir PNG almak istiyordum. Bu makale, bunu kendi sunucumda başsız bir tarayıcı çalıştırmadan nasıl başardığımı anlatıyor.


Neden yaygın Laravel fatura kütüphaneleri yetersiz?

PHP PDF kütüphanelerinin durumu, nazikçe ifade etmek gerekirse, tarihsel kalitede. DomPDF aktif olarak bakımda ancak render motoru CSS 2.1’in alt kümesi ve kısmi CSS 3 desteğiyle sınırlı; bu nedenle flexbox, grid, güvenilir webfontları ve göz ardı edilen veya render’ı çöken gölge/filtre özellikleri yok. “Burada bir sayı tablosu var” çıktısı için işe yarıyor. Tasarım ekibinizin görüşleri olduğunda işe yaramıyor.

Snappy (wkhtmltopdf aracılığıyla), bir süre daha sadık render yapıyordu, ancak wkhtmltopdf 2023’te arşivlendi. Hala çalışıyor ama güncellenmiyor. Ayrıca, zirve zamanlarında, font render’ı Chrome ile belirgin şekilde farklıydı; bu, çünkü tasarımcınız şablonu Chrome’da önizlemişti.

Modern hissiyat taşıyan bir seçenek, PHP’den exec çağrısıyla Puppeteer veya Playwright çalıştırmak ya da Browsershot gibi bir hizmet kullanmaktır. Bu işe yarıyor ama artık Laravel uygulamanızın yanı sıra bir Node.js yüklemesi, bir Chromium binary’si maintain etmeniz gerekiyor ve PHP’den buna exec çağrısı yapmak, debug etmekten pek hoşlanmadığım bir hata kategorisidir. Browsershot özellikle harika bir yazılım, ancak her ortamda CI ve üretim konteynerleriniz dahil, yüklemeniz, güncellemeniz ve çalışır durumda tutmanız gereken bir altyapıdır.

Beni bu sorundan kurtaran yaklaşım, faturayı kendi altyapımda render etmeye çalışmayı bırakmaktı. Blade şablonunun normalde yaptığı gibi HTML’yi render etmesine izin verin. O HTML’i bir API’ye gönderin. PNG’yi geri alın. Fatura tasarımı tamamen Blade ve CSS içinde yaşıyor; bu, başka bir Laravel görünümü gibi ve sunucumda hiçbir şey değişmek zorunda değil.


Kurulum

Ödeme olarak işaretlendiğinde bir PNG fatura oluşturan bir faturalama sistemi için çalışır bir uygulamayı adım adım açıklayacağım. Fatura, şirket detaylarıyla, bir satır öğesi tablosuyla, toplamlar bloğuyla ve ödeme koşullarıyla bir footer içerir. Her zaman bekleyebileceğiniz gibi.

Şu şablonla başlayın: resources/views/invoices/image.blade.php:


            

            

{{ $business['address'] }}
{{ $business['email'] }} - {{ $business['phone'] }}

Bill to

{{ $customer['name'] }}

{{ $customer['address'] }}

@foreach ($items as $item) @endforeach
Description Qty Unit Amount
{{ $item['description'] }} {{ $item['qty'] }} £{{ number_format($item['unit'], 2) }} £{{ number_format($item['qty'] * $item['unit'], 2) }}

Subtotal£{{ number_format($totals['subtotal'], 2) }}

VAT ({{ $totals['vat_rate'] }}%)£{{ number_format($totals['vat'], 2) }}

Total£{{ number_format($totals['total'], 2) }}

Payment due within 14 days. Bank transfer details on request.
{{ $business['name'] }} - Company no. {{ $business['company_no'] }}

Artık bir hizmet sınıfı, bir alan Faturasını alır, Blade şablonunu render eder, API’ye gönderir ve PNG baytlarını döndürür:

 config('invoicing.business'),
            'customer' => [
                'name' => $invoice->customer->name,
                'address' => $invoice->customer->formatted_address,
            ],
            'invoice' => [
                'number' => $invoice->number,
                'issued_at' => $invoice->issued_at->format('j F Y'),
                'due_at' => $invoice->due_at->format('j F Y'),
            ],
            'items' => $invoice->items->map(fn ($i) => [
                'description' => $i->description,
                'qty' => $i->quantity,
                'unit' => $i->unit_price,
            ])->all(),
            'totals' => [
                'subtotal' => $invoice->subtotal,
                'vat_rate' => $invoice->vat_rate,
                'vat' => $invoice->vat_amount,
                'total' => $invoice->total,
            ],
        ])->render();

        $response = Http::withToken($this->apiKey)
            ->timeout(30)
            ->post('https://api.html2img.com/v1/render', [
                'html' => $html,
                'viewport_width' => 800,
                'viewport_height' => 1100,
                'device_scale_factor' => 2,
                'wait_for_selector' => '.totals-row.total',
                'full_page' => true,
            ]);

        if ($response->failed()) {
            throw new RuntimeException(
                "Invoice render failed: {$response->status()} {$response->body()}"
            );
        }

        return $response->body();
    }
}

Bunu bir hizmet sağlayıcısında bağlayın veya doğrudan çözümleyin:

$renderer = new InvoiceImageRenderer(config('services.html2img.key'));
$png = $renderer->render($invoice);

Storage::disk('s3')->put("invoices/{$invoice->number}.png", $png);

Render çağrısındaki birkaç detayı belirtmek gerekir. full_page: true bu yöntemin faturalar için çalışmasını sağlıyor, çünkü bir faturanın yüksekliği, kaç satır öğesi olduğuna bağlı ve klipslemek veya uzatmak istemezsiniz. Görünüm genişliği 800 ile sabit kalır (bir belge için okunabilir bir genişlik) ve yükseklik, içerik gerektirdikçe değişir. wait_for_selector: '.totals-row.total' render işleminin tüm içerik ağacının monte edilmesinden sonra gerçekleşmesini garanti eder, bu, Google Font henüz yüklenmediyse önemlidir. device_scale_factor: 2 1600 piksel genişliğinde bir PNG verir, bu da retina ekranlarda veya basıldığında keskin görünmesini sağlar.

Blade, {{ $var }} kullanıldığında HTML kaçışını sizin için yapar, bu nedenle kullanıcıdan sağlanan veriler (müşteri isimleri ve adresler gibi) yerleşimi bozamaz veya markup enjekte edemez. Zengin metin kaynağından satır açıklamalarını alıyorsanız, {!! $var !!} kullanın, bu da sadece sunucu tarafında temizlendiğinden emin olduktan sonra yapılmalıdır.


Bilinmesi Gereken Tuzaklar

Fontlar, ilk çalıştırmada en büyük sürpriz kaynağıdır. @import, render içinde bir ağ gidiş dönüşü ekler. Binlerce fatura üretmek için bir üretim hattında, ya font dosyasını kendiniz barındırmalı ve @font-face ile kamuya açık bir URL aracılığıyla referans vermelisiniz ya da woff2’yi base64 ile encode edip inline kullanmalısınız. wait_for_selector seçeneği yardımcı olur, ancak eğer seçiciniz font yüklenene kadar görünüyorsa, hala bir an için geri dönüş alsınız. Üzerine küçük bir ms_delay eklemek (300-500ms) makul bir tam güvence sağlar.

Sayıların locale’den bağımsız formatlanması gerekir. number_format() varsayılan olarak ABD geleneklerine göre formatlar. Birleşik Krallık faturaları için number_format($amount, 2, '.', ',') kullanırım. Avrupa faturalarında, virgül ondalık ayırıcı olduğunda, argümanları değiştirin. Bunu üretimde yanlış yapmak utanç verici.

Faturaları, mümkünse bir web isteği içinde senkron olarak render etmeyin. Kuyruklayın. Laravel’in iş sistemini bu doğal olarak ele alır ve API, render işlemini asenkron yapmanız ve tamamlandığında bilgilendirilmeniz için webhook’ları destekler. Toplu işlemler için, webhook akışının substantially daha hızlı olduğu çünkü her render’da engelleme yapılmadığıdır.

Bir operasyonel not: fatura şablonunu versiyonlayın. Tasarımı değiştirdiğinizde, yeniden render edilen eski faturalar, orijinal versiyonlarından farklı görünecek ve bu muhasebe karışıklığına neden olabilir. Veya oluşturma zamanında render edilen PNG’yi S3’e snapshot olarak alıp servis edin ya da fatura üzerinde bir template_version sütunu dahil edin ve buna göre doğru Blade görünümünü seçin. Ben ilkini yapıyorum.

Laravel entegrasyonu hakkında daha derinlemesine bilgi için Laravel kullanım kılavuzuna başvurabilirsiniz; bu, HTTP istemci ayarı ve render ediciyi API’yi vurmadan test etme yöntemini kapsar. Daha uzun belgeler veya toplu çalışmalar için webhook parametre belgeleri, asenkron modelin nasıl olacağını açıklar. Faturalar ötesinde belge tarzı şablonları örnekleri görmek isterseniz, fatura ve makbuz örneği birkaç varyant içerir.

Görünümü render et, HTML’i gönder, PNG’yi kaydet. Blade şablonunuz, faturanın nasıl göründüğünün gerçek kaynağıdır; uygulamanızın geri kalanının gerçek kaynağı olduğu gibi.

Kaynak: Orijinal Makale

Contents
  • Neden yaygın Laravel fatura kütüphaneleri yetersiz?
  • Kurulum
  • Bilinmesi Gereken Tuzaklar
Deploynix Yol Haritası: Önümüzdeki Dönemde Neler Geliştiriyoruz ve Neden
Bir Kullanım Durumu, Üç Giriş Noktası: HTTP, CLI ve Kuyruk İşçileri Aynı Kodu Paylaşıyor – DEV Community
Laravel 13 17 Mart’ta çıkıyor — işte her yeni özellik ve kod örnekleri
LaraCopilot’un Laravel Dağıtım Riskini Yüzde 80 Azaltma Yöntemleri
Quiz Tabanlı Potansiyel Müşteri Oluşturma: Geliştirici Rehberi
Bu Makaleyi Paylaş
Facebook Bağlantıyı Kopyala Yazdır
Paylaş
Önceki Makale Dota 2 E-sporunda Şok Gelişme: Heroic Takımı Dağıldı
Sonraki Makale 1 Milyon Açık AI Servisini İnceledik: Güvenlik Durumu Kritik!

Sanal Medya

FacebookBeğen
452Takip Et
PinterestSabitle
237Takip Et

Son Eklenenler

HP, RTX 5080 oyun PC’sinde 2.600 $ indirim yaptı!
Donanım
$559 Nvidia RTX 5070 GPU, en uygun fiyatla 1440p oyun sunuyor
Donanım
Laravel’de Carbon (MultiCarbon) ile Jalali ve Hijri Tarihleri
Yazılım
DDR4 bellek ve anakart üretimi yeniden başlıyor, DDR5’siz geleceğe hazırlık
Donanım
AI token maliyetleri büyük bir sorun haline geliyor, OpenAI çözümler arıyor
Donanım
Elden Ring: Tarnished Edition Switch 2 İçin Ön Sipariş Fırsatları
Oyun
//

Siber güvenlik, yapay zeka ve savunma sanayiinden; finans ve sinema dünyasına uzanan geniş bir yelpaze. Teknomers; teknoloji, strateji ve yazılım dünyasını sade bir dille sizlerle buluşturuyor.

Kurumsal

  • Hakkımızda
  • Gizlilik politikası
  • Tanıtım Yazısı ve Backlink Hizmeti

Kategoriler

  • Teknoloji
  • Oyun
  • Sinema
  • Siber Güvenlik
  • Bilim
  • Finans
  • Dünyadan Güncel Haberler

Populer

  • TV'de Ücretsiz İzlenebilen Şifresiz Erotik Kanallar (2025 Güncel Frekans Listesi)

  • The Last of Us PC Kontrolleri: Hızlı Silah Değiştirme ve Tüm Tuşlar (2025)

  • Hogwarts Legacy'de Odaklanma İksiri Nasıl Yapılır?

Teknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor HaberleriTeknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor Haberleri
Bizi Takip Et
© 2026 Teknomers. All Rights Reserved.
Welcome Back!

Sign in to your account

Kullanıcı Adı veya E-posta Adresi
Şifre

Şifrenizi mi unuttunuz?