วิธีที่แอปแก้ไขรูปภาพเวกเตอร์ 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