mpdf 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. #!/usr/bin/python3
  2. # -*- coding: utf-8 -*-
  3. import gi, sys, os, locale, cairo
  4. from gi.repository import Gio, Gtk, GLib, GdkPixbuf, Gdk, Poppler, GObject
  5. translate = {"tr":{0:"Sayfa Genişliği",
  6. 1:"Sayfa Yüksekliği",
  7. 2:"Orjinal Boyut",
  8. 3:"Pdf Dosyası Seçiniz",
  9. 4:"Yazı Kopyalandı",
  10. 5:"Sayfa No",
  11. 6:"Bulunan İfade Sayısı",
  12. 7:"Tüm Dökümanda Ara",
  13. 8:"Aranıyor",
  14. 9:"Milis Linux için Poppler ile yazılmış basit bir pdf görüntüleyici."},
  15. "en":{0:"Page Width",
  16. 1:"Page Height",
  17. 2:"Original Size",
  18. 3:"Select Pdf File",
  19. 4:"Text Copied",
  20. 5:"Page Number",
  21. 6:"Number of Expressions Found",
  22. 7:"Search All Documents",
  23. 8:"Searching",
  24. 9:"A simple pdf viewer for Milis Linux written in Poppler."}}
  25. l = locale.getdefaultlocale()
  26. l = l[0].split("_")[0]
  27. locales = list(translate.keys())
  28. if l not in locales:
  29. l = "en"
  30. _ = translate[l]
  31. class MPdf(Gtk.Window):
  32. def __init__(self):
  33. super(MPdf, self).__init__()
  34. self.scale_factor = 1
  35. self.is_full_screen = 0
  36. self.document = False
  37. self.selection = False
  38. self.selection_texts = [[],0]
  39. self.sizes = [_[0],_[1],_[2],"%75","%100","%125","%150","%200","%300","%400","%500"]
  40. self.h_bar = Gtk.HeaderBar()
  41. self.h_bar.set_title("MPdf")
  42. self.set_titlebar(self.h_bar)
  43. self.h_bar.set_show_close_button(True)
  44. self.open_pdf_file_button = Gtk.ToolButton()
  45. self.open_pdf_file_button.set_stock_id(Gtk.STOCK_FILE)
  46. self.open_pdf_file_button.connect("clicked", self.open_pdf_file)
  47. self.h_bar.pack_start(self.open_pdf_file_button)
  48. self.print_button = Gtk.ToolButton()
  49. self.print_button.connect("clicked",self.print_button_show)
  50. self.print_button.set_stock_id(Gtk.STOCK_PRINT)
  51. self.h_bar.pack_start(self.print_button)
  52. self.about_button = Gtk.ToolButton()
  53. self.about_button.connect("clicked",self.about_button_show)
  54. self.about_button.set_stock_id(Gtk.STOCK_ABOUT)
  55. self.h_bar.pack_end(self.about_button)
  56. self.pages_sb = Gtk.SpinButton(climb_rate=1, digits=0)
  57. self.pages_sb.connect("value-changed",self.change_current_page)
  58. self.pages_sb.set_wrap(True)
  59. self.h_bar.pack_start(self.pages_sb)
  60. self.max_page_lb = Gtk.Label()
  61. self.h_bar.pack_start(self.max_page_lb)
  62. self.search_entry = Gtk.SearchEntry()
  63. self.search_entry.connect("search-changed",self.change_search_entry)
  64. self.h_bar.pack_start(self.search_entry)
  65. self.spinner = Gtk.Spinner()
  66. self.spinner.start()
  67. self.h_bar.pack_start(self.spinner)
  68. self.search_up_button = Gtk.ToolButton()
  69. self.search_up_button.set_stock_id(Gtk.STOCK_GO_UP)
  70. self.search_up_button.connect("clicked", self.search_up_func)
  71. self.h_bar.pack_start(self.search_up_button)
  72. self.search_down_button = Gtk.ToolButton()
  73. self.search_down_button.set_stock_id(Gtk.STOCK_GO_DOWN)
  74. self.search_down_button.connect("clicked", self.search_down_func)
  75. self.h_bar.pack_start(self.search_down_button)
  76. self.scale_combo = Gtk.ComboBoxText.new_with_entry()
  77. self.scale_combo.connect("changed", self.scale_combo_changed)
  78. for size in self.sizes:
  79. self.scale_combo.append_text(size)
  80. self.h_bar.pack_end(self.scale_combo)
  81. self.scale_combo.set_active(2)
  82. self.info_bar = Gtk.Label()
  83. self.h_bar.pack_end(self.info_bar)
  84. h_box = Gtk.HBox()
  85. v_box = Gtk.VBox()
  86. v_box.pack_start(h_box, True, False, 0)
  87. self.scroll = Gtk.ScrolledWindow()
  88. self.scroll.connect("edge-overshot",self.scroll_max_position)
  89. self.scroll.connect("scroll-event", self.on_scroll)
  90. self.scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
  91. self.doc_viewer = Gtk.DrawingArea()
  92. self.doc_viewer.set_events(Gdk.EventMask.BUTTON_PRESS_MASK|Gdk.EventMask.BUTTON_MOTION_MASK|Gdk.EventMask.BUTTON_RELEASE_MASK|Gdk.EventMask.KEY_PRESS_MASK )
  93. self.doc_viewer.connect("draw", self.draw_pdf_file)
  94. self.doc_viewer.connect("button_press_event", self.selection_start)
  95. self.doc_viewer.connect("motion-notify-event", self.selection_move)
  96. self.doc_viewer.connect("button-release-event", self.selection_stop)
  97. self.scroll.add_with_viewport(self.doc_viewer)
  98. self.scroll.set_propagate_natural_width(True)
  99. self.scroll.set_propagate_natural_height(True)
  100. h_box.pack_start(self.scroll, True, False, 0)
  101. self.add(v_box)
  102. self.set_default_size(640,480)
  103. self.control_is_press = False
  104. self.connect('size-allocate', self.size_changed)
  105. self.connect("key-press-event",self.key_press)
  106. self.connect("key-release-event",self.key_release)
  107. def about_button_show(self, widget):
  108. about = Gtk.AboutDialog()
  109. about.set_program_name("MPdf")
  110. about.set_version("1.0")
  111. about.set_logo_icon_name("qpdfview")
  112. about.set_authors(["SonAkinci41"])
  113. about.set_comments(_[9])
  114. about.set_copyright("(c) 2021 Fatih Kaya <sonakinci41@gmail.com>")
  115. about.set_license(" GPL-3.0 License ")
  116. about.set_website("https://mls.akdeniz.edu.tr/git/sonakinci41/MPdf")
  117. about.run()
  118. about.destroy()
  119. def print_button_show(self, widget):
  120. if self.document:
  121. pd = Gtk.PrintOperation()
  122. pd.set_n_pages(self.document_pages)
  123. pd.connect("draw_page",self.draw_page)
  124. result = pd.run(Gtk.PrintOperationAction.PRINT_DIALOG, self)
  125. def draw_page(self, operation, print_ctx, page_num):
  126. cr = print_ctx.get_cairo_context()
  127. page = self.document.get_page(page_num)
  128. page.render(cr)
  129. def on_scroll(self,widget,scroll):
  130. if self.control_is_press:
  131. self.scale_factor -= scroll.delta_y
  132. self.scale_combo.get_child().set_text("% "+str(int(self.scale_factor*100)))
  133. return True
  134. else:
  135. return False
  136. def search_up_func(self, widget):
  137. if self.document:
  138. if (self.selection_texts[1] - 1) != -1:
  139. self.selection_texts = [self.selection_texts[0], self.selection_texts[1] - 1]
  140. self.doc_viewer.queue_draw()
  141. else:
  142. if (self.current_page - 1) != -1:
  143. self.search_next_or_prev("prev")
  144. self.scroll_focus_selected()
  145. def search_down_func(self, widget):
  146. if self.document:
  147. if (self.selection_texts[1] + 1) != len(self.selection_texts[0]):
  148. self.selection_texts = [self.selection_texts[0], self.selection_texts[1] + 1]
  149. self.doc_viewer.queue_draw()
  150. else:
  151. if (self.current_page + 1) != self.document_pages:
  152. self.search_next_or_prev("next")
  153. self.scroll_focus_selected()
  154. def scroll_focus_selected(self):
  155. if self.selection_texts[0] != []:
  156. w, he = self.get_size()
  157. v_adj = self.scroll.get_vadjustment()
  158. h_adj = self.scroll.get_hadjustment()
  159. s_rec = self.selection_texts[0][self.selection_texts[1]]
  160. h = ((s_rec.x1 + s_rec.x2) / 2) / self.doc_width
  161. v = (self.doc_height - ( (s_rec.y1 + s_rec.y2)) / 2) / self.doc_height
  162. v_adj.set_value(v*v_adj.get_upper()- (he / 2))
  163. self.scroll.set_vadjustment(v_adj)
  164. h_adj.set_value(h*h_adj.get_upper() - (w / 2))
  165. self.scroll.set_hadjustment(h_adj)
  166. def scroll_max_position(self, widget, pos):
  167. if pos == Gtk.PositionType.BOTTOM:
  168. if self.document and self.current_page != self.document_pages - 1:
  169. v_adj = self.scroll.get_vadjustment()
  170. v_adj.set_value(v_adj.get_lower())
  171. self.scroll.set_vadjustment(v_adj)
  172. self.pages_sb.set_value(self.current_page + 2)
  173. elif pos == Gtk.PositionType.TOP :
  174. if self.document and self.current_page != 0:
  175. v_adj = self.scroll.get_vadjustment()
  176. v_adj.set_value(v_adj.get_upper())
  177. self.scroll.set_vadjustment(v_adj)
  178. self.pages_sb.set_value(self.current_page)
  179. def key_release(self, widget, event):
  180. key_name = Gdk.keyval_name(event.keyval)
  181. if key_name == "Control_L" or key_name == "Control_R":
  182. self.control_is_press = False
  183. def key_press(self, widget, event):
  184. key_name = Gdk.keyval_name(event.keyval)
  185. if not self.search_entry.is_focus() and not self.pages_sb.is_focus() and not self.scale_combo.is_focus():
  186. if key_name == "Left":
  187. if self.document and self.current_page != 0:
  188. self.pages_sb.set_value(self.current_page)
  189. elif key_name == "Right":
  190. if self.document and self.current_page != self.document_pages - 1:
  191. self.pages_sb.set_value(self.current_page + 2)
  192. elif key_name == "Up":
  193. v_adj = self.scroll.get_vadjustment()
  194. v_val = v_adj.get_value()
  195. if v_val - 20 > v_adj.get_lower():
  196. v_val -= 20
  197. else:
  198. v_val = v_adj.get_upper()
  199. self.pages_sb.set_value(self.current_page)
  200. v_adj.set_value(v_val)
  201. self.scroll.set_vadjustment(v_adj)
  202. elif key_name == "Down":
  203. v_adj = self.scroll.get_vadjustment()
  204. v_val = v_adj.get_value()
  205. n_val = v_val + 20
  206. v_adj.set_value(n_val)
  207. self.scroll.set_vadjustment(v_adj)
  208. if self.scroll.get_vadjustment().get_value() != n_val and self.current_page != self.document_pages - 1:
  209. v_adj.set_value(v_adj.get_lower())
  210. self.scroll.set_vadjustment(v_adj)
  211. self.pages_sb.set_value(self.current_page + 2)
  212. elif key_name == "Control_L" or key_name == "Control_R":
  213. self.control_is_press = True
  214. def search_next_or_prev(self, next_prev):
  215. if next_prev == "next":
  216. self.search_page_number = self.current_page + 1
  217. else:
  218. self.search_page_number = self.current_page - 1
  219. text = self.search_entry.get_text().lower()
  220. self.spinner.show()
  221. GObject.timeout_add(10, self.search_thread,text,next_prev)
  222. def search_thread(self,text,next_prev):
  223. a_page = self.document.get_page(self.search_page_number)
  224. s_text = a_page.find_text(text)
  225. if len(s_text) != 0:
  226. self.spinner.hide()
  227. self.pages_sb.set_value(self.search_page_number+1)
  228. return False
  229. if next_prev == "next":
  230. self.search_page_number += 1
  231. else:
  232. self.search_page_number -= 1
  233. if self.search_page_number == self.document_pages or self.search_page_number == -1:
  234. self.spinner.hide()
  235. return False
  236. else:
  237. return True
  238. def change_search_entry(self,widget):
  239. text = widget.get_text().lower()
  240. if self.document and text != "":
  241. finding = self.active_page.find_text(text)
  242. self.selection_texts = [finding, 0]
  243. if finding == []:
  244. self.search_next_or_prev("next")
  245. self.doc_viewer.queue_draw()
  246. elif text == "":
  247. self.selection_texts = [[], 0]
  248. self.doc_viewer.queue_draw()
  249. #self.search_all_func(None)
  250. def selection_start(self,widget,pos):
  251. self.selection = [pos.x,pos.y,pos.x,pos.y]
  252. self.doc_viewer.queue_draw()
  253. def selection_move(self,widget,pos):
  254. self.selection[2] = pos.x
  255. self.selection[3] = pos.y
  256. self.doc_viewer.queue_draw()
  257. def selection_stop(self,widget,pos):
  258. self.selection[2] = pos.x
  259. self.selection[3] = pos.y
  260. self.doc_viewer.queue_draw()
  261. calc_rect = self.calc_selection(self.selection)
  262. p_rect = Poppler.Rectangle()
  263. p_rect.x1 = calc_rect[0]
  264. p_rect.x2 = calc_rect[0] + calc_rect[2]
  265. p_rect.y1 = calc_rect[1]
  266. p_rect.y2 = calc_rect[1] + calc_rect[3]
  267. s_text = self.active_page.get_selected_text(Poppler.SelectionStyle.GLYPH ,p_rect)
  268. if s_text != " " and s_text != "" and s_text != "\n":
  269. os.system("wl-copy '{}'".format(s_text))
  270. self.info_bar.set_text(_[4])
  271. GObject.timeout_add(2000, self.hide_info_bar)
  272. self.selection = False
  273. self.scroll.grab_focus()
  274. def hide_info_bar(self):
  275. self.info_bar.set_text("")
  276. return False
  277. def open_pdf_file(self,widget):
  278. dialog = Gtk.FileChooserDialog(_[3], self, Gtk.FileChooserAction.OPEN,
  279. (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
  280. filter_ = Gtk.FileFilter()
  281. filter_.set_name(_[2])
  282. filter_.add_pattern("*.pdf")
  283. dialog.add_filter(filter_)
  284. return_dialog = dialog.run()
  285. if return_dialog == Gtk.ResponseType.OK:
  286. self.load_pdf_file(dialog.get_filename())
  287. dialog.destroy()
  288. def size_changed(self, widget, alloc):
  289. if self.document:
  290. text = self.scale_combo.get_active_text()
  291. old_scale_factor = self.scale_factor
  292. w,h = self.get_size()
  293. if text == self.sizes[0]:
  294. self.scale_factor = w/self.doc_width
  295. elif text == self.sizes[1]:
  296. self.scale_factor = h/self.doc_height
  297. if old_scale_factor != self.scale_factor:
  298. self.doc_viewer.set_size_request(self.doc_width*self.scale_factor, self.doc_height*self.scale_factor)
  299. self.doc_viewer.queue_draw()
  300. def scale_combo_changed(self,widget):
  301. if self.document:
  302. text = widget.get_active_text()
  303. old_scale_factor = self.scale_factor
  304. w,h = self.get_size()
  305. if text == self.sizes[0]:
  306. self.scale_factor = w/self.doc_width
  307. elif text == self.sizes[1]:
  308. self.scale_factor = h/self.doc_height
  309. elif text == self.sizes[2]:
  310. self.scale_factor = 1
  311. elif "%" in text:
  312. text = text.replace("%","")
  313. text = text.replace(" ","")
  314. try:
  315. t = int(text)
  316. if t < 25:
  317. t = 25
  318. elif t > 750:
  319. t = 750
  320. self.scale_factor = t/100
  321. except:
  322. pass
  323. else:
  324. text = text.replace("%","")
  325. text = text.replace(" ","")
  326. try:
  327. t = int(text)
  328. if t < 25:
  329. t = 25
  330. elif t > 750:
  331. t = 750
  332. self.scale_factor = t/100
  333. except:
  334. pass
  335. if old_scale_factor != self.scale_factor:
  336. self.doc_viewer.set_size_request(self.doc_width*self.scale_factor, self.doc_height*self.scale_factor)
  337. self.doc_viewer.queue_draw()
  338. self.scroll.grab_focus()
  339. def load_pdf_file(self,f):
  340. g_file = Gio.File.new_for_path(f)
  341. self.document = Poppler.Document.new_from_gfile(g_file, None, None)
  342. self.current_page = 0
  343. self.document_pages = self.document.get_n_pages()
  344. #Sayfa değiştirici
  345. ad = Gtk.Adjustment(0, 1, self.document_pages, 1, 0, 0)
  346. self.pages_sb.set_adjustment(ad)
  347. self.pages_sb.set_value(self.current_page+1)
  348. self.max_page_lb.set_text("/ {}".format(str(self.document_pages)))
  349. self.h_bar.set_title(os.path.split(f)[-1])
  350. #Aktif sayfayı ve boyutunu getirelim
  351. self.get_pdf_page()
  352. self.search_entry.set_text("")
  353. def change_current_page(self,widget):
  354. n_current_page = int(widget.get_text()) - 1
  355. if self.current_page != n_current_page:
  356. self.current_page = n_current_page
  357. self.get_pdf_page()
  358. finding = self.active_page.find_text(self.search_entry.get_text())
  359. self.selection_texts = [finding, 0]
  360. self.doc_viewer.queue_draw()
  361. self.scroll_focus_selected()
  362. def get_pdf_page(self):
  363. self.active_page = self.document.get_page(self.current_page)
  364. self.doc_width, self.doc_height = self.active_page.get_size()
  365. self.doc_viewer.set_size_request(self.doc_width*self.scale_factor, self.doc_height*self.scale_factor)
  366. self.doc_viewer.queue_draw()
  367. def draw_pdf_file(self, widget, cr):
  368. if self.document:
  369. cr.scale(self.scale_factor,self.scale_factor)
  370. cr.set_source_rgba(1, 1, 1, 1)
  371. cr.rectangle(0, 0, self.doc_width, self.doc_height)
  372. cr.fill()
  373. cr.set_source_rgba(0, 0, 0, 1)
  374. cr.rectangle(0, 0, self.doc_width, self.doc_height)
  375. cr.stroke()
  376. self.active_page.render_for_printing(cr)
  377. if self.selection:
  378. cr.set_source_rgba(0.5, 0.5, 0.5, 0.5)
  379. cr.rectangle(*self.calc_selection(self.selection))
  380. cr.fill()
  381. for s_text in self.selection_texts[0]:
  382. if s_text == self.selection_texts[0][self.selection_texts[1]]:
  383. cr.set_source_rgba(0.21, 0.68, 0.56, 0.5)
  384. else:
  385. cr.set_source_rgba(0.5, 0.5, 0.5, 0.5)
  386. cr.rectangle(*self.calc_selection([s_text.x1,self.doc_height-s_text.y1,s_text.x2,self.doc_height-s_text.y2],True))
  387. cr.fill()
  388. def calc_selection(self,selection,find=False):
  389. if selection[0] > selection[2]:
  390. start_x = selection[2]
  391. x_size = selection[0] - selection[2]
  392. else:
  393. start_x = selection[0]
  394. x_size = selection[2] - selection[0]
  395. if selection[1] > selection[3]:
  396. start_y = selection[3]
  397. y_size = selection[1] - selection[3]
  398. else:
  399. start_y = selection[1]
  400. y_size = selection[3] - selection[1]
  401. if find:
  402. return (start_x,start_y,x_size,y_size)
  403. else:
  404. return (start_x/self.scale_factor,start_y/self.scale_factor,x_size/self.scale_factor,y_size/self.scale_factor)
  405. apps = []
  406. def load_pdf_file(files):
  407. for f in files:
  408. f_type = os.path.splitext(f)
  409. if os.path.exists(f) and os.path.isfile(f) and f_type[-1] == ".pdf":
  410. app = MPdf()
  411. app.load_pdf_file(f)
  412. app.connect("delete-event", close_window)
  413. app.show_all()
  414. app.spinner.hide()
  415. apps.append(app)
  416. else:
  417. print("Dosya bulunamadı!")
  418. def close_window(win,x):
  419. apps.remove(win)
  420. if len(apps) == 0:
  421. Gtk.main_quit()
  422. if __name__ == '__main__':
  423. args = sys.argv
  424. if len(args) > 1:
  425. load_pdf_file(args[1:])
  426. else:
  427. app = MPdf()
  428. app.connect("delete-event", close_window)
  429. app.show_all()
  430. app.spinner.hide()
  431. apps.append(app)
  432. Gtk.main()