φυβλαςのβλογ
บล็อกของ phyblas



การแปลงไฟล์ pdf เป็นรูปภาพโดยใช้มอดูล pdf2image
เขียนเมื่อ 2023/02/26 22:49
แก้ไขล่าสุด 2024/02/17 16:18
 



ในไพธอนมีมอดูลชื่อ pdf2image ซึ่งเอาไว้แปลงไฟล์ pdf มาเป็นไฟล์รูปภาพได้

ในบทความนี้จะเขียนอธิบายถึงวิธีการใช้งานมอดูลนี้อย่างง่าย




การติดตั้งและใช้งาน

pdf2image สามารถติดตั้งได้ง่ายโดยใช้ pip เช่นเดียวกับมอดูลส่วนใหญ่
pip install pdf2image

พอติดตั้งแล้วก็สามารถใช้งานได้เลย โดยมอดูลนี้โดยหลักๆแล้วมีอยู่แค่ ๒ ฟังก์ชัน คือ convert_from_path กับ convert_from_bytes แต่โดยทั่วไปแล้วใช้แค่ convert_from_path เป็นหลัก




การใช้ convert_from_path

ฟังก์ชัน convert_from_path ใช้เพื่อเปิดไฟล์ pdf ขึ้นมาเป็นลิสต์ของออบเจ็กต์รูปภาพของมอดูล PIL (pillow) ซึ่งสามารถใช้เมธอด .save() เพื่อทำการบันทึกเป็นไฟล์ภาพชนิดต่างๆได้

ตัวอย่างเช่นถ้าต้องการแปลงไฟล์ pdf ที่มีแค่หน้าเดียวให้เป็นไฟล์รูปภาพอาจเขียนโค้ดได้ดังนี้
import pdf2image

lis_img = pdf2image.convert_from_path(r'คัมภีร์คาถาต้องห้าม.pdf')
lis_img[0].save(r'ภาพจากคัมภีร์คาถาต้องห้าม.png')

ชนิดของภาพอาจเป็น png, jpg, gif, tif, bmp, ฯลฯ จะเป็นไฟล์ชนิดไหนก็ถูกตัดสินอัตโนมัติจากสกุลไฟล์ที่เขียนในชื่อ เช่นถ้าเขียนเป็ฯ
lis_img[0].save('xxx.jpg')

ก็จะได้เป็นไฟล์ jpg

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

lis_img = pdf2image.convert_from_path(r'คัมภีร์คาถาต้องห้าม.pdf')
for i in range(len(lis_img)):
    lis_img[i].save(r'ภาพจากคัมภีร์คาถาต้องห้าม_%d.png'%(i+1))




การใช้ convert_from_bytes

ฟังก์ชัน convert_from_bytes นั้นก็คล้ายกับ convert_from_path แค่จะไม่ได้อ่าน pdf จากตัวไฟล์ แต่ไปอ่านจากข้อมูลไบต์ภายในตัวไฟล์ ถ้าจะใช้อ่านไฟล์จากภาพก็ต้องเปิดไฟล์ขึ้นมาด้วย open ในโหมด rb ก่อนแล้วอ่านข้อมูลในตัวไฟล์แล้วจึงค่อยใช้ convert_from_bytes

อย่างตัวอย่างที่แปลง pdf เป็นภาพหลายๆหน้านั้นถ้าจะใช้ convert_from_bytes ก็อาจเขียนได้แบบนี้
import pdf2image

with open(r'คัมภีร์คาถาต้องห้าม.pdf','rb') as f:
    lis_img = pdf2image.convert_from_bytes(f.read())
    for i in range(len(lis_img)):
        lis_img[i].save(r'ภาพจากคัมภีร์คาถาต้องห้ามx_%d.png'%(i+1))




การปรับความละเอียดของภาพ

ปกติเมื่อใช้ convert_from_path โดยไม่ได้กำหนดขนาดความละเอียดของภาพจะได้ภาพที่อาจใหญ่ไปหน่อย แต่หากต้องการทำให้ภาพเล็กลงหรือใหญ่ขึ้นไปอีกก็อาจทำได้โดยใส่คีย์เวิร์ด dpi ลงไป เช่น
lis_img = pdf2image.convert_from_path(r'คัมภีร์คาถาต้องห้าม.pdf',dpi=72)

ถ้าไม่ได้ใส่ละก็ ค่าตั้งต้นคือ 200 ซึ่งค่อนข้างใหญ่

อนึ่ง จริงๆ dpi นั้นเป็นอาร์กิวเมนต์ตัวที่ ๒ อยู่แล้ว ดังนั้นก็อาจละ dpi= ไปก็ได้ เช่น
lis_img = pdf2image.convert_from_path(r'คัมภีร์คาถาต้องห้าม.pdf',72)




การกำหนดขนาดของภาพ

นอกจากกำหนดความละเอียดของภาพแล้ว เราอาจทำการกำหนดขนาดความกว้างและสูงของภาพโดยตรงได้เลย โดยใส่คีย์เวิร์ด size แล้วใส่ทูเพิลของความกว้างและสูงที่ต้องการลงไปได้เลย เช่น
lis_img = pdf2image.convert_from_path(r'คัมภีร์คาถาต้องห้าม.pdf',size=(300,200))
print(lis_img[0].size) # ได้ (300, 200)

แต่หากต้องการกำหนดแค่ความกว้างแล้วให้ความสูงถูกเปลี่ยนตามสัดส่วนละก็อาจใส่ตัวหลังเป็น None เช่น
lis_img = pdf2image.convert_from_path(r'คัมภีร์คาถาต้องห้าม.pdf',size=(300,None))
print(lis_img[0].size) # ได้ (300, 425)

ในตัวอย่างนี้ใช้กับเอกสารที่เป็ฯหน้า A4 ดังนั้นถ้าความกว้างเป็น 300 ความสูงก็จะเป็น 425 อย่างที่เห็น

และเช่นเดียวกัน หากตัวหน้าเป็น None ก็จะเป็นการกำหนดความสูง แล้วให้ความกว้างกำหนดตามสัดส่วนโดยอัตโนมัติ เช่น
lis_img = pdf2image.convert_from_path(r'คัมภีร์คาถาต้องห้าม.pdf',size=(None,200))
print(lis_img[0].size) # ได้ (142, 200)

นอกจากนี้อาจใส่เป็นเลขตัวเดียวก็ได้ ซึ่งนั่นจะหมายความว่ากำหนดทั้งความกว้างและสูงเป็นค่านั้น
lis_img = pdf2image.convert_from_path(r'คัมภีร์คาถาต้องห้าม.pdf',size=300)
print(lis_img[0].size) # ได้ (300, 300)




การเอาเฉพาะบางหน้า

หากต้องการจะเอาเฉพาะแค่บางหน้าภายในไฟล์ pdf ก็อาจทำได้โดยการใส่คีย์เวิร์ด first_page และ last_page ลงไป

เช่นถ้าต้องการแค่หน้า 2 ไปจนถึงหน้า 4 ก็อาจเขียนเป็น
lis_img = pdf2image.convert_from_path(r'คัมภีร์คาถาต้องห้าม.pdf',first_page=2,last_page=4)
print(len(lis_img)) # ได้ 3

แบบนี้ก็จะได้มาแค่ ๓ หน้า คือหน้า 2,3,4

อนึ่ง เลขหน้าในที่นี้จะนับจาก 1 ไม่ใช่นับจาก 0 ต่างจากลิสต์ในไพธอนที่เริ่มจาก 0 ดังนั้นระวังสับสน




การทำภาพโปร่งใส

ปกติภาพที่ได้จากการใช้ convert_from_path โดยทั่วไปจะได้ภาพที่ไม่มีความโปร่งใส และฉากหลังเป็นสีขาว แต่ให้ด้านหลังสีขาวนี้กลายเป็นโปร่งใสแทนก็ทำได้โดยใส่คีย์เวิร์ด transparent=True ลงไป เพียงแต่ว่าจะต้องใส่ fmt='png' ลงไปด้วย เพื่อให้อ่านขึ้นมาในโหมดภาพ png ซึ่งมีค่าความโปร่งใสอยู่ตั้งแต่แรก

อนึ่ง fmt ในที่นี้ปกติไม่ได้จำเป็นต้องใส่ เพราะยังไงตอนที่จะบันทึกเป็นภาพโดยใช้ .save() ก็กำหนดสกุลของภาพได้ตามที่ต้องการอยูด้วย แต่โดยปกติถ้าไม่ได้ใส่ fmt จะถูกอ่านเป็นชนิด ppm (portable pixmap) ซึ่งไม่ได้รวมค่า alpha (ค่าความไม่ใส) อยู่ด้วย

ลองเปิดแบบต่างๆแล้วเทียบผลลัพธ์ดู
img = pdf2image.convert_from_path(r'คัมภีร์คาถาต้องห้าม.pdf',fmt='png')[0]
print(img.mode) # ได้ RGB

img = pdf2image.convert_from_path(r'คัมภีร์คาถาต้องห้าม.pdf',fmt='png',transparent=True)[0]
print(img.mode) # ได้ RGBA

img = pdf2image.convert_from_path(r'คัมภีร์คาถาต้องห้าม.pdf',transparent=True)[0]
print(img.mode) # ได้ RGB

ในที่นี้ RGBA คือโหมดของภาพที่มีความโปร่งใส ถ้านำมาบันทึกเป็นไฟล์ png ก็จะได้จะเป็นภาพที่ฉากหลังโปร่งใส จะเห็นได้ว่าถึงใส่ transparent=True แต่ถ้าไม่ได้ใส่ fmt='png' ไปด้วยก็จะได้ผลไม่ต่างจากไม่ใส่ คือได้โหมด RGB ซึ่งเป็นภาพสีธรรมดาไม่มี A (คือค่า alpha) รวมอยู่




การทำเป็นภาพขาวดำ

หากไม่ต้องการสี ต้องการเปิดในโหมดภาพขาวดำก็ทำได้โดยใส่ grayscale=True ลงไป เท่านี้ก็กลายเป็นภาพขาวดำแล้ว
img = pdf2image.convert_from_path(r'คัมภีร์คาถาต้องห้าม.pdf',grayscale=True)[0]
print(img.mode) # ได้ L




การทำไฟล์ tiff หลายหน้า

ไฟล์ tiff (.tif) นั้นเป็นสกุลไฟล์ภาพที่สามารถบันทึกภาพหลายภาพลงในไฟล์เดียวได้ โดยแต่ละภาพนั้นจะถูกใส่แยกเป็นหน้า

การใช้ pdf2image เพื่อบันทึกแต่ละหน้าใน pdf ลงมาเป็นหน้าใน tiff อาจเขียนได้ดังนี้
import pdf2image

pdf_file = r'เอกสาร.pdf' # ชื่อไฟล์ pdf ที่จะแปลง
img_file = r'ภาพ.tif' # ชื่อไฟล์ tiff ที่ต้องการ

lis_img = pdf2image.convert_from_path(pdf_file,dpi=72)
lis_img[0].save(img_file,compression='tiff_deflate',save_all=True,append_images=lis_img[1:])

ในที่นี้จริงๆไม่ใช่ความสามารถของ pdf2image โดยตรง แต่เป็นความสามารถของเมธอด .save() ของตัวออบเจ็กต์ภาพของ PIL ดังนั้นจะขอละการอธิบายในรายละเอียด




การแปลงไฟล์เวิร์ดเป็นไฟล์ภาพ

หากต้องการจะแปลงไฟล์เวิร์ดไปเป็นไฟล์ภาพ เราอาจใช้ docx2pdf ร่วมกับ pdf2image ได้

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

สำหรับเรื่องการแปลงจากเวิร์ดเป็น pdf โดยใช้ docx2pdf อ่านได้ใน https://phyblas.hinaboshi.com/20230207

โค้ดแปลงเวิร์ดเป็นภาพ png อาจเขียนได้แบบนี้
import docx2pdf
import pdf2image
import os

word_file = r'คัมภีร์คาถาต้องห้าม.docx' # ชื่อไฟล์เวิร์ดที่ต้องการแปลง
img_path = r'ภาพจากคัมภีร์คาถาต้องห้าม' # ชื่อโฟลเดอร์ที่จะวางไฟล์ภาพที่ได้
dpi = 72 # ค่าความละเอียดของภาพ

# ก่อนอื่นแปลงเป็น pdf ก่อน
pdf_file = word_file+'.pdf' # ชื่อไฟล์ pdf ที่จะสร้างขึ้นมาชั่วคราว แต่เดี๋ยวก็จะลบอยู่แล้วที่จริงจะตั้งยังไงก็ได้
docx2pdf.convert(word_file,pdf_file)
# ถ้าโฟลเดอร์ที่จะวางรูปนั้นยังไม่มีอยู่ก็สร้างขึ้นมาก่อน
if(not os.path.exists(img_path)):
    os.mkdir(img_path)
# ทำการแปลงจาก pdf เป็นภาพ
lis_img = pdf2image.convert_from_path(pdf_file,dpi)
for i,img in enumerate(lis_img,1):
    img.save(os.path.join(img_path,str(i)+'.png'))
os.remove(pdf_file) # ไฟล์ pdf ใช้เสร็จแล้วก็ลงทิ้งได้

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

ถ้าหากมีอยู่หน้าเดียวอยู่แล้วก็อาจเขียนแบบนี้ได้เลย
word_file = r'คัมภีร์คาถาต้องห้าม.docx' # ชื่อไฟล์เวิร์ดที่ต้องการแปลง
img_file = r'ภาพจากคัมภีร์คาถาต้องห้าม.png' # ไฟล์ภาพที่ต้องการสร้าง
dpi = 72 # ค่าความละเอียดของภาพ

pdf_file = word_file+'.pdf'
docx2pdf.convert(word_file,pdf_file)
pdf2image.convert_from_path(pdf_file,dpi)[0].save(img_file)
os.remove(pdf_file)

เท่านี้ก็สามารถแปลงไฟล์เวิร์ดให้เป็นรูปภาพได้แล้ว




สรุปทิ้งท้าย

สุดท้ายนี้ของสรุปคีย์เวิร์ดต่างๆที่ใช้ใส่ใน convert_from_path ซึ่งได้กล่าวถึงมาในข้างต้นไว้ตรงนี้

dpi ความละเอียดของภาพที่อ่านได้
size ขนาดของภาพที่อ่านได้
first_page หน้าแรกที่จะอ่าน
last_page หน้าสุดท้ายที่จะอ่าน
fmt ฟอร์แม็ตของภาพที่อ่านได้
transparent ถ้าใส่ True จะได้ภาพที่ฉากหลังโปร่งใส
grayscale ถ้าใส่ True จะได้ภาพขาวดำ



อ้างอิง


-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python
-- คอมพิวเตอร์ >> pdf

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

สารบัญ

รวมคำแปลวลีเด็ดจากญี่ปุ่น
มอดูลต่างๆ
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
การเรียนรู้ของเครื่อง
-- โครงข่าย
     ประสาทเทียม
ภาษา javascript
ภาษา mongol
ภาษาศาสตร์
maya
ความน่าจะเป็น
บันทึกในญี่ปุ่น
บันทึกในจีน
-- บันทึกในปักกิ่ง
-- บันทึกในฮ่องกง
-- บันทึกในมาเก๊า
บันทึกในไต้หวัน
บันทึกในยุโรปเหนือ
บันทึกในประเทศอื่นๆ
qiita
บทความอื่นๆ

บทความแบ่งตามหมวด



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  ค้นหาบทความ

  บทความแนะนำ

ตัวอักษรกรีกและเปรียบเทียบการใช้งานในภาษากรีกโบราณและกรีกสมัยใหม่
ที่มาของอักษรไทยและความเกี่ยวพันกับอักษรอื่นๆในตระกูลอักษรพราหมี
การสร้างแบบจำลองสามมิติเป็นไฟล์ .obj วิธีการอย่างง่ายที่ไม่ว่าใครก็ลองทำได้ทันที
รวมรายชื่อนักร้องเพลงกวางตุ้ง
ภาษาจีนแบ่งเป็นสำเนียงอะไรบ้าง มีความแตกต่างกันมากแค่ไหน
ทำความเข้าใจระบอบประชาธิปไตยจากประวัติศาสตร์ความเป็นมา
เรียนรู้วิธีการใช้ regular expression (regex)
การใช้ unix shell เบื้องต้น ใน linux และ mac
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ

ไทย

日本語

中文