SVGcode: PWA להמרת תמונות רשת לגרפיקה וקטורית מסוג SVG

SVGcode הוא אפליקציה מסוג Progressive Web App שמאפשרת להמיר תמונות רשת כמו JPG , PNG , GIF , WebP , AVIF וכו' לגרפיקה וקטורית בפורמט SVG. הוא משתמש ב-File System Access API, ב-API של הלוח האסינכרוני, ב-File Treatment API ובהתאמה אישית של window Controls Overlay.

(אם אתם מעדיפים לצפות במקום לקרוא אותם, המאמר הזה זמין גם כסרטון).

מ-Raster לווקטור

האם אי פעם שיניתם גודל של תמונה והתוצאה הייתה מפוקסלת ולא איכותית? אם המיקום לכן סביר להניח שנתקלתם בפורמט תמונה מסוג רשת נקודות כמו WebP, PNG או JPG.

הגדלת התמונה מסוג רשת נקודות גורמת לה להיראות מפוקסלת.

לעומת זאת, גרפיקה וקטורית היא תמונות שמוגדרות באמצעות נקודות במערכת קואורדינטות. האלה נקודות מחוברות באמצעות קווים ועקומות כדי ליצור מצולעים וצורות אחרות. לגרפיקה וקטורית יש יתרון על פני גרפיקה מסוג רסטר בכך שניתן להגדיל או להקטין אותה לכל רזולוציה ללא תצוגת פיקסלים.

הגדלת תמונה וקטורית מבלי לפגוע באיכות.

היכרות עם קוד SVG

פיתחתי PWA בשם SVGcode שיכולה לעזור לכם להמיר תמונות רסטר של שאילתות. קרדיט שצריך לתת לו קרדיט: לא המצאתי את זה. עם SVGcode, אני פשוט עומד של כלי שורת הפקודה Potrace Peter Selinger שיש לי הומר ל-Web Assembly, כך שניתן להשתמש בו אפליקציית אינטרנט.

צילום מסך של אפליקציית SVGcode.
אפליקציית SVGcode.

שימוש ב-SVGcode

קודם כל אני רוצה להראות לך איך להשתמש באפליקציה. אני מתחיל עם תמונת הטיזר של מפגש הפסגה של מפתחי Chrome שהורדתי מערוץ ChromiumDev Twitter. זוהי תמונת רשת נקודות של PNG גוררים אל אפליקציית SVGcode. כשמשחררים את הקובץ, האפליקציה עוקבת אחר צבע התמונה לפי צבע, עד שתופיע גרסה וקטורית של הקלט. עכשיו אני יכול להתקרב לתמונה, וכמו שאתם יכולים לראות הקצוות נשארים חדים. אבל אם תתקרבו ללוגו של Chrome, אפשר לראות שסרטון המעקב לא מושלמת, ובמיוחד קווי המתאר של הלוגו נראים קצת מנופפים. אוכל לשפר את התוצאה על ידי להסיר את נקודות המעקב על ידי ביטול החלקיקים בעד חמישה פיקסלים, למשל.

המרת תמונה שמוטמעת ל-SVG.

Posterization ב-SVGcode

שלב חשוב בווקטורים, במיוחד עבור תמונות מצולמות, הוא הפצת הקלט לאחר מכן כדי לצמצם את מספר הצבעים. ו-SVGcode מאפשר לי לעשות זאת לכל ערוץ צבעים, ולראות את של קובץ ה-SVG שנוצר במהלך ביצוע השינויים. אני מרוצה מהתוצאה, אוכל לשמור את קובץ ה-SVG בדיסק הקשיח ולהשתמש בה בכל מקום שבא לי.

יצירת פוסטר של תמונה כדי לצמצם את מספר הצבעים.

ממשקי API המשמשים בקוד SVG

עכשיו, אחרי שהבנתם מה אפשר לעשות באמצעות האפליקציה, אני רוצה להראות לכם כמה מממשקי ה-API שעוזרים ליצור הקסם קורה.

Progressive Web App

SVGcode הוא Progressive Web App שאפשר להתקין, ולכן היא מופעלת באופן מלא במצב אופליין. האפליקציה מבוססת ב תבנית Vanilla JS עבור Vite.js ומשתמשת פלאגין של Vite PWA, שיוצר קובץ שירות (service worker) משתמש במנגנון Workbox.js. תיבת העבודה היא קבוצה של ספריות שיכולות להפעיל קובץ שירות (service worker) מוכן לייצור עבור Progressive Web Apps, הדפוס הזה לא בהכרח יעבוד בכל האפליקציות, אבל בתרחיש לדוגמה של 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. אם רוצים, אפשר ללמוד על קוד המקור של SVG src/js/filesystem.js.

Async Clipboard API

גם SVGcode משתלב באופן מלא עם הלוח של מערכת ההפעלה באמצעות ה-Async Clipboard API. אפשר להדביק תמונות מסייר הקבצים של מערכת ההפעלה באפליקציה על ידי לחיצה על מדביקים את לחצן התמונה או על ידי לחיצה על Command או על Control ואז על v במקלדת.

הדבקת תמונה מסייר הקבצים ל-SVGcode.

לאחרונה, ל-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 היא עד כמה הוא משתלב היטב עם מערכת ההפעלה. בתור PWA שמותקנת במכשיר, היא יכולה להפוך ל-handler של קבצים או אפילו ל-handler של הקבצים שמוגדר כברירת מחדל עבור קובצי תמונה. הזה כלומר, כשאני ב-Finder במחשב macOS, אפשר ללחוץ לחיצה ימנית על תמונה ולפתוח אותה באמצעות בפורמט SVG. התכונה הזו נקראת 'טיפול בקבצים' ופועלת על סמך המאפיין file_handlers במאפיין מניפסט של אפליקציית אינטרנט ותור ההפעלה, שמאפשרים לאפליקציה לצרוך את הקובץ שהועבר.

פתיחת קובץ משולחן העבודה שמותקנת בו אפליקציית 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;
    }
  }
});

מידע נוסף זמין במאמר מתן הרשאה לאפליקציות אינטרנט מותקנות להיות רכיבי handler של קבצים, ולעיין בקוד המקור src/js/filehandling.js.

שיתוף באינטרנט (קבצים)

דוגמה נוספת לשילוב עם מערכת ההפעלה היא תכונת השיתוף של אפליקציה. בהנחה שאני רוצה לערוך קובץ SVG שנוצר באמצעות SVGcode. דרך אחת להתמודד עם זה היא לשמור את הקובץ, מפעילים את אפליקציית העריכה בפורמט 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 לא קיים בפועל, אבל מטופל רק ב-fetch של ה-Service Worker. handler, שמעביר את הקבצים שהתקבלו לעיבוד בפועל באפליקציה.

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. אני מקווה שהאפליקציה הזו יכול להפוך לכלי חיוני לעיבוד תמונות, לצד אפליקציות מדהימות אחרות כמו Squoosh או SVGOMG.

SVGcode זמין בכתובת svgco.de. רוצה לראות מה עשיתי שם? אפשר לבדוק את קוד המקור שלו ב-GitHub. שימו לב שמכיוון ש-Potrace היא עם רישיון GPL, כך גם SVGcode. ועם זאת, יצירת וקטורים שמחה! אני מקווה ש-SVGcode יהיה שימושי, חלק מהתכונות שלו יכולות לתת השראה לאפליקציה הבאה שלכם.

אישורים

המאמר הזה נבדק על ידי ג'ו מדלי.