SVGcode: Kafes resimleri SVG vektör grafiklerine dönüştüren bir PWA

SVGcode, JPG, PNG, GIF, WebP, AVIF gibi kafes resimleri SVG biçimindeki vektör grafiğe dönüştürmenize olanak tanıyan bir Progresif Web Uygulamasıdır. File System Access API, Async Clipboard API, File Handling API ve Window Controls Overlay özelleştirmesi kullanılır.

(Fazla okumayı tercih ediyorsanız bu makaleyi video olarak da bulabilirsiniz.)

Kafesten vektöre

Bir resmi ölçeklendirdikten sonra sonuç pikselleştirilmiş ve tatmin edici değil miydi? Öyleyse muhtemelen WebP, PNG veya JPG gibi kafes resim biçimleriyle uğraşmışsınızdır.

Kafes resmin ölçeklendirilmesi, resmin pikselleştirilmiş görünmesini sağlar.

Vektör grafikler ise, bir koordinat sisteminde noktalarla tanımlanan görüntülerdir. Bu noktalar, çokgenler ve başka şekiller oluşturmak üzere çizgiler ve eğrilerle birbirine bağlanır. Vektör grafikler, pikselleştirme olmadan herhangi bir çözünürlüğe ölçeklendirilebilmeleri açısından kafes grafiklere göre bir avantaja sahiptir.

Bir vektör resmin kalite kaybı olmadan ölçeklendirilmesi.

SVGcode ile tanışın

Kafes resimleri vektörlere dönüştürmenize yardımcı olabilecek SVGcode adlı bir PWA geliştirdim. Kredinin gerektiği yerlerde kredi: Bu yöntemi ben keşfetmedim. SVGcode ile sadece web uygulamasında kullanılabilmesi için Web Assembly'ye dönüştürdüğüm, Peter Selinger'in Potrace adlı komut satırı aracının omuzlarında duruyorum.

SVGcode uygulamasının ekran görüntüsü.
SVGcode uygulaması.

SVGcode'u kullanma

İlk olarak, uygulamanın nasıl kullanılacağını göstermek istiyorum. ChromiumDev Twitter kanalından indirdiğim Chrome Dev Summit'in tanıtım resmiyle başlıyorum. Bu, daha sonra SVGcode uygulamasına sürüklediğim bir PNG kafes resmi. Dosyayı bıraktığımda, girdinin vektörleştirilmiş sürümü görünene kadar uygulama, resmin rengini renge göre takip ediyor. Şimdi resmi yakınlaştırabiliyorum ve gördüğünüz gibi kenarlar keskin kalıyor. Ancak Chrome logosunu yakınlaştırdığınızda çizimin mükemmel olmadığını, özellikle de logonun dış çizgilerinin biraz benekli göründüğünü fark edebilirsiniz. Beş piksele kadar olan benekleri engelleyerek izdeki benekleri kaldırarak sonucu iyileştirebilirim.

Bırakılan bir resmi SVG'ye dönüştürme.

SVG kodunda posterleştirme

Vektörleştirmede, özellikle de fotoğraf görüntülerinde önemli bir adım, renk sayısını azaltmak için giriş görüntüsünün posterleştirilmesidir. SVGcode, bunu renk kanalına göre yapmamı ve değişiklik yaparken ortaya çıkan SVG'yi görmemi sağlıyor. Sonuçtan memnun kaldığımda, SVG'yi sabit diskime kaydedip istediğim yerde kullanabiliyorum.

Renk sayısını azaltmak için bir resmi posterleştirme.

SVGcode'da kullanılan API'ler

Artık uygulamanın yapabildiklerini gördüğünüze göre, bu sihri gerçekleştirmenize yardımcı olacak bazı API'leri göstereyim.

Progresif Web Uygulaması

SVGcode yüklenebilir bir Progresif Web Uygulamasıdır ve bu nedenle tamamen çevrimdışı özelliği etkin durumdadır. Uygulama, Vite.js'nin Vanilla JS şablonunu temel alır ve arka planda Workbox.js'yi kullanan bir hizmet çalışanı oluşturan popüler Vite eklentisi PWA'yı kullanır. Workbox, Progresif Web Uygulamaları için üretime hazır bir hizmet çalışanını destekleyebilecek bir kitaplık kümesidir. Bu kalıp, tüm uygulamalarda her zaman işe yaramayabilir ancak SVGcode'un kullanım alanı için çok işe yarar.

Pencere Denetimi Yer Paylaşımı

SVGcode, kullanılabilir ekran alanını en üst düzeye çıkarmak için ana menüsünü başlık çubuğu alanına taşıyarak Pencere Denetimleri Yer Paylaşımı özelleştirmesini kullanır. Bunun, yükleme akışının sonunda etkinleştirildiğini görebilirsiniz.

SVGcode'u yükleme ve Pencere Denetimi Yer Paylaşımı özelleştirmesini etkinleştirme.

File System Access API

Giriş resmi dosyalarını açmak ve elde edilen SVG'leri kaydetmek için File System Access API'yi kullanıyorum. Bu şekilde, daha önce açılan dosyaların referans bilgilerini saklayıp, uygulamayı yeniden yükledikten sonra bile kaldığım yerden devam edebiliyorum. Bir resim kaydedildiğinde, svgo kitaplığı aracılığıyla optimize edilir. Bu işlem, SVG'nin karmaşıklığına bağlı olarak biraz zaman alabilir. Dosya kaydetme iletişim kutusunun gösterilmesi için kullanıcı hareketi gerekir. Bu nedenle, dosya tanıtıcısının SVG optimizasyonu gerçekleşmeden önce alınması önemlidir. Böylece, optimize edilmiş SVG hazır olduğunda kullanıcı hareketi geçersiz kılınmaz.

try {
  let svg = svgOutput.innerHTML;
  let handle = null;
  // To not consume the user gesture obtain the handle before preparing the
  // blob, which may take longer.
  if (supported) {
    handle = await showSaveFilePicker({
      types: [{description: 'SVG file', accept: {'image/svg+xml': ['.svg']}}],
    });
  }
  showToast(i18n.t('optimizingSVG'), Infinity);
  svg = await optimizeSVG(svg);
  showToast(i18n.t('savedSVG'));
  const blob = new Blob([svg], {type: 'image/svg+xml'});
  await fileSave(blob, {description: 'SVG file'}, handle);
} catch (err) {
  console.error(err.name, err.message);
  showToast(err.message);
}

Sürükle ve bırak

Bir giriş resmini açmak için dosya açma özelliğini kullanabilirim veya yukarıda gördüğünüz gibi bir resim dosyasını uygulamaya sürükleyip bırakmanız yeterlidir. Dosya açma özelliği oldukça basittir, daha ilginç olan "sürükle ve bırak" işlevidir. Bunun özellikle güzel bir tarafı da veri aktarım öğesinden getAsFileSystemHandle() yöntemi aracılığıyla bir dosya sistemi herkese açık kullanıcı adı alabilmenizdir. Daha önce de belirtildiği gibi, bu herkese açık kullanıcı adını koruyabilirim. Böylece, uygulama yeniden yüklendiğinde hazır olur.

document.addEventListener('drop', async (event) => {
  event.preventDefault();
  dropContainer.classList.remove('dropenter');
  const item = event.dataTransfer.items[0];
  if (item.kind === 'file') {
    inputImage.addEventListener(
      'load',
      () => {
        URL.revokeObjectURL(blobURL);
      },
      {once: true},
    );
    const handle = await item.getAsFileSystemHandle();
    if (handle.kind !== 'file') {
      return;
    }
    const file = await handle.getFile();
    const blobURL = URL.createObjectURL(file);
    inputImage.src = blobURL;
    await set(FILE_HANDLE, handle);
  }
});

Daha fazla bilgi için File System Access API ile ilgili makaleye göz atın. Daha fazla bilgi için src/js/filesystem.js adresindeki SVGcode kaynak kodunu inceleyin.

Async Clipboard API

SVGcode ayrıca, Async Clipboard API'sı aracılığıyla işletim sisteminin panosuyla tam olarak entegre edilmiştir. Resmi yapıştır düğmesini tıklayarak veya klavyenizdeki komut ya da Ctrl ve v tuşlarına basarak işletim sisteminin dosya gezgininden uygulamaya resim yapıştırabilirsiniz.

Dosya gezgininden SVG koduna resim yapıştırma.

Async Clipboard API, kısa süre önce SVG resimlerinin işlenmesine olanak sağladı. Bu sayede, bir SVG resmini kopyalayıp daha fazla işlem için başka bir uygulamaya da yapıştırabilirsiniz.

SVGcode'dan SVGOMG'ye resim kopyalama.
copyButton.addEventListener('click', async () => {
  let svg = svgOutput.innerHTML;
  showToast(i18n.t('optimizingSVG'), Infinity);
  svg = await optimizeSVG(svg);
  const textBlob = new Blob([svg], {type: 'text/plain'});
  const svgBlob = new Blob([svg], {type: 'image/svg+xml'});
  navigator.clipboard.write([
    new ClipboardItem({
      [svgBlob.type]: svgBlob,
      [textBlob.type]: textBlob,
    }),
  ]);
  showToast(i18n.t('copiedSVG'));
});

Daha fazla bilgi edinmek için Async Clipboard makalesini okuyun veya dosyaya src/js/clipboard.js bakın.

Dosya İşleme

SVGcode'un en sevdiğim özelliklerinden biri, işletim sistemiyle uyum sağlaması. Yüklü bir PWA olarak, resim dosyaları için bir dosya işleyici, hatta varsayılan dosya işleyici olabilir. Yani macOS makinemdeki Finder'dayken bir resmi sağ tıklayıp SVGcode ile açabiliyorum. Dosya İşleme adlı bu özellik, Web Uygulaması Manifest dosyasındaki file_handlers özelliği ile uygulamanın iletilen dosyayı kullanmasına izin veren başlatma sırası temel alınarak çalışır.

Yüklü SVGcode uygulamasıyla bir dosyayı masaüstünden açma.
window.launchQueue.setConsumer(async (launchParams) => {
  if (!launchParams.files.length) {
    return;
  }
  for (const handle of launchParams.files) {
    const file = await handle.getFile();
    if (file.type.startsWith('image/')) {
      const blobURL = URL.createObjectURL(file);
      inputImage.addEventListener(
        'load',
        () => {
          URL.revokeObjectURL(blobURL);
        },
        {once: true},
      );
      inputImage.src = blobURL;
      await set(FILE_HANDLE, handle);
      return;
    }
  }
});

Daha fazla bilgi için Yüklü web uygulamalarının dosya işleyiciler olmasına izin verme başlıklı makaleye göz atın ve src/js/filehandling.js'te kaynak kodu görüntüleyin.

Web Paylaşımı (Dosyalar)

İşletim sistemine uyum sağlamanın bir başka örneği de uygulamanın paylaşım özelliğidir. SVGcode ile oluşturulmuş bir SVG'de düzenleme yapmak istediğimi varsayarsak, bu sorunu çözmenin bir yolu dosyayı kaydetmek, SVG düzenleme uygulamasını başlatmak ve ardından SVG dosyasını buradan açmaktır. Bununla birlikte, dosyaların doğrudan paylaşılmasına olanak tanıyan Web Paylaşımı API'sini kullanmak daha sorunsuz bir akıştır. Dolayısıyla, SVG düzenleme uygulaması bir paylaşım hedefiyse dosyayı sapma olmadan doğrudan alabilir.

shareSVGButton.addEventListener('click', async () => {
  let svg = svgOutput.innerHTML;
  svg = await optimizeSVG(svg);
  const suggestedFileName =
    getSuggestedFileName(await get(FILE_HANDLE)) || 'Untitled.svg';
  const file = new File([svg], suggestedFileName, { type: 'image/svg+xml' });
  const data = {
    files: [file],
  };
  if (navigator.canShare(data)) {
    try {
      await navigator.share(data);
    } catch (err) {
      if (err.name !== 'AbortError') {
        console.error(err.name, err.message);
      }
    }
  }
});
Gmail ile SVG resmi paylaşma.

Web Paylaşımı Hedefi (Dosyalar)

Öte yandan, SVGcode bir paylaşım hedefi olarak da çalışabilir ve diğer uygulamalardan dosya alabilir. Bunun çalışması için uygulamanın, işletim sistemine Web Paylaşımı Hedef API'si aracılığıyla ne tür verileri kabul edebileceğini bildirmesi gerekir. Bu işlem, Web Uygulaması Manifest'inde özel bir alan aracılığıyla gerçekleşir.

{
  "share_target": {
    "action": "https://svgco.de/share-target/",
    "method": "POST",
    "enctype": "multipart/form-data",
    "params": {
      "files": [
        {
          "name": "image",
          "accept": ["image/jpeg", "image/png", "image/webp", "image/gif"]
        }
      ]
    }
  }
}

action rotası aslında mevcut değil ancak yalnızca hizmet çalışanının fetch işleyicisinde işleniyor ve daha sonra alınan dosyaları uygulamada gerçek işlenmek üzere iletiyor.

self.addEventListener('fetch', (fetchEvent) => {
  if (
    fetchEvent.request.url.endsWith('/share-target/') &&
    fetchEvent.request.method === 'POST'
  ) {
    return fetchEvent.respondWith(
      (async () => {
        const formData = await fetchEvent.request.formData();
        const image = formData.get('image');
        const keys = await caches.keys();
        const mediaCache = await caches.open(
          keys.filter((key) => key.startsWith('media'))[0],
        );
        await mediaCache.put('shared-image', new Response(image));
        return Response.redirect('./?share-target', 303);
      })(),
    );
  }
});
Ekran görüntüsünü SVGcode ile paylaşma.

Sonuç

Tamam, SVGcode'daki gelişmiş uygulama özelliklerinden bazılarına kısa bir tur attık. Umarım bu uygulama, Squoosh veya SVGOMG gibi diğer muhteşem uygulamalarla birlikte resim işleme ihtiyaçlarınız için önemli bir araç haline gelir.

SVG kodu, svgco.de adresinde bulunabilir. Orada ne yaptığımı görüyor musun? Kaynak kodunu GitHub'da inceleyebilirsiniz. Potrace'in yanı sıra SVGcode'un da GPL lisanslı olduğunu unutmayın. Vektörelleştirme de harika! Umarım SVGcode yararlı olur ve bazı özellikleri bir sonraki uygulamanız için ilham kaynağı olur.

Teşekkür

Bu makale Joe Medley tarafından incelendi.