SVGcode:將光柵圖片轉換為 SVG 向量圖形的 PWA

SVGcode 是漸進式網頁應用程式,可將 JPG、PNG、GIF、WebP、AVIF 等光柵圖片轉換成 SVG 格式的向量圖形。這個 API 使用 File System Access API、Async Clipboard API、File Handling API,以及視窗控制項疊加層自訂功能。

,瞭解如何調查及移除這項存取權。
(如果你偏好觀看,也可以用影片格式觀看這篇文章)。

從光柵化到向量

您是否曾調整圖片,但結果有像素化但不滿意?如果 您應該留意到光柵圖片格式 例如 WebP、PNG 或 JPG

放大光柵圖片,讓圖片看起來像素化。

相反地,向量圖形是透過座標系統中的點定義的圖片。這些 用線條和曲線連接點,形成多邊形和其他形狀。向量圖形具有 優於光柵圖形,可以放大或縮小至任何解析度 不會像素化

放大向量圖片,不損及品質。

SVGcode 簡介

我建構了名為 SVGcode 的 PWA,可協助您將光柵圖片轉換成 建立向量標明出處:我沒有這麼做。透過 SVGcode 名為 Potrace 的命令列工具的肩膀。 Peter Selinger 已轉換成 Web Assembly,因此可在 網頁應用程式。

SVGcode 應用程式螢幕截圖。
SVGcode 應用程式。

使用 SVGcode

首先來談談如何使用應用程式。我會從 Chrome 開發人員高峰會的前導廣告圖片開始 這是我從 ChromiumDev Twitter 頻道下載的這是我安裝的 PNG 光柵圖片 拖曳到 SVGcode 應用程式放置檔案時,應用程式會追蹤圖片的顏色, 直到輸入的向量化版本為止接著就能放大圖片 邊緣保持清晰但放大 Chrome 標誌時,您會發現繪製作業並未 最完美的標誌,尤其是標誌的輪廓 看起來有點模糊不清就能改善搜尋結果 忽略最高像素 (5 個像素) 的譜系,藉此消除追蹤。

將已捨棄的圖片轉換為 SVG。

SVG 程式碼中的海報

向量的一個重要步驟,尤其是攝影圖像的部分,就是將輸入內容延後 減少顏色數量SVG 程式碼能讓我根據不同顏色管道進行這項作業 產生的 SVG如果滿意結果,可以將可擴充向量圖形儲存到硬碟 而且隨時隨地都可以使用

調整圖片以減少色彩數量。

SVG 程式碼中使用的 API

現在您已瞭解這個應用程式的眾多功能,接著我將介紹幾個 API 神奇的神奇效果

漸進式網頁應用程式

SVGcode 是可安裝的漸進式網頁應用程式,因此可完全啟用離線功能。應用程式是以 的 Vanilla JS 範本 適用於 Vite.js,並使用熱門 Vite 外掛程式 PWA,可建立具有下列需求的 Service Worker: 實際上卻使用 Workbox.js。Workbox 為集合 一系列程式庫,為漸進式網頁應用程式提供可投入實際工作環境的服務工作人員,這種模式 不一定適用於所有應用程式,但在 SVGcode 的用途上是很好的選擇。

視窗控制項重疊

為了盡可能增加可用的螢幕空間,SVGcode 會使用 視窗控制項重疊自訂功能,將主選單移至上方 標題列區域在安裝流程結束時,您可以看到系統已啟用這個功能。

安裝 SVGcode,並啟用視窗控制項疊加層自訂功能。

File System Access API

如要開啟輸入圖片檔並儲存產生的 SVG,我使用 File System Access API。這可以讓我保留 先前開啟的檔案,即使應用程式重新載入後,也能從上次中斷的地方繼續瀏覽。當圖片擷取到 則會透過 svgo 程式庫進行最佳化,這可能需要一點時間 會視 SVG 的複雜度而定使用者必須做出手勢才能顯示檔案儲存對話方塊。是 因此,請務必在執行 SVG 最佳化前取得檔案控制代碼,這樣使用者 但在最佳化 SVG 準備就緒時,手勢不會失效。

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);
}

拖曳

在開啟輸入圖片的情況下,我可以使用檔案開啟功能,或是如上所示 將圖片檔拖曳到應用程式檔案開啟功能相當簡單直覺 有趣的是拖曳式大小寫最棒的是,您可以 可透過 getAsFileSystemHandle()敬上 方法。如先前所述,我可以保留這個帳號代碼,以便在應用程式重新載入時使用。

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);
  }
});

詳情請參閱 File System Access API 一文,以及 有興趣的話,請前往 src/js/filesystem.js

Async Clipboard API

SVGcode 也會透過 Async Clipboard API,與作業系統的剪貼簿完全整合。 您只要按一下 「貼上圖片」按鈕,或是按下鍵盤上的 Command 鍵或 Control 鍵 + v 鍵。

將檔案探索工具中的圖片貼到 SVG 程式碼。

Async Clipboard API 最近也能夠處理 SVG 圖片,因此 複製 SVG 圖片,並貼到其他應用程式中,以便進行後續處理。

將 SVGcode 中的圖片複製到 SVGOMG。
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'));
});

詳情請參閱非同步剪貼簿文章,或查看 src/js/clipboard.js

檔案處理

SVGcode 最受喜愛的功能之一,就是能與作業系統完美融合。身為 即可成為圖片檔的檔案處理常式,甚至是預設的檔案處理常式。這個 所以當您在 macOS 電腦上開啟 Finder 時,可以在圖片上按一下滑鼠右鍵 SVG。這項功能稱為「檔案處理」,並以 網頁應用程式資訊清單和啟動佇列,允許應用程式使用傳遞的檔案。

從已安裝 SVGcode 應用程式的電腦上開啟檔案。
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;
    }
  }
});

詳情請參閱允許安裝的網頁應用程式做為檔案處理常式,並在 src/js/filehandling.js

網路分享 (檔案)

另一個融入作業系統的例子是應用程式的分享功能。假設 對使用 SVG 程式碼建立的 SVG 進行編輯,其中一種方法是儲存檔案。 啟動 SVG 編輯應用程式,然後從中開啟可擴充向量圖形檔案。但更流暢的流程是 使用 Web Share API,如此即可直接共用檔案。所以如果 SVG 編輯應用程式是共用目標,可以直接接收檔案,不會進行偏差。

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 圖片分享到 Gmail。

網路共用目標 (檔案)

另一方面,SVG 程式碼也能做為共用目標,接收來自其他應用程式的檔案。目的地: 功能正常運作,應用程式必須透過 Web Share Target API 可接受哪些類型的資料。這項作業是透過 專屬欄位

{
  "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 路徑實際上不存在,但只會在 Service Worker 的 fetch 中處理 處理常式接著會傳遞接收的檔案,以便在應用程式中實際處理。

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。

結論

接下來是快速導覽,介紹一些 SVGcode 中的進階應用程式功能。希望這個應用程式 也成為處理圖片的必備工具,以及其他出色的應用程式,例如 SquooshSVGOMG

您可以從 svgco.de 取得 SVGcode。查看我在那裡做什麼?你可以 前往 GitHub 查看原始碼。請注意,由於 Potrace 是 經 GPL 授權,例如 SVGcode。完成這項任務後,祝您向量地圖一切順利!希望 SVG 程式碼能派上用場 其中部分功能可激發您下一個應用程式的靈感。

特別銘謝

本文經過 Joe Medley