วิธีที่แอปแก้ไขรูปภาพเวกเตอร์ Boxy SVG ใช้ Local Font Access API เพื่อให้ผู้ใช้เลือกแบบอักษรโปรดในพื้นที่

Local Font Access API มีกลไกในการเข้าถึงข้อมูลแบบอักษรที่ผู้ใช้ติดตั้งไว้ในเครื่อง ซึ่งรวมถึงรายละเอียดระดับสูงขึ้น เช่น ชื่อ สไตล์ และตระกูล รวมถึงไบต์ดิบของไฟล์แบบอักษรที่เกี่ยวข้อง ดูวิธีที่แอปแก้ไข SVG อย่าง Boxy SVG ใช้ API นี้

บทนำ

(บทความนี้มีให้บริการในรูปแบบวิดีโอด้วย)

Boxy SVG เป็นโปรแกรมแก้ไขกราฟิกเวกเตอร์ Use Case หลักคือการแก้ไขภาพวาดในรูปแบบไฟล์ SVG สำหรับการสร้างภาพ โลโก้ ไอคอน และองค์ประกอบอื่นๆ ของการออกแบบกราฟิก เครื่องมือนี้พัฒนาขึ้นโดย Jarosław Foksa ซึ่งเป็นนักพัฒนาเกมชาวโปแลนด์ และเปิดตัวครั้งแรกเมื่อวันที่ 15 มีนาคม 2013 Jarosław ทำบล็อก Boxy SVG ซึ่งเขาได้เปิดตัวฟีเจอร์ใหม่ที่เขาเพิ่มลงในแอป นักพัฒนาซอฟต์แวร์เป็นผู้สนับสนุนที่แข็งแกร่งสำหรับโปรเจ็กต์ Fugu ของ Chromium และยังมีแท็ก Fugu บนเครื่องมือติดตามแนวคิดของแอปอีกด้วย

แอป Boxy SVG ที่แก้ไข SVG ไอคอน Project Fugu

Local Font Access API ใน Boxy SVG

ฟีเจอร์หนึ่งที่ Jarosław เขียนบล็อกถึงคือ Local Font Access API Local Font Access API ช่วยให้ผู้ใช้เข้าถึงแบบอักษรที่ติดตั้งในเครื่อง รวมถึงรายละเอียดระดับสูงขึ้น เช่น ชื่อ สไตล์ และชุดแบบอักษร ตลอดจนไบต์ดิบของไฟล์แบบอักษรพื้นฐาน ในภาพหน้าจอต่อไปนี้ คุณจะเห็นวิธีที่ฉันให้สิทธิ์เข้าถึงแบบอักษรที่ติดตั้งในเครื่องบน MacBook แก่แอปและเลือกแบบอักษร Marker Felt สำหรับข้อความ

แอป Boxy SVG ที่แก้ไข SVG ไอคอน Project Fugu โดยเพิ่มข้อความ "Project Fugu rocks" ที่ตั้งค่าในแบบอักษร Marker Felt ซึ่งแสดงเป็นแบบเลือกในเครื่องมือเลือกแบบอักษร

โค้ดพื้นฐานค่อนข้างตรงไปตรงมา เมื่อผู้ใช้เปิดเครื่องมือเลือกแบบอักษรเป็นครั้งแรก แอปพลิเคชันจะตรวจสอบก่อนว่าเว็บเบราว์เซอร์รองรับ Local Font Access API หรือไม่

นอกจากนี้ ยังตรวจสอบ API เวอร์ชันเก่าเวอร์ชันทดลองและนำไปใช้ด้วยหากมี ตั้งแต่ปี 2023 เป็นต้นไป คุณสามารถละเว้น API เก่าได้อย่างปลอดภัย เนื่องจาก API ดังกล่าวใช้งานได้เพียงระยะเวลาสั้นๆ ผ่าน Flag ทดลองของ Chrome แต่ผลิตภัณฑ์ที่มาจาก Chromium บางรายการอาจยังคงใช้ API ดังกล่าว

let isLocalFontsApiEnabled = (
  // Local Font Access API, Chrome >= 102
  window.queryLocalFonts !== undefined ||
  // Experimental Local Font Access API, Chrome < 102
  navigator.fonts?.query !== undefined
);

หาก Local Font Access API ไม่พร้อมใช้งาน เครื่องมือเลือกแบบอักษรจะเปลี่ยนเป็นสีเทา ข้อความตัวยึดตําแหน่งจะแสดงต่อผู้ใช้แทนรายการแบบอักษร

if (isLocalFontsApiEnabled === false) {
  showPlaceholder("no-local-fonts-api");
  return;
}

เครื่องมือเลือกแบบอักษรที่แสดงข้อความ &quot;เบราว์เซอร์ของคุณไม่รองรับ Local Font Access API&quot;

ไม่เช่นนั้น ระบบจะใช้ Local Font Access API เพื่อดึงข้อมูลรายการแบบอักษรทั้งหมดจากระบบปฏิบัติการ สังเกตการบล็อก try…catch ซึ่งจำเป็นเพื่อจัดการกับข้อผิดพลาดเกี่ยวกับสิทธิ์อย่างถูกต้อง

let localFonts;

if (isLocalFontsApiEnabled === true) {
  try {
    // Local Font Access API, Chrome >= 102
    if (window.queryLocalFonts) {
      localFonts = await window.queryLocalFonts();
    }
    // Experimental Local Font Access API, Chrome < 102
    else if (navigator.fonts?.query) {
      localFonts = await navigator.fonts.query({
        persistentAccess: true,
      });
    }
  } catch (error) {
    showError(error.message, error.name);
  }
}

เมื่อเรียกข้อมูลรายการแบบอักษรในเครื่องแล้ว ระบบจะสร้าง fontsIndex แบบง่ายและมาตรฐานจากรายการดังกล่าว

let fontsIndex = [];

for (let localFont of localFonts) {
  let face = "400";

  // Determine the face name
  {
    let subfamily = localFont.style.toLowerCase();
    subfamily = subfamily.replaceAll(" ", "");
    subfamily = subfamily.replaceAll("-", "");
    subfamily = subfamily.replaceAll("_", "");

    if (subfamily.includes("thin")) {
      face = "100";
    } else if (subfamily.includes("extralight")) {
      face = "200";
    } else if (subfamily.includes("light")) {
      face = "300";
    } else if (subfamily.includes("medium")) {
      face = "500";
    } else if (subfamily.includes("semibold")) {
      face = "600";
    } else if (subfamily.includes("extrabold")) {
      face = "800";
    } else if (subfamily.includes("ultrabold")) {
      face = "900";
    } else if (subfamily.includes("bold")) {
      face = "700";
    }

    if (subfamily.includes("italic")) {
      face += "i";
    }
  }

  let descriptor = fontsIndex.find((descriptor) => {
    return descriptor.family === localFont.family);
  });

  if (descriptor) {
    if (descriptor.faces.includes(face) === false) {
      descriptor.faces.push(face);
    }
  } else {
    let descriptor = {
      family: localFont.family,
      faces: [face],
    };

    fontsIndex.push(descriptor);
  }
}

for (let descriptor of fontsIndex) {
  descriptor.faces.sort();
}

จากนั้นระบบจะจัดเก็บดัชนีแบบอักขระมาตรฐานไว้ในฐานข้อมูล IndexedDB เพื่อให้สามารถค้นหา แชร์ระหว่างอินสแตนซ์แอป และเก็บรักษาระหว่างเซสชันได้อย่างง่ายดาย Boxy SVG ใช้ Dexie.js เพื่อจัดการฐานข้อมูล

let database = new Dexie("LocalFontsManager");
database.version(1).stores({cache: "family"}).
await database.cache.clear();
await database.cache.bulkPut(fontsIndex);

ส่วนพื้นที่เก็บข้อมูลของเครื่องมือสําหรับนักพัฒนาเว็บใน Chrome ที่แสดงตาราง IndexedDB ที่มีแคชแบบอักษร

เมื่อป้อนข้อมูลฐานข้อมูลแล้ว วิดเจ็ตตัวเลือกแบบอักษรจะสามารถค้นหาและแสดงผลลัพธ์บนหน้าจอได้ โดยทำดังนี้

เครื่องมือเลือกแบบอักษรที่มีแบบอักษร

โปรดทราบว่า Boxy SVG จะแสดงผลรายการในองค์ประกอบที่กำหนดเองชื่อ <bx-fontfamilypicker> และจัดสไตล์รายการในรายการแบบอักษรแต่ละรายการเพื่อให้แสดงในแบบอักษรตระกูลหนึ่งๆ เพื่อแยกจากส่วนที่เหลือของหน้า Boxy SVG จะใช้ Shadow DOM ในองค์ประกอบนี้และองค์ประกอบที่กำหนดเองอื่นๆ

แผงองค์ประกอบเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome ที่แสดงเครื่องมือเลือกแบบอักษรที่กำลังตรวจสอบ ซึ่งเป็นองค์ประกอบที่กำหนดเองชื่อ &quot;bx-fontfamiliypicker&quot;

สรุป

ฟีเจอร์แบบอักษรในเครื่องได้รับความนิยมอย่างมากเนื่องจากผู้ใช้สามารถเข้าถึงแบบอักษรในเครื่องเพื่อใช้ออกแบบและสร้างสรรค์ผลงานได้ เมื่อรูปแบบ API เปลี่ยนแปลงและฟีเจอร์ใช้งานไม่ได้ชั่วคราว ผู้ใช้จะสังเกตเห็นทันที Jarosław รีบเปลี่ยนโค้ดเป็นรูปแบบการป้องกันที่คุณเห็นในสนิปเพลตด้านบน ซึ่งใช้ได้กับ Chrome เวอร์ชันล่าสุดและผลิตภัณฑ์อื่นๆ ของ Chromium ที่อาจยังไม่ได้เปลี่ยนไปใช้เวอร์ชันล่าสุด ลองใช้ Boxy SVG และอย่าลืมตรวจสอบแบบอักษรที่ติดตั้งในเครื่อง คุณอาจค้นพบแบบอักษรคลาสสิกที่ลืมไปนานแล้ว เช่น Zapf Dingbats หรือ Webdings