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

SVGcode, JPG, PNG, GIF, WebP, AVIF gibi raster resimleri SVG biçiminde vektör grafiklerine dönüştürmenize olanak tanıyan bir Progressive Web App'dir. File System Access API, Async Clipboard API, File Handling API ve Window Controls Overlay özelleştirmesini kullanır.

(İçerikleri okumak yerine izlemeyi tercih ediyorsanız bu makaleyi video olarak da bulabilirsiniz.)

Kafesten vektöre

Bir resmi ölçeklendirdiğinizde piksel piksel ve tatmin edici olmayan bir sonuç elde ettiğiniz oldu mu? Bu durumda, muhtemelen WebP, PNG veya JPG gibi bir raster resim biçimiyle uğraşıyordunuzdur.

Raster bir resmi büyütmek, resmin piksel piksel görünmesine neden olur.

Öte yandan, vektör grafikleri, bir koordinat sistemindeki noktalarla tanımlanan görüntülerdir. Bu noktalar çizgilerle ve eğrilerle bağlanarak poligonlar ve başka şekiller oluşturulur. Vektör grafiklerinin, pikselleşme olmadan herhangi bir çözünürlüğe ölçeklendirilebilmesi, raster grafiklere kıyasla bir avantajdır.

Kaliteden ödün vermeden bir vektör resmini ölçeklendirme.

SVGcode ile tanışın

Rastsal resimleri vektörlere dönüştürmenize yardımcı olabilecek SVGcode adlı bir PWA oluşturdum. Gerektiği durumlarda kredi verme: Bunu ben icat etmedim. SVGcode, Peter Selinger tarafından geliştirilen ve web uygulamasında kullanılabilmesi için Web Assembly'ye dönüştürdüğüm Potrace adlı bir komut satırı aracının üzerine inşa edilmiştir.

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

SVG kodunu kullanma

Öncelikle, uygulamanın nasıl kullanılacağını göstermek istiyorum. ChromiumDev Twitter kanalından indirdiğim Chrome Dev Summit için tanıtım resmiyle başlıyorum. Bu, SVGcode uygulamasına sürüklediğim bir PNG raster görüntüsüdür. Dosyayı bıraktığımda uygulama, girişin vektörel bir sürümü görünene kadar resmi renklere göre izler. Artık resmi yakınlaştırabilirim ve gördüğünüz gibi kenarlar keskin kalır. Ancak Chrome logosunu yakınlaştırdığınızda, çizimin mükemmel olmadığını ve özellikle logonun dış hatlarının biraz bozuk göründüğünü görebilirsiniz. Örneğin, beş piksele kadar olan noktaları bastırarak izlemede noktaları kaldırarak sonucu iyileştirebilirim.

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

SVG kodunda posterleştirme

Özellikle fotoğrafik görüntüler için vektörleştirmenin önemli bir adımı, renk sayısını azaltmak amacıyla giriş görüntüsünü posterize etmektir. SVGcode, bunu renk kanalı başına yapmama ve değişiklikleri yaparken ortaya çıkan SVG'yi görmeme olanak tanır. Sonuçtan memnun kaldığımda SVG'yi sabit diskime kaydedip istediğim yerde kullanabilirim.

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

SVGcode'da kullanılan API'ler

Uygulamanın neler yapabileceğini gördünüz. Şimdi de bu sihirlerin gerçekleşmesine yardımcı olan API'lerden bazılarını göstereceğim.

Progresif Web Uygulaması

SVGcode, yüklenebilir bir Progresif Web Uygulaması olduğundan tamamen çevrimdışı olarak kullanılabilir. Uygulama, Vite.js için Vanilla JS şablonunu temel alır ve popüler Vite eklentisi PWA'yı kullanır. Bu eklenti, arka planda Workbox.js kullanan bir hizmet çalışanı oluşturur. Workbox, progresif web uygulamaları için üretime hazır hizmet çalışanlarını destekleyebilen bir kitaplık grubudur. Bu kalıp, tüm uygulamalarda her zaman işe yaramayabilir ancak SVGcode'un kullanım alanı için idealdir.

Pencere Denetimi Yer Paylaşımı

SVGcode, mevcut ekran alanını en üst düzeye çıkarmak için ana menüsünü başlık çubuğu alanına taşıyarak pencere kontrolleri yer paylaşımı özelleştirmesini kullanır. Bu özelliğin, yükleme akışının sonunda etkinleştirildiğini görebilirsiniz.

SVGcode yükleme ve Window Controls Overlay özelleştirmeyi etkinleştirme

File System Access API

Giriş resim dosyalarını açmak ve elde edilen SVG'leri kaydetmek için File System Access API'yi kullanıyorum. Bu sayede, daha önce açtığım dosyalara referans tutabilir ve uygulama yeniden yüklendikten sonra bile kaldığım yerden devam edebilirim. Bir resim her 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 kutusunu göstermek için kullanıcı hareketi gerekir. Bu nedenle, SVG optimizasyonu yapılmadan önce dosya adını almak önemlidir. Böylece, optimize edilmiş SVG hazır olduğunda kullanıcı hareketi geçersiz olmaz.

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

Giriş resmini açmak için dosya açma özelliğini kullanabilir veya yukarıda gördüğünüz gibi bir resim dosyasını uygulamaya sürükleyip bırakabilirim. Dosya açma özelliği oldukça basittir. Daha ilginç olan sürükle ve bırak özelliğidir. Bu yöntemin en iyi yanı, getAsFileSystemHandle() yöntemi aracılığıyla veri aktarma öğesinden dosya sistemi tutamacını alabilmenizdir. Daha önce de belirtildiği gibi, bu herkese açık kullanıcı adını kalıcı hale getirebilirim. 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 makalesine göz atın ve ilgileniyorsanız src/js/filesystem.js adresindeki SVGcode kaynak kodunu inceleyin.

Async Clipboard API

SVGcode, Async Clipboard API'si aracılığıyla işletim sisteminin panosuyla da tamamen entegre edilmiştir. Resmi yapıştır düğmesini tıklayarak veya klavyenizde komut tuşuna ya da kontrol tuşuna artı v tuşuna basarak işletim sisteminin dosya gezgininden uygulamaya resim yapıştırabilirsiniz.

Dosya gezgininden bir resmi SVG koduna yapıştırma.

Async Clipboard API, kısa süre önce SVG resimleriyle de çalışabilme özelliğini kazandı. Böylece, bir SVG resmini kopyalayıp daha fazla işleme almak 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 Eşzamansız Pano makalesini okuyun veya dosyayı inceleyin src/js/clipboard.js.

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 bile olabilir. Bu, macOS makinemdeki Finder'dayken bir resmi sağ tıklayıp SVG koduyla açabileceğim anlamına geliyor. Dosya İşleme olarak adlandırılan bu özellik, Web Uygulaması Manifest'indeki file_handlers mülküne ve uygulamanın iletilen dosyayı kullanmasına olanak tanıyan başlatma sırasına göre çalışır.

SVGcode uygulaması yüklüyken masaüstünden bir dosyayı 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 edinmek için Yüklü web uygulamalarının dosya işleyici olmasına izin verme başlıklı makaleye göz atın ve src/js/filehandling.js'da kaynak kodunu görüntüleyin.

Web'de Paylaşım (Dosyalar)

İşletim sistemiyle uyumlu bir diğer örnek de uygulamanın paylaşma özelliğidir. SVGcode ile oluşturulan bir SVG'de düzenleme yapmak istediğimizi varsayalım. Bu sorunu çözmenin bir yolu, dosyayı kaydetmek, SVG düzenleme uygulamasını başlatmak ve ardından SVG dosyasını oradan açmaktır. Ancak daha sorunsuz bir akış için dosyaları doğrudan paylaşmanıza olanak tanıyan Web Share API'yi kullanabilirsiniz. Bu nedenle, SVG düzenleme uygulaması bir paylaşım hedefiyse dosyayı doğrudan, sapma olmadan 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);
      }
    }
  }
});
SVG resmini Gmail'de paylaşma.

Web Paylaşımı Hedefi (Dosyalar)

SVGcode, paylaşım hedefi olarak da kullanılabilir ve diğer uygulamalardan dosya alabilir. Bunun işe yaraması için uygulamanın, Web Paylaşımı Hedef API üzerinden işletim sistemine ne tür verileri kabul edebileceğini bildirmesi gerekir. Bu işlem, web uygulaması manifest'indeki ö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şlenir. Daha sonra, alınan dosyalar uygulamada gerçek işlemler için iletilir.

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);
      })(),
    );
  }
});
SVGcode'a ekran görüntüsü paylaşma.

Sonuç

Bu, SVGcode'daki gelişmiş uygulama özelliklerinden bazılarını içeren kısa bir turdu. Bu uygulamanın, Squoosh veya SVGOMG gibi diğer harika uygulamalarla birlikte resim işleme ihtiyaçlarınız için vazgeçilmez bir araç haline gelmesini umuyoruz.

SVGcode'u svgco.de adresinden edinebilirsiniz. Ne yaptığımı anladınız mı? Kaynak kodunu GitHub'da inceleyebilirsiniz. Potrace GPL lisanslı olduğundan SVGcode'un da GPL lisanslı olduğunu unutmayın. Bu konuyla ilgili olarak, iyi vektörleştirmeler dilerim. SVGcode'un işinize yarayacağını ve özelliklerinden bazılarının bir sonraki uygulamanıza ilham vereceğini umuyoruz.

Teşekkür

Bu makale Joe Medley tarafından incelendi.