φυβλαςのβλογ
บล็อกของ 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)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ

บทความแต่ละเดือน

2024年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2023年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2022年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2021年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2020年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

ค้นบทความเก่ากว่านั้น

ไทย

日本語

中文