PerfectVector
โดย Irene Kimอ่าน 3 นาที

SVG feMorphology: เพิ่มขอบโดยไม่สร้างพาธใหม่

สร้างขอบ SVG จาก SourceAlpha ด้วย feMorphology เปรียบเทียบการขยาย การหด ช่องว่าง และรัศมีที่ไม่เท่ากัน โดยคงเรขาคณิตของพาธต้นฉบับไว้

ในหน้านี้

หากต้องการเพิ่มขอบรอบรูปเงาของ SVG หลายสีทั้งภาพ ให้ขยาย SourceAlpha ลบอัลฟาต้นฉบับออกจากผลลัพธ์ที่ใหญ่ขึ้น เติมสีให้วงขอบที่เหลือ แล้วซ้อนภาพต้นฉบับไว้ด้านบน ฟิลเตอร์จะเปลี่ยนรูปลักษณ์ที่เรนเดอร์ โดยข้อมูลพาธต้นฉบับยังคงเดิม

ใช้ operator="erode" หากต้องการรูปเงาจากอัลฟาที่เล็กลงแทน ทั้งสองวิธีไม่ได้สร้างพาธออฟเซ็ตที่แก้ไขได้ ต้องตรวจช่องว่าง ช่องแคบ และมุมคมด้วยตา เพราะการดำเนินการทางสัณฐานวิทยาใช้บริเวณใกล้เคียงรูปสี่เหลี่ยมผืนผ้า ไม่ใช่การออฟเซ็ตเส้นขอบแบบวงกลม

เริ่มจากรูปเงา ไม่ใช่ช่องสี

ข้อกำหนด Filter Effects ของ W3C นิยามการขยายว่าเป็นการหาค่าสูงสุดของแต่ละองค์ประกอบภายในบริเวณใกล้เคียงรูปสี่เหลี่ยมผืนผ้า และการหดว่าเป็นการหาค่าต่ำสุด เมื่อใช้ SourceAlpha ข้อมูลขาเข้าคือช่องอัลฟาของภาพ จึงสร้างรูปเงาได้โดยไม่ต้องขยายช่องสีเขียวอมฟ้าและสีคอรัลแยกกัน

ตัวอย่างนี้ใช้ฟิลเตอร์กับภาพทั้งสองพาธ ช่องสี่เหลี่ยมจัตุรัสโปร่งใสเป็นส่วนหนึ่งของรูปเงาจากอัลฟา ส่วนสีคอรัลอยู่ภายในบริเวณสีเขียวอมฟ้าที่ทึบอยู่แล้ว จึงไม่ได้สร้างขอบด้านนอกแยกต่างหาก

เราสร้าง SVG ด้วยมือและเปิดไฟล์อิสระห้ารูปแบบในเบราว์เซอร์ ทุกไฟล์คงนิยามพาธต้นฉบับสองพาธไว้เหมือนกัน ภาพเปรียบเทียบด้านล่างเป็นการเรนเดอร์ไฟล์เหล่านั้นจริง ไม่ได้ใช้ภาพที่ไล่เส้นหรือภาพตัวอย่างเอฟเฟกต์ที่สร้างขึ้น

ภาพเรนเดอร์ SVG จริงห้าแบบของตราสัญลักษณ์สองสีเดียวกัน: ไม่มีฟิลเตอร์ ขอบสีทองจากอัลฟาที่รัศมี 10 รูปเงาที่หดลง รัศมี 22 ที่เติมช่องสี่เหลี่ยม และขอบที่รัศมีแต่ละแกนไม่เท่ากัน 18 4
สีทองมาจากวงขอบอัลฟาที่ขยาย โดยซ้อนสีต้นฉบับไว้ด้านบน ส่วนการหดจะตัดสีเหล่านั้นให้เหลือรูปเงาที่เล็กลง ทั้งห้าไฟล์คงพาธต้นทางสองพาธเดิมไว้

ที่รัศมี 10 ขอบจะขยายออกนอกขอบรูปที่มองเห็นและเข้าไปในช่องว่าง ที่ 22 สีทองจะเติมช่องสี่เหลี่ยมของตัวอย่างนี้เต็ม รูปแบบ 18 4 ขยายตามแนวนอนมากกว่าแนวตั้ง การหดจะลดพื้นที่ทึบด้านนอกและขยายช่องโปร่งใส จุดแหลมด้านล่างก็เปลี่ยนไปด้วย

สิ่งที่สังเกตได้เหล่านี้ใช้กับภาพนี้และการตั้งค่าเหล่านี้เท่านั้น ไม่ใช่กฎเลือกรัศมีที่ปลอดภัยสำหรับโลโก้หรือไอคอนอื่นโดยทั่วไป

สร้างวงขอบอัลฟาด้านนอก

บันทึกตัวอย่างฉบับสมบูรณ์นี้เป็น outline.svg แล้วเปิดในเบราว์เซอร์ นี่คือ SVG รัศมี 10 ที่ใช้ในการจับภาพจริง:

<svg xmlns="http://www.w3.org/2000/svg" width="300" height="220" viewBox="0 0 300 220">
<defs>
<g id="artwork">
  <path fill="#173b40" fill-rule="evenodd"
    d="M50 60H250V170H170L150 195L130 170H50Z M105 90H145V130H105Z"/>
  <path fill="#f28567" d="M175 90H220V140H175Z"/>
</g>
<filter id="outline" filterUnits="userSpaceOnUse"
  primitiveUnits="userSpaceOnUse" x="0" y="0" width="300" height="220">
  <feMorphology in="SourceAlpha" operator="dilate" radius="10" result="grown"/>
  <feComposite in="grown" in2="SourceAlpha" operator="out" result="ring"/>
  <feFlood flood-color="#e4b84c" result="paint"/>
  <feComposite in="paint" in2="ring" operator="in" result="coloredRing"/>
  <feMerge>
    <feMergeNode in="coloredRing"/>
    <feMergeNode in="SourceGraphic"/>
  </feMerge>
</filter>
</defs>
<use href="#artwork" filter="url(#outline)"/>
</svg>

ฟิลเตอร์ทำงานสี่ขั้นตอน:

  1. feMorphology ขยาย SourceAlpha เป็น grown
  2. feComposite เก็บส่วนของ grown ที่อยู่นอกอัลฟาต้นฉบับ ได้ผลเป็น ring
  3. feFlood ให้สีทอง และการคอมโพสิตอีกครั้งจำกัดสีนี้ให้อยู่เฉพาะวงขอบ
  4. feMerge วาง SourceGraphic ต้นฉบับเหนือวงขอบที่เติมสีแล้ว

ลำดับข้อมูลขาเข้าสำคัญต่อการลบ ส่วนการคอมโพสิตของข้อกำหนด กำหนด in เป็นต้นทางและ in2 เป็นปลายทาง ในตัวอย่างนี้ in="grown", in2="SourceAlpha" และ operator="out" ลบพื้นที่ทึบเดิมออกจากอัลฟาที่ขยาย การสลับข้อมูลขาเข้าทั้งสองจะไม่ได้วงขอบด้านนอกแบบนี้

คำว่า ด้านนอก หมายถึงนอกบริเวณอัลฟาที่ทึบ รวมถึงพื้นที่ภายในช่องโปร่งใส หากขอบต้องหลีกเลี่ยงช่องเปิดด้านใน ฟิลเตอร์นี้ไม่ได้แยกสองกรณีนี้ให้โดยอัตโนมัติ ต้องมีรูปเงาแยกต่างหากหรือวิธีสร้างอื่นที่นิยามขอบด้านนอกตามที่ต้องการ

สีต้นทางยังมองเห็นได้เพราะเราผสาน SourceGraphic ที่ไม่แก้ไขเป็นขั้นสุดท้าย วิธีนี้แยกจากเส้นขอบพาธทั่วไป สำหรับเส้นขอบกึ่งกลาง เส้นขอบด้านในที่ใช้การตัด หรือเส้นขอบด้านนอกที่ใช้มาสก์ ดูการจัดแนวเส้นขอบ SVG ส่วนลำดับการระบายสี อธิบายกรณีซ้อนเส้นขอบกับสีเติมที่ง่ายกว่า

หดอัลฟาและเก็บสีในบริเวณที่เหลือ

แทนฟิลเตอร์ขอบด้วยนิยามต่อไปนี้ แล้วเปลี่ยน use สุดท้ายเป็น filter="url(#erode)":

<filter id="erode" filterUnits="userSpaceOnUse"
  primitiveUnits="userSpaceOnUse" x="0" y="0" width="300" height="220">
  <feMorphology in="SourceAlpha" operator="erode" radius="10" result="shrunken"/>
  <feComposite in="SourceGraphic" in2="shrunken" operator="in"/>
</filter>

การคอมโพสิตนี้เก็บภาพต้นฉบับเฉพาะบริเวณที่ยังมีอัลฟาหลังหด ไม่ได้ซ้อนต้นฉบับทั้งหมดกลับด้านบน เพราะจะบดบังผลการทำให้บางลงที่ต้องการ ในตัวอย่างนี้พื้นที่เขียวอมฟ้าด้านนอกเล็กลง ขณะที่บริเวณคอรัลภายในยังคงอยู่

ระบุ operator ให้ชัดเจนในตัวอย่างที่ใช้งาน เอกสารอ้างอิง operator แยก erode และ dilate บน feMorphology ออกจาก in และ out บน feComposite แอตทริบิวต์ชื่อเดียวกันมีหน้าที่ต่างกันในสององค์ประกอบนี้ ค่าเริ่มต้นของ operator สำหรับสัณฐานวิทยาคือ erode การละไว้จึงทำให้ได้ผลตรงข้ามกับการขยายที่ตั้งใจได้ง่าย

แยกหน่วยรัศมีออกจากบริเวณฟิลเตอร์

เอกสารอ้างอิง radius รองรับตัวเลขหนึ่งหรือสองค่า ค่าเดียวใช้กับทั้งสองแกน หากมีสองค่า ค่าแรกเป็นรัศมี x และค่าที่สองเป็นรัศมี y สำหรับรูปแบบขอบเพิ่มเติมสองแบบ ให้เปลี่ยนเฉพาะ radius="10" เป็น radius="22" หรือ radius="18 4" ในตัวอย่างฉบับสมบูรณ์

รัศมีเหล่านี้อยู่ในระบบพิกัดที่เลือกด้วย primitiveUnits ไม่ได้รับประกันว่าขอบจะหนาเท่าเดิมในหน่วยพิกเซล CSS ทุกขนาดแสดงผล เราใช้ primitiveUnits="userSpaceOnUse" อย่างชัดเจนกับ viewBox 0 0 300 220 การเปลี่ยนขนาด SVG ที่แสดงจะปรับสเกลเอฟเฟกต์ไปพร้อมภาพ

แอตทริบิวต์สองตัวที่ชื่อคล้ายกันควบคุมคนละเรื่อง:

แอตทริบิวต์สิ่งที่ควบคุมค่าในตัวอย่าง
primitiveUnitsค่าความยาวภายในคำสั่งฟิลเตอร์พื้นฐาน รวมถึงรัศมีสัณฐานวิทยาuserSpaceOnUse
filterUnitsx, y, width และ height ของบริเวณฟิลเตอร์userSpaceOnUse
viewBox ที่รากกรอบสี่เหลี่ยมในพิกัดผู้ใช้ที่แมปไปยังวิวพอร์ต SVG0 0 300 220

เอกสารอ้างอิง primitiveUnits ของ MDN อธิบายระบบพิกัดของคำสั่งฟิลเตอร์พื้นฐาน ส่วนเอกสารอ้างอิง filterUnits อธิบายบริเวณด้านนอกแยกต่างหาก filterUnits มีค่าเริ่มต้นเป็น objectBoundingBox และ primitiveUnits เป็น userSpaceOnUse การตั้งทั้งคู่ชัดเจนทำให้ตรวจตัวอย่างได้ง่ายขึ้น

ภาพต้นทางครอบคลุม x=50 ถึง 250 และ y=60 ถึง 195 รัศมีเท่ากันทั้งสองแกนที่ใหญ่ที่สุดในการทดสอบคือ 22 และบริเวณฟิลเตอร์กับวิวพอร์ตขนาด 300 คูณ 220 ยังมีพื้นที่รองรับผลลัพธ์นั้น ตรวจขอบเขตทั้งสองอีกครั้งเมื่อเปลี่ยนภาพหรือรัศมี ข้อกำหนดอธิบายบริเวณฟิลเตอร์ว่าเป็นขอบตัดแบบเด็ดขาด รัศมีที่ใหญ่ขึ้นไม่สามารถระบายเลยบริเวณนี้ได้ คู่มือการตัดด้วยฟิลเตอร์และวิวพอร์ต SVG สาธิตข้อจำกัดสองอย่างนี้แยกกัน

หากฟิลเตอร์ดูเหมือนไม่ทำงาน ให้ตรวจ radius ด้วย ค่าเริ่มต้นคือ 0 และเอกสารอ้างอิงระบุว่าค่าติดลบหรือศูนย์จะปิดผลของคำสั่งฟิลเตอร์พื้นฐาน ตัวอย่างข้างต้นใช้ค่าบวกอย่างชัดเจนทั้งสองแกน

ตรวจช่องว่างและมุมก่อนส่งมอบ

บริเวณใกล้เคียงรูปสี่เหลี่ยมผืนผ้าของสัณฐานวิทยาทำให้รูปลักษณ์ต่างจากขอบมนทั่วไป รัศมี x และ y ที่เท่ากันไม่ได้ทำให้บริเวณนั้นเป็นวงกลม จุดแหลมด้านล่างที่กลายเป็นขั้นในภาพเปรียบเทียบเป็นตำแหน่งที่เหมาะสำหรับตรวจความแตกต่างนี้

ผลลัพธ์สิ่งที่ควรตรวจก่อนใช้
ขอบด้านนอกใหญ่ขึ้นช่องเปิดและรูปทรงใกล้กันอาจดูเชื่อมติดกัน
รูปเงาที่หดลงรายละเอียดบางอาจหายไปและช่องว่างอาจใหญ่ขึ้น
รัศมีแต่ละแกนไม่เท่ากันการขยายแนวนอนและแนวตั้งต่างกันโดยตั้งใจ
ภาพตัวอย่างในเบราว์เซอร์ถูกต้องยังต้องทดสอบในโปรแกรมแก้ไขหรือตัวส่งออกปลายทาง
ต้องการขอบเป็นเรขาคณิตที่แก้ไขได้ผลของฟิลเตอร์ขณะเรนเดอร์ไม่ใช่เส้นรอบรูปใหม่ในต้นทาง

เราตรวจว่าทั้งห้าไฟล์ยังมีพาธต้นทางสองพาธที่แอตทริบิวต์ d เหมือนกัน นิยามฟิลเตอร์ต่างกัน แต่เรขาคณิตต้นทางไม่ต่าง ตรวจวัตถุ SVG จริงเมื่อปลายทางต้องการพาธที่แก้ไข ออฟเซ็ต หรือส่งไปผลิตได้ ใช้คำสั่งจัดการเรขาคณิตของโปรแกรมแก้ไขสำหรับความต้องการนั้น แล้วตรวจเส้นรอบรูปที่ได้ การเปลี่ยนหรือลบฟิลเตอร์นี้เพียงอย่างเดียวไม่ได้สร้างเส้นเหล่านั้น

เก็บไฟล์ต้นฉบับที่ไม่มีฟิลเตอร์และสำเนาสำหรับส่งมอบแยกกัน เปิดไฟล์ที่ส่งมอบในปลายทางจริง แล้วเปรียบเทียบมุม ช่องเปิดภายใน สี และขอบเขต ตัวอย่างในเบราว์เซอร์นี้ไม่ได้ยืนยันการรองรับในแอปออกแบบ ตัวส่งออก หรือเครื่องตัดใดโดยเฉพาะ

เตรียมต้นทางก่อนเพิ่มเอฟเฟกต์

PerfectVector ช่วยได้เมื่อภาพเริ่มต้นมีเพียง PNG หรือ JPG เตรียม SVG สำหรับประเมิน แล้วตรวจรูปเงาต้นทาง ช่องเล็ก ๆ และขอบเขตสีที่สร้างกลับขึ้นมาก่อนใช้ฟิลเตอร์ ขอบจากสัณฐานวิทยาจะขยายปัญหาในรูปเงานั้น ไม่ได้ซ่อมเรขาคณิตให้ตรงตามที่ตั้งใจแทนคุณ

ใช้ไฟล์เวกเตอร์ต้นฉบับโดยตรงหากมี สำหรับสัญลักษณ์ง่าย ๆ การวาดใหม่ด้วยมืออาจควบคุมได้สะดวกกว่า การไล่เส้นภาพที่รวมเลเยอร์และฝังขอบไว้แล้วไม่สามารถกู้การตั้งค่าฟิลเตอร์ต้นฉบับ หรือบอกได้ว่าส่วนใดคือรูปร่างก่อนใช้ฟิลเตอร์ ภาพรวมการแปลงภาพเป็นเวกเตอร์ อธิบายข้อจำกัดของการสร้างกลับขึ้นมานี้

คำถามที่พบบ่อย

feMorphology สร้างพาธขอบที่แก้ไขได้หรือไม่? ไม่ ฟิลเตอร์นี้เปลี่ยนผลลัพธ์ที่เรนเดอร์ ตัวอย่างคงพาธต้นทางสองพาธเดิมไว้ ดังนั้นปลายทางที่ต้องการเส้นรอบรูปแยกต้องใช้คำสั่งจัดการเรขาคณิตและตรวจการนำเข้า

ทำไมขอบสีทองจึงเติมช่องว่างใน SVG ของฉัน? วงขอบขยายออกนอกอัลฟาที่ทึบ รวมถึงเข้าไปในช่องโปร่งใส ในตัวอย่างนี้ รัศมี 22 เติมช่องสี่เหลี่ยมเต็ม ภาพอื่นต้องตรวจระยะช่องว่างและรัศมีของตนเอง

ทำไมใช้ SourceAlpha แทน SourceGraphic? SourceAlpha ทำให้ฟิลเตอร์ทำงานกับรูปเงาโดยไม่ขยายแต่ละช่องสีต้นฉบับ ตัวอย่างเติมสีให้วงขอบอัลฟาแยกต่างหาก แล้วผสาน SourceGraphic เป็นขั้นสุดท้ายเพื่อแสดงสีเดิม

แหล่งอ้างอิง

  1. W3C — Filter Effects ระดับ 1 — นิยามบริเวณใกล้เคียงรูปสี่เหลี่ยมผืนผ้าของสัณฐานวิทยา ข้อมูลขาเข้าการคอมโพสิต และการตัดที่บริเวณฟิลเตอร์
  2. MDN — radius — นิยามไวยากรณ์รัศมีค่าเดียวและสองค่า หน่วย และค่าที่ปิดเอฟเฟกต์
  3. MDN — operator — แยกการดำเนินการสัณฐานวิทยาออกจากการคอมโพสิต
  4. MDN — primitiveUnits — กำหนดระบบพิกัดสำหรับรัศมีสัณฐานวิทยา
  5. MDN — filterUnits — กำหนดระบบพิกัดสำหรับบริเวณฟิลเตอร์ด้านนอก

หากต้นทางมีเพียงราสเตอร์ เตรียมภาพเวกเตอร์ด้วย PerfectVector ตรวจรูปเงาและช่องเปิดก่อนใช้ฟิลเตอร์ จากนั้นเพิ่มขอบและเปรียบเทียบไฟล์สุดท้ายในโปรแกรมดูปลายทาง

เพิ่มเติมจากบล็อก

เริ่มต้นด้วย SVG ที่เรียบร้อยขึ้น
และแก้ไขได้ง่ายกว่า