* 2023.09.06 ์ถ๊ฐ
์ข ๋ ๊ฐํธํ๊ฒ ์ฌ์ฉํ ์ ์๋๋ก ์คํ ๊ฐ๋ฅํ ํ์ผ๋ก ๋น๋ํ์๋ค. mac์ฉ ์คํ ํ์ผ๋ ๋ฐฐํฌํ๋ ค ํ์ง๋ง, ์ ์ ์๋ ์๋ฌ๋ก ์ธํด ํ๋ฃจ๋ฅผ ๊ผฌ๋ฐ ์จ๋ ์์ธ์ ๋ชป ์ฐพ์ ์ฐ์ ์๋์ฐ์ฉ ์คํ ํ์ผ๋ง ๊นํ๋ธ์ ์ถ๊ฐํ์๋ค.
์ ๊ทธ๋ฆฌ๊ณ , ์ง์ ์ฌ์ฉํ๋ฉด์ ๋ถํธํ ์ ์ด์๋ ์บก์ฒ ์๋ ์กฐ์ ์ GUI์์ ํ ์ ์๋๋ก ์ถ๊ฐํ์๊ณ , ์ด๊ธฐํ ๋ฒํผ๋ ์ถ๊ฐํ์๋ค.
์บก์ณ ์๋๋ฅผ ์ถ๊ฐํ ์ด์ ๋, ์คํํ๋ ํ๊ฒฝ๋ง๋ค e-book์์ ๋ค์ ํ์ด์ง๋ก ์ด๋ํ ๋, ํ๋ฉด ๋ก๋ฉ์ด ๋๋ฆฐ ๊ฒฝ์ฐ๊ฐ ์ข ์ข ์์๋ค. ๋๋ฌธ์ ์บก์ฒํ๊ธฐ ์ ์ ๋ค์ ํ์ด์ง๋ฅผ ๋๊ฒจ๋ณด๋ฉด์ ์ด๋ ์ ๋์ ํ ์ผ๋ก ์บก์ฒํ ์ง ํ๋จํ์ฌ ์ง์ ํด ์ฃผ๋ฉด ๋๋ค.
ํด๋น ํ์ผ์ ์๋ ๊นํ๋ธ ๋งํฌ๋ก ๋ค์ด๊ฐ์ dist ํด๋ ์์ ebook_to_pdf.exe์ ๋ฐ์ผ๋ฉด ๋๋ค.
์คํ ์ ์๋์ ๊ฐ์ ํ๋ฉด์ด ๋ฌ๋ค๋ฉด ์คํ์ ๋๋ฌ์ค์ผ ๋๋ค.
์คํ์ ๋๋ฅด๋ฉด ์๋ GUI ํ๋ฉด์ด ๋ฌ๋ค.
์ฌ์ฉ๋ฒ๊ณผ ์คํ ์ ์ ์์ฌํญ์ ๊นํ๋ธ Readme์ ์์ฑํด ๋์์ผ๋ ๊ผญ ์ฐธ๊ณ ํ๊ธธ ๋ฐ๋๋ค.
๋ง์ง๋ง์ผ๋ก ํ๋ ๋น๋ถ์ ๋ง์ ์ ํ๋ฉด ์ฌ๋ฐฐํฌ๋ ์ํด์ฃผ์ จ์ผ๋ฉด ํ๊ณ .. ๊ผญ ๊ฐ์ธ ์ฌ์ฉ ์ฉ๋๋ก๋ง ํ์ฉํ๊ธธ ๋ฐ๋๋ค. ๋ฐ์๋ ์ ์ด๋จ์ง๋ง ๋ง๋ค์ด์ง pdf๋ฅผ ๊ณต์ ํ๋ ๊ฒ์ ๋ถ๋ฒ์ด๋ฉฐ, ๋ณธ์ธ์ด ์ฑ ์์ ธ์ผ ํ๋ค. ๊ทธ๋ผ ์ ํ์ฉํ์๊ธธ..!
๋ค์ด๊ฐ๊ธฐ ์์..
์์ ๊ฐ๋ฐ์ ํ์ฐฝ ์
๋ฌธํ๋ ์๊ธฐ์ ๊ฐ๋ฐ ๊ด๋ จ ์์ ๋ค์ ๊ตฌ๋งคํ์ฌ ์คํ๋ผ์ธ ์ค์บ ๋งค์ฅ์ ๊ฐ์ PDF๋ก ์ถ์ถํด์ ์์ดํจ๋๋ก ๊ณต๋ถํ๊ณค ํ์๋ค. ์๋ ๊ฐ๋ฐ ์์ ์ ํ์ด์ง ์๋ ๋ง๊ณ , ๋ค๊ณ ๋ค๋๊ธฐ์ ํ๋ ๋ถ๋ถ์ด ๋ง์ ํจ๋๋ก ๊ณต๋ถํ๋ ๊ฒ์ ๋๋ฌด ํธ๋ฆฌํ์๊ณ , ๋ ๋ฐ์ค, ํ๊ธฐ, ๊ฒ์ ๋ฑ์ด ๊ฐ๋ฅํ๋ค๋ ๊ฑด ๋ฅ๋ฅ ๋ ๋งค์ฐ ํฅ์๋๋ ์ด์ ์ด ์์๋ค.
์ต๊ทผ ์ฑ
๋ค์ ๋ณผ ์ผ๋ค์ด ์๊ฒผ๊ณ , ๋ ์ฑ
์ ์ฌ์ ์คํ๋ผ์ธ ๋งค์ฅ์ ๊ฐ์ ์ค์บํ๊ณ ์ผ์ด ๋๋ฌด ๊ท์ฐฎ๊ณ ๋ฒ๊ฑฐ๋ก์์ e-book์ ๊ตฌ๋งคํ๋ฉด ๋๊ฒ ๋ค ์๊ฐํ๋ค. ํ์ง๋ง ๋ง์ ์ฐพ์๋ณด๋ ์ ๋ช
์์ ์์ ๊ตฌ๋งคํ๋ e-book๋ค์ DRM์ด ๊ฑธ๋ ค์์๊ณ , ๊ฐ ์
์ฒด๋ง๋ค ์ ๊ณตํ๋ ๋ทฐ์ด์์๋ง ์ฝ์ ์๊ฐ ์์๋ค. ๋๋ ๊ตฟ๋
ธํธ๋ ํ๋ ์ฌ๊ฐ์ ์ดํ์ ์ฌ์ฉํ์ฌ ํ๊ธฐ๊ฐ ์ ๊ณต๋๊ณ , ๋ฌธ์ ๊ฒ์(OCR)์ด ํ์ํ์๊ธฐ ๋๋ฌธ์ ์ผ๋ฐ pdf ํ์ผ๋ก ๋ณํ์ด ํ์ํ๋ค.
๋ฐฉ๋ฒ์ ์ฐพ๋ ์ค ํ ์ ํ๋ธ ์์์์ ์์ดํจ๋ E-Book ๋ทฐ์ด ์ฑ์ ํตํด ๋ชจ๋ ํ์ด์ง๋ฅผ ์บก์ฒํ๊ณ , pdf๋ก ๋ณํํ์ฌ ๊ตฟ๋
ธํธ ์ฑ์์ ํ์ฉํ๋ ๊ฒ์ ๋ณด์๋ค. ํด๋น ์ ํ๋ฒ๊ฐ ์
์ฒด์ ์ง์ ๋ฌธ์ํด๋ณด๋ ‘ํ์ธ์๊ฒ ๊ณต์ ๋๋ ๊ฒ์ด ์๋ ๊ฐ์ธ์ ์ผ๋ก ์ฌ์ฉ์ ๊ฒฝ์ฐ ์ ์๊ถ ์๋ฐ์ ํด๋น๋์ง ์๋๋ค ‘ ๋ผ๋ ๋ต๋ณ์ ๋ฐ์๊ณ , ๊ฒฐ๋ก ์ ๊ฐ์ธ์ ์ฌ์ฉ์๋ ๋ฌธ์ ๊ฐ ์๋ค๋ ๊ฒ์ด๋ค.
์ด ์์์ ๋ณด๊ณ ๋ฐ๋ก ๋ฌด์์ ๋ง๋ค์ด์ผ ํ ์ง ์๊ฐ์ด ๋ฌ๋ค.
1. ์ผ์ผ์ด ์บก์ฒ๋ ๊ท์ฐฎ๋ค! → ์๋์ผ๋ก ํ์ด์ง๋ฅผ ๋๊ธฐ๋ฉฐ ์บก์ฒํ๋๋ก ๊ตฌํ
2. ์ด๋ฏธ์ง๋ฅผ ๋ชจ์ pdf๋ก ๋ง๋ค์ด์ผ ๋๋ค! → ์๋์ผ๋ก PDF๋ก ๋ณํ
๋ฐ๋ก ํ์ด์ฐธ์ ์ค์นํ๊ณ ๊ฐ๋ฐ์ ๋ค์ด๊ฐ๋ค.
๊ฐ๋ฐ ํ๊ฒฝ
๋ณธ์ธ์ ๋งฅ๋ถ ์์ด M1์ ์ฌ์ฉํ๊ณ ์๋ค. ๋ชจ๋ ๊ฒ์ MacOS์ ๋ง์ถฐ์ ๊ฐ๋ฐํ์๋ค.
๊ฐ๋ฐ ๊ณผ์
1. APP UI
๊ธฐ๋ฅ ๊ตฌํ๋ณด๋ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ๊ฒฝ ๊ตฌ์ถ์์ ์๊ฐ์ด ๋ง์ด ๊ฑธ๋ ธ๋ค. ์๋ง ์ต์ MacOS์ ๋ํ ์ ์ฝ ์ฌํญ์ด ์ด์ ๋ณด๋ค ๋ง์์ง ๋๋์ด์๋ค. GUI๋ฅผ ๊ตฌํํ๊ธฐ ์ํด PyQt5๋ฅผ ์ฌ์ฉํ๋ ค ํ์ผ๋ ์ด๋์ ๋ ์๋ํด๋ ์ ์์ ์ผ๋ก ์ค์น๊ฐ ์๋๋ค.. ๊ฒ์ํ๋ค๋ณด๋ ์ต์ OS ์
๋ฐ์ดํธ ์ดํ์๋ ์ฌ์ฉ์ด ์๋๋ค๋ ๊ธ์ ๋ดค๊ณ , ๋์ฒด๋ก PySide๋ฅผ ์ฌ์ฉํ๋ผ๋ ๋ง์ด ์์ด์ ๋ฐ๋ก PySide6๋ฅผ ์ค์นํ์๋ค.
# ์ฑ ํ์ดํ
self.setWindowTitle("eBookToPdf")
# ๋ฒํผ ์์ฑ
self.button1 = QPushButton("์ขํ ์์น ํด๋ฆญ")
self.button2 = QPushButton("์ขํ ์์น ํด๋ฆญ")
self.button3 = QPushButton("PDF๋ก ๋ง๋ค๊ธฐ")
self.button3.setFixedSize(QSize(430, 60))
# ๋ฒํผ ํด๋ฆญ ์ด๋ฒคํธ
self.button1.clicked.connect(self.์ข์ธก์๋จ_์ขํ_ํด๋ฆญ)
self.button2.clicked.connect(self.์ฐ์ธกํ๋จ_์ขํ_ํด๋ฆญ)
self.button3.clicked.connect(self.btn_click)
self.title = QLabel('E-Book PDF ์์ฑ๊ธฐ', self)
self.title.setAlignment(Qt.AlignmentFlag.AlignCenter)
font_title = self.title.font()
font_title.setPointSize(20)
self.title.setFont(font_title)
self.stat = QLabel('', self)
self.stat.setAlignment(Qt.AlignmentFlag.AlignCenter)
font_stat = self.stat.font()
font_stat.setPointSize(18)
font_stat.setBold(True)
self.stat.setFont(font_stat)
self.sign = QLabel('Made By EastShine', self)
self.sign.setAlignment(Qt.AlignmentFlag.AlignRight)
font_sign = self.stat.font()
font_sign.setPointSize(10)
font_sign.setItalic(True)
self.sign.setFont(font_sign)
self.label1 = QLabel('์ด๋ฏธ์ง ์ข์ธก์๋จ ์ขํ ==> ', self)
self.label1_1 = QLabel('(0, 0)', self)
self.label2 = QLabel('์ด๋ฏธ์ง ์ฐ์ธกํ๋จ ์ขํ ==> ', self)
self.label2_1 = QLabel('(0, 0)', self)
self.label3 = QLabel('์ด ํ์ด์ง ์ ', self)
self.label4 = QLabel('PDF ์ด๋ฆ ', self)
self.input1 = QLineEdit()
self.input1.setPlaceholderText("์ด ํ์ด์ง ์๋ฅผ ์
๋ ฅํ์ธ์.")
self.input2 = QLineEdit()
self.input2.setPlaceholderText("์์ฑํ PDF์ ์ด๋ฆ์ ์
๋ ฅํ์ธ์.")
# Box ์ค์
box1 = QHBoxLayout()
box1.addWidget(self.label1)
box1.addWidget(self.label1_1)
box1.addWidget(self.button1)
box2 = QHBoxLayout()
box2.addWidget(self.label2)
box2.addWidget(self.label2_1)
box2.addWidget(self.button2)
box3 = QHBoxLayout()
box3.addWidget(self.label3)
box3.addWidget(self.input1)
box4 = QHBoxLayout()
box4.addWidget(self.label4)
box4.addWidget(self.input2)
box5 = QHBoxLayout()
box5.addWidget(self.stat)
box5.addWidget(self.sign)
# ๋ ์ด์์ ์ค์
layout = QVBoxLayout()
layout.addWidget(self.title)
layout.addStretch(2)
layout.addLayout(box1)
layout.addStretch(1)
layout.addLayout(box2)
layout.addStretch(1)
layout.addLayout(box3)
layout.addStretch(1)
layout.addLayout(box4)
layout.addStretch(4)
layout.addLayout(box5)
layout.addWidget(self.button3)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
# ์ฐฝ ํฌ๊ธฐ ๊ณ ์
self.setFixedSize(QSize(450, 320))
๋ค์๊ณผ ๊ฐ์ด ๊ฐ๋จํ๊ฒ GUI๋ฅผ ๊ตฌ์ฑํ๋ค. (๋์ค์ ํน์ ์๊ตฌ์ฌํญ์ด ์์ผ๋ฉด ์คํํ์ผ๋ก ๋ฐฐํฌ๋ ํด๋ณด๊ณ ์ถ์ด made by๋ ๋ฃ์ด๋จ๋ค.)
์ ์ ์๊ฒ ๋ฐ์์ผ ํ๋ ๋ฐ์ดํฐ๋ฅผ ์
๋ ฅํ ์ ์๋๋ก ์ฌํํ๊ฒ ๊ตฌ์ฑํ๋ค.
2. ์ด๋ฏธ์ง ์บก์ฒ
pdf๋ฅผ ๋ง๋ค๊ธฐ ์ํด ebook์ ๋ชจ๋ ํ์ด์ง๋ฅผ ์บก์ฒํ์ฌ์ผ ํ๋ค. ์บก์ณ๋ฅผ ์ํด PyAutoGUI, mss, pynput ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์๋ค.
def ์ข์ธก์๋จ_์ขํ_ํด๋ฆญ(self):
def on_click(x, y, button, pressed):
self.posX1 = int(x)
self.posY1 = int(y)
self.label1_1.setText(str(f'({int(x)}, {int(y)})'))
print('Button: %s, Position: (%s, %s), Pressed: %s ' % (button, x, y, pressed))
if not pressed:
return False
with mouse.Listener(on_click=on_click) as listener:
listener.join()
์บก์ณํ ์์ญ์ ์ง์ ํ๊ธฐ ์ํด Click Event๋ก ์ด๋ฏธ์ง์ ๋งจ ์ข์ธก ์๋จ๊ณผ ๋งจ ์ฐ์ธก ํ๋จ์ ์ขํ๋ฅผ ๊ตฌํ๋๋ก ํ๋ค. ๋๋ค ์๋ ๋ฐฉ์์ ๋๊ฐ์์ ์ข์ธก์๋จ์ ์ขํ ํด๋ฆญ ์ฝ๋๋ง ์ ์ด๋์๋ค.
# ํ์ผ ์ ์ฅ
while self.num <= self.total_page:
time.sleep(0.1)
# ์บก์ณํ๊ธฐ
with mss.mss() as sct:
# Grab the data
img = sct.grab(self.region)
# Save to the picture file
mss.tools.to_png(img.rgb, img.size, output=f'pdf_images/img_{str(self.num).zfill(4)}.png')
# ํ์ด์ง ๋๊ธฐ๊ธฐ
kb_control.press(Key.right)
kb_control.release(Key.right)
self.num += 1
PyAutoGUI์๋ ์บก์ฒ๋ฅผ ์ง์ํ์ง๋ง, mss ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฑ๋ฅ๊ณผ ์๋๊ฐ ๋น๊ต์ ๋นจ๋ผ์ ์บก์ฒ๋ mss๋ฅผ ํ์ฉํ์๋ค.
'pdf_images' ํด๋๋ฅผ ์์ฑํ์ฌ ๊ทธ ์์ ์ด๋ฏธ์ง๋ฅผ ์ ์ฅํ๋๋ก ํ๊ณ , zfill์ ํ์ฉํด String ์ค๋ฆ์ฐจ์ ์ ๋ ฌ์ ๋ฌธ์ ๊ฐ ์๋๋ก 'img_0001', 'img_0002' ์ด๋ฐ ์์ผ๋ก ํ์ผ ์ด๋ฆ์ ๋ง๋ค์ด ์ฃผ์๋ค.
์บก์ณ ํ์ pynput ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ํค๋ณด๋์ ์ค๋ฅธ์ชฝ ๋ฐฉํฅํค๋ฅผ ๋๋ฌ์ฃผ๋ ์ด๋ฒคํธ๋ฅผ ๋ฃ์ด์ฃผ์ด ๋ค์ ํ์ด์ง๋ก ์ ํํ๋๋ก ํด์ฃผ์๋ค.
3. PDF ๋ณํ
# ์ด๋ฏธ์ง ํ์ผ ๋ฆฌ์คํธ
file_list = os.listdir(path)
file_list = natsort.natsorted(file_list)
# .DS_Store ํ์ผ์ด๋ฆ ์ญ์
if '.DS_Store' in file_list:
del file_list[0]
img_list = []
# PDF ์ฒซ ํ์ด์ง ๋ง๋ค์ด๋๊ธฐ
img_path = 'pdf_images/' + file_list[0]
im_buf = Image.open(img_path)
cvt_rgb_0 = im_buf.convert('RGB')
for i in file_list:
img_path = 'pdf_images/' + i
im_buf = Image.open(img_path)
cvt_rgb = im_buf.convert('RGB')
img_list.append(cvt_rgb)
del img_list[0]
pdf_name = self.input2.text()
if pdf_name == '':
pdf_name = 'default'
cvt_rgb_0.save(pdf_name+'.pdf', save_all=True, append_images=img_list)
print("PDF ๋ณํ ์๋ฃ!")
self.stat.setText('PDF ๋ณํ ์๋ฃ!')
shutil.rmtree('pdf_images/')
pdf_image ํด๋์ ์๋ ํ์ผ์ ์ค๋ฆ์ฐจ์ ์ ๋ ฌ ํ ‘.DS_Store’ ํ์ผ์ด ๊ณ์ ํฌํจ๋๊ธธ๋(MacOS ์์คํ
์ด finder๋ก ์ ๊ทผํ ๋ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํด ์๋์ผ๋ก ์์ฑ๋๋ ํ์ผ์ด๋ค.) ํ์ผ List์์ ์ญ์ ํด์ฃผ์๊ณ , PIL ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํตํด PDF ํ์ผ๋ก ๋ณํํด์ฃผ์๋ค.
์ฒซ ํ์ด์ง๋ก ํ์ ๋ง๋ค์ด๋๊ณ , ์ฒซ ํ์ด์ง๊ฐ ์ ์ธ๋ ์ด๋ฏธ์ง ๋ฆฌ์คํธ๋ฅผ ํ์ append ํด์ฃผ๋ ๋ฐฉ์์ผ๋ก ๋ง๋ค์๋ค. (๊ณ์ ์ฒซํ์ด์ง๊ฐ 2์ฅ์ด ๋๋ ์ํฉ์ด ์๊ฒผ์๋ค..)
PDF ๋ณํ ํ์๋ ์ด๋ฏธ์ง ์บก์ฒ ํด๋๋ฅผ ํต์ผ๋ก ์ญ์ ํด์ฃผ์๋ค.
์ ์ฒด ์ฝ๋
https://github.com/eastshine12/eBookToPdf.git
์์ ๊นํ๋ธ ๋งํฌ๋ฅผ ํตํด ์ ์ฒด ์ฝ๋๋ฅผ ํ์ธํ ์ ์๋ค!
์ฌ์ฉ ์ ์ ์์ฌํญ
- ํด๋น ํ๋ก๊ทธ๋จ์ mac ์ ์ฉ app์ด๋ค.
- ์ด๋ฏธ์ง ์ขํ ์์ญ์ด ๋ทฐ์ด ์์ญ์ ๋ฒ์ด๋๋ฉด ์๋๋ค.
- ํค๋ณด๋ ์ค๋ฅธ์ชฝ ๋ฐฉํฅํค๋ฅผ ํตํด ๋ค์ ํ์ด์ง ์ ํ์ด ๋์ด์ผ ํ๋ค.
- ํ์ด์ง ์๊ฐ ๋ง์ ๊ฒฝ์ฐ PDF ์ฉ๋์ด ๊ฝค ๋๋ฏ๋ก HDD ์ฉ๋์ด ์ฌ์ ๊ฐ ์์ด์ผ ํ๋ค.
๋ง์น๋ฉฐ..
์ฐธ๊ณ ๋ก ๋ช ์
์ฒด์ ๋ทฐ์ด๋ ์บก์ฒ ์ ํด๋น ๋ทฐ์ด์ ํ๋ฉด์ด ๋ํ๋์ง ์๋๋ค. ์บก์ฒ ์กฐ์ฐจ ๋ง์๋ ๊ฒ์ด๋ค. ๋ด๊ฐ ํ
์คํธํ ๋ทฐ์ด๋ ์x๋ ๋งฅ ์ ์ฉ ๋ทฐ์ด์ด๋ค.
ํด๋น ํ๋ก๊ทธ๋จ์ ๋์ ํธ๋ฆฌํจ์ ์ํด ๋ง๋ค์ด์ง ๊ฒ์ด๋ฉฐ, ๋ง์ฝ ํ์ํ ์ฌ๋์ด ์๋ค๋ฉด ๋ฐ๋์ ๊ฐ์ธ ์ฌ์ฉ ๋ชฉ์ ์ผ๋ก ์ฌ์ฉํ๊ธธ ๋ฐ๋๋ค. ์์๋ ๋ช
์ํ์ง๋ง ๊ฐ์ธ ์ธ ํ์ธ ๊ณต์ ๋ ์ ์๊ถ ๋ฒ์ ์๋ฐฐ๋๋ฉฐ ์ด์ ๋ํ ์ฑ
์์ ์ฌ์ฉ์ ๋ณธ์ธ์ด ์ง๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ๋ช
์ฌํ์ฌ ์ฌ์ฉํ์๊ธธ..