💡 ตัวอย่างทำงานเต็มที่พร้อมใช้งานบน GitHub:
extract-annotations-from-pdf-using-groupdocs-parser-dotnet
Introduction
PDF ที่ผ่านการตรวจสอบมักจะมีข้อมูลมากกว่าข้อความที่มองเห็นได้ – โน้ตสติ๊กกี้, ข้อความที่ไฮไลท์, และคอมเมนต์แบบอินไลน์ที่ผู้ตรวจสอบทิ้งไว้ การเลื่อนดูทุกหน้าเพื่อค้นหาเหล่านี้ไม่สามารถทำได้อย่างมีประสิทธิภาพเมื่อเอกสารผ่านหลายรอบของข้อเสนอแนะ GroupDocs.Parser เป็นไลบรารี .NET ที่อ่าน annotation ที่ฝังอยู่ในเอกสารโดยอัตโนมัติ ทำให้คอมเมนต์ที่กระจัดกระจายของผู้ตรวจสอบกลายเป็นข้อมูลโครงสร้างที่โค้ดของคุณสามารถประมวลผลได้ บทแนะนำนี้จะแสดงวิธีดึง annotation จาก PDF ทั้งไฟล์, แยกตามหน้า, ดึงพร้อมกับข้อความของเอกสาร, และส่งออกผลลัพธ์เป็น CSV หรือ JSON
ฉันเจอปัญหานี้ขณะสร้างระบบติดตามการตรวจสอบสำหรับทีมเอกสาร: โน้ตปล่อยเวอร์ชัน 40 หน้าได้ผ่านผู้ตรวจสอบสามคน และการเปิดไฟล์เพื่อค้นหาคอมเมนต์ทุกอันใช้เวลานานกว่าการแก้ไขปัญหาที่พวกเขาแจ้งไว้ การดึง annotation ด้วยไม่กี่บรรทัดของโค้ดทำให้งานเสร็จในสองนาที
ในส่วนต่อไปนี้คุณจะได้เรียนรู้วิธี:
- ดึง annotation ทั้งหมดจาก PDF ด้วยการเรียกครั้งเดียว
- แท็กแต่ละ annotation ด้วยหน้าที่มันอยู่
- ดึงข้อความของเอกสารและข้อความของ annotation มาร่วมกันในหนึ่งการอ่าน
- แปลงผลลัพธ์เป็น CSV หรือ JSON เพื่อใช้ต่อในเครื่องมืออื่น
Why Extracting PDF Annotations Matters
การอ่าน PDF annotation ด้วยโปรแกรมมีประโยชน์สำหรับ:
- กระบวนการตรวจสอบ: รวบรวมคอมเมนต์ของผู้ตรวจสอบทั้งหมดโดยไม่ต้องเปิดไฟล์ในโปรแกรมดู PDF
- การทำงานร่วมกัน: แสดงส่วนที่ไฮไลท์หรือมีโน้ตโดยตรงในเครื่องมือของคุณ
- การตรวจสอบ: เก็บบันทึกของการทำเครื่องหมายบนเอกสารตามเวลา แม้หลังจากที่เอกสารถูกแบนหรือสรุปแล้ว
GroupDocs.Parser เพิ่มการดึง annotation แบบเนทีฟสำหรับไฟล์ PDF ในเวอร์ชัน 26.7 ผ่านเมธอด GetAnnotations พร้อมตัวเลือกใหม่ IncludeAnnotations บน TextOptions เพื่อดึงข้อความ annotation เข้าไปในผลลัพธ์ข้อความปกติ
Prerequisites
- .NET 6.0 หรือใหม่กว่า
- GroupDocs.Parser for .NET 26.7+ (temporary license)
- ไฟล์ PDF ที่มี annotation อยู่แล้ว (เช่น
document-with-annotations.pdf)
ติดตั้งผ่าน NuGet:
dotnet add package GroupDocs.Parser
How do I extract annotations from a PDF document?
Answer: โหลดไฟล์ด้วย Parser แล้วเรียก GetAnnotations() สำหรับทั้งเอกสารหรือ GetAnnotations(pageIndex) สำหรับหน้าเดียว แต่ละผลลัพธ์เป็นคอลเลกชันของอ็อบเจ็กต์ AnnotationItem ที่มีคุณสมบัติ Value เก็บข้อความคอมเมนต์ หากต้องการเห็นคอมเมนต์รวมกับเนื้อหาเอกสารปกติ ให้ตั้งค่า IncludeAnnotations บน TextOptions แล้วเรียก GetText แทน
Whole‑Document Extraction
โค้ดสแนปต่อไปนี้ดึง annotation ทั้งหมดจากไฟล์ด้วยการเรียกครั้งเดียว ซึ่งเป็นวิธีที่เร็วที่สุดในการตรวจสอบว่าเอกสารมีคอมเมนต์เปิดอยู่หรือไม่
// Extract every annotation from the whole document
var result = new List<string>();
using (var parser = new Parser(path))
{
IEnumerable<AnnotationItem> annotations = parser.GetAnnotations();
if (annotations == null)
{
return result; // format doesn't support annotations
}
foreach (var item in annotations)
{
result.Add(item.Value); // annotation text
}
}
return result;
Key points:
GetAnnotations()จะคืนค่าnullเมื่อฟอร์แมตไม่รองรับการดึง annotation, และคืนคอลเลกชันว่างเมื่อเอกสารไม่มีคอมเมนต์เลย- แต่ละ
AnnotationItemเปิดเผยข้อความผ่านคุณสมบัติValue– นี่คือข้อมูลจุดเดียวที่ SDK รายงานในขณะนี้ - ไม่มีการระบุหน้าที่นี่; ใช้ overload ตามหน้าที่แสดงด้านล่างหากต้องการ
Per‑Page Extraction
เมื่อตำแหน่งของคอมเมนต์สำคัญ ให้วนลูปผ่านหน้าของเอกสารและเรียก GetAnnotations(pageIndex) สำหรับแต่ละหน้า
// Tag each annotation with its zero-based page index
var result = new List<AnnotationRecord>();
using (var parser = new Parser(path))
{
if (!parser.Features.Annotations)
{
return result;
}
var info = parser.GetDocumentInfo();
if (info == null || info.PageCount == 0)
{
return result;
}
for (int pageIndex = 0; pageIndex < info.PageCount; pageIndex++)
{
IEnumerable<AnnotationItem> pageAnnotations = parser.GetAnnotations(pageIndex);
if (pageAnnotations == null)
{
continue;
}
foreach (var item in pageAnnotations)
{
result.Add(new AnnotationRecord { PageIndex = pageIndex, Value = item.Value });
}
}
}
return result;
Key points:
GetDocumentInfo().PageCountเป็นตัวขับลูป; ไม่มี “จำนวนหน้าที่มี annotation” แยกต่างหากGetAnnotations(pageIndex)ใช้ดัชนีเริ่มจากศูนย์ เหมือนเมธอดระดับหน้าทั้งหมดใน API- รายการ
AnnotationRecordที่ได้มีรูปแบบที่เหมาะกับการส่งออกเป็น CSV หรือ JSON
Extracting Text Together with Annotations
แทนที่จะทำสองรอบบนเอกสาร คุณสามารถผสานข้อความ annotation เข้าไปในผลลัพธ์การดึงข้อความปกติได้โดยตรง
// Read document text with annotation text included
using (var parser = new Parser(path))
{
var options = new TextOptions
{
IncludeAnnotations = true
};
using (TextReader reader = parser.GetText(options))
{
return reader?.ReadToEnd() ?? string.Empty;
}
}
Key points:
IncludeAnnotationsเป็นคุณสมบัติของTextOptionsดังนั้นจึงทำงานร่วมกับการเรียกGetTextที่คุณใช้สำหรับการดึงข้อความธรรมดา- มีประโยชน์เมื่อต้องการผลลัพธ์แบบทรานสคริปต์เดียวแทนรายการคอมเมนต์แยกต่างหาก
- สามารถผสานกับ
GetText(pageIndex, options)หากต้องการเฉพาะหน้าหนึ่ง
Checking Annotation Support First
ไม่ใช่ทุกฟอร์แมตที่รองรับ annotation ดังนั้นควรตรวจสอบก่อนที่จะเขียนตรรกะรอบ GetAnnotations
// Returns true if the loaded document format supports annotation extraction
using (var parser = new Parser(path))
{
return parser.Features.Annotations;
}
Key points:
Features.Annotationsเป็นแฟล็กบูลีนง่าย ๆ บนอินสแตนซ์Parser- การตรวจสอบล่วงหน้าช่วยทำให้เจตนาโค้ดชัดเจน แม้ว่า
GetAnnotationsจะคืนค่าnullอย่างสุภาพอยู่แล้ว
Exporting the Annotations to CSV
การส่งออกเป็น CSV ทำให้ผู้ตรวจสอบสามารถเปิดรายการคอมเมนต์โดยตรงใน Excel วิธีด้านล่างเขียนไฟล์สองคอลัมน์ (page,value) จากรายการที่มีการแท็กหน้าที่สร้างไว้ก่อนหน้า
var sb = new StringBuilder();
sb.AppendLine("page,value");
foreach (var record in records)
{
sb.AppendLine($"{record.PageIndex},{CsvEscape(record.Value)}");
}
File.WriteAllText(outputPath, sb.ToString());
Key points:
CsvEscapeทำการใส่เครื่องหมายคำพูดอย่างปลอดภัยสำหรับฟิลด์ที่มีคอมม่า, เครื่องหมายคำพูด, หรือการขึ้นบรรทัดใหม่- ไฟล์ที่ได้เปิดโดยตรงใน Excel หรือสามารถส่งต่อไปยังเครื่องมือจัดการตั๋วได้
Helper: CsvEscape
if (string.IsNullOrEmpty(s)) return string.Empty;
if (s.Contains(",") || s.Contains("\"") || s.Contains("\n"))
{
return "\"" + s.Replace("\"", "\"\"") + "\"";
}
return s;
Exporting the Annotations to JSON
สำหรับ pipeline ที่ต้องการคอมเมนต์แบบโปรแกรมเมติก JSON array มักจะเหมาะกว่า CSV มาก
var sb = new StringBuilder();
sb.AppendLine("[");
for (int i = 0; i < records.Count; i++)
{
var comma = i < records.Count - 1 ? "," : string.Empty;
sb.AppendLine($" {{ \"page\": {records[i].PageIndex}, \"value\": \"{Escape(records[i].Value)}\" }}{comma}");
}
sb.AppendLine("]");
File.WriteAllText(outputPath, sb.ToString());
Key points:
- ผลลัพธ์เป็นอาร์เรย์แบนของอ็อบเจ็กต์
{ page, value }– ง่ายต่อการ deserialize โดยบริการ downstream ใด ๆ Escapeทำให้ payload เป็น JSON ที่ถูกต้องโดยไม่ต้องนำเข้าไลบรารีการแปลง
Helper: Escape
return s?.Replace("\\", "\\\\").Replace("\"", "\\\"") ?? string.Empty;
Comparing Methods: When to Use Each
| Method | Best For | Key Advantages | Limitations |
|---|---|---|---|
| Whole‑Document Extraction | ตรวจสอบอย่างรวดเร็วว่า “มีคอมเมนต์หรือไม่?” | เรียกครั้งเดียว, โค้ดง่ายที่สุด | ไม่มีการระบุหน้า |
| Per‑Page Extraction | ส่งต่อฟีดแบ็กไปยังส่วนที่ถูกต้อง | ผลลัพธ์มีการแท็กหน้า, พร้อมส่งออก | ต้องเรียกเพิ่มหนึ่งครั้งต่อหน้า |
| Combined Text + Annotations | สร้างทรานสคริปต์เดียวที่อ่านได้ | ไม่ต้องทำรอบที่สองบนเอกสาร | คอมเมนต์ไม่แยกจากข้อความหลัก |
| CSV Export | การติดตามการตรวจสอบแบบสเปรดชีต | เปิดง่ายใน Excel, อ่านได้โดยมนุษย์ | โครงสร้างแบน จำกัด |
| JSON Export | Pipeline อัตโนมัติ, ระบบตั๋ว | โครงสร้าง, อ่านโดยเครื่อง | ขนาด payload มากกว่าบางกรณี |
เริ่มด้วยการดึงแบบ Whole‑Document เพื่อตรวจสอบว่าไฟล์มีคอมเมนต์ที่ต้องดำเนินการหรือไม่, จากนั้นสลับไปใช้ Per‑Page เมื่อจำเป็นต้องระบุตำแหน่งฟีดแบ็ก
Best Practices and Tips
- Dispose
Parserทันที: ใช้usingblock เพื่อปล่อยทรัพยากรเนทีฟ - แยกแยะ
nullกับค่าว่าง:GetAnnotationsคืนnullหมายถึงฟอร์แมตไม่รองรับ; คอลเลกชันว่างหมายถึงไม่มีคอมเมนต์ - ตรวจสอบ
Features.Annotationsในงานแบช: ข้ามไฟล์ที่ไม่รองรับตั้งแต่ต้น แทนการตรวจnullภายในลูป - ใช้รายการที่แท็กหน้าครั้งเดียว: สร้างรายการด้วย
ExtractAnnotationsByPageแล้วส่งต่อให้ทั้งตัวส่งออก CSV และ JSON เพื่อให้ผลลัพธ์สองแบบสอดคล้องกัน - ความปลอดภัย: ข้อความ annotation เป็นข้อมูลที่ผู้ตรวจสอบใส่เอง – ควรจัดการเหมือนสตริงที่ไม่เชื่อถือได้ก่อนแสดงใน UI หรือรายงาน
Conclusion
GroupDocs.Parser ให้วิธีโดยตรงและโปรแกรมเมติกในการดึงคอมเมนต์ของผู้ตรวจสอบออกจาก PDF แทนการค้นหาด้วยตนเอง โดยการดึง annotation ทั้งไฟล์, แท็กตามหน้า, หรือผสานเข้ากับข้อความปกติ คุณสามารถสร้างกระบวนการตรวจสอบที่แสดงฟีดแบ็กทันทีเมื่อเอกสารเข้าสู่ pipeline ของคุณ ส่งออกผลลัพธ์เป็น CSV หรือ JSON แล้วเชื่อมต่อกับเครื่องมือที่ทีมของคุณใช้อยู่แล้ว
Next steps:
- สำรวจ GetAnnotations API reference เพื่อดูลายเซ็นเมธอดเต็มและ overloads
- เรียนรู้วิธี extract text from PDF documents ควบคู่กับ annotation เพื่อสร้าง pipeline เนื้อหาที่ครบถ้วน
- ดูตัวอย่างโปรเจกต์เพิ่มเติมบน GitHub สำหรับสถานการณ์การประมวลผลแบบแบช (Examples Repo)