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.

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

Rastgele görüntüden 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.

Buna karşılık, vektör grafikleri bir koordinat sistemindeki noktalarla tanımlanan resimlerdir. Bu noktalar, poligonlar ve diğer şekiller oluşturmak için çizgiler ve eğrilerle birbirine bağlanır. Vektör grafiklerinin, pikselleşme olmadan herhangi bir çözünürlüğe ölçeklendirilebilmesi, raster grafiklere kıyasla bir avantajdır.

Kalite kaybı olmadan bir vektör resmini büyütme.

SVGcode ile tanışın

Rastır görselleri 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 kodu kullanma

Öncelikle uygulamayı nasıl kullanacağınızı göstermek istiyorum. ChromiumDev Twitter kanalından indirdiğim Chrome Dev Summit 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örelleştirilmiş 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, izlemenin mükemmel olmadığını ve özellikle de logonun ana hatlarının biraz benekli göründüğünü görebilirsiniz. Örneğin, beş piksele kadar olan noktaları bastırarak izlemede noktaları kaldırarak sonucu iyileştirebilirim.

Yerleştirilen 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 bir hizmet çalışanını destekleyebilecek bir kitaplık grubudur. Bu kalıp tüm uygulamalarda işe yaramayabilir ancak SVGcode'un kullanım alanı için mükemmeldir.

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.

SVG kodunu yükleme ve Pencere Denetimleri Yer Paylaşımı özelleştirmesini 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 verebilir ve uygulama yeniden yüklendikten sonra bile kaldığımız yerden devam edebiliriz. 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 yöntemidir. 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 Dosya Sistemi Erişimi API'si ile ilgili makaleyi inceleyin. Dilerseniz src/js/filesystem.js adresindeki SVGcode kaynak kodunu da inceleyebilirsiniz.

Async Clipboard API

SVGcode, Async Clipboard API aracılığıyla işletim sisteminin panosuyla da tam entegrasyon sağlar. Resmi yapıştır düğmesini tıklayarak veya klavyenizde komut tuşuna ya da kontrol tuşuna ve 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 Asenkron Pano makalesini okuyun veya src/js/clipboard.js dosyasını inceleyin.

Dosya İşleme

SVGcode'un en sevdiğim özelliklerinden biri, işletim sistemiyle uyumlu olması. Yüklü bir PWA olarak resim dosyaları için dosya işleyici veya hatta varsayılan dosya işleyici 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.

Yüklü SVGcode uygulamasıyla 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 için Yüklü web uygulamalarının dosya işleyici olmasına izin verme başlıklı makaleyi inceleyin ve src/js/filehandling.js 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 üzerinden 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ğildir ancak yalnızca hizmet çalışanının fetch işleyicisinde işlenir. Ardından, alınan dosyalar uygulamada gerçek işleme için aktarılır.

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'da 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 ederiz

Bu makale Joe Medley tarafından incelendi.