resimlik 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. #!/usr/bin/python3
  2. # -*- coding: utf-8 -*-
  3. import gi, sys, os, locale, cairo, subprocess
  4. gi.require_version("Gtk","3.0")
  5. from gi.repository import Gio, Gtk, GLib, GdkPixbuf, Gdk
  6. translate = {"tr":{0:"Açmak istediğiniz resimleri seçiniz.",
  7. 1:"Açmak istediğiniz dizini seçiniz.",
  8. 2:"Resim",
  9. 3:"{} dosyası okunamadı. Format desteklenmiyor.",
  10. 4:"PyGtk tabanlı basit resim gösterici.",
  11. 5:"Resim Dosyası Aç",
  12. 6:"Dizin Aç",
  13. 7:"Önceki Resim",
  14. 8:"Yakınlaş",
  15. 9:"Uzaklaş",
  16. 10:"90 Derece Döndür - Saat Yönü Tersi",
  17. 11:"90 Derece Döndür - Saat Yönü",
  18. 12:"Hakkında",
  19. 13:"Sonraki Resim",
  20. 14:"Yazdır",
  21. 15:"Tam Ekran",
  22. 16:"Resim Bilgisi",
  23. 17:"Resimi Diskten Siler",
  24. 18:"Resim Silinecek!",
  25. 19:"{} yolunda bulunan resim kalıcı olarak silinecek onaylıyor musunuz?",
  26. 20:"HATA",
  27. 21:"Resim Silinemedi"},
  28. "en":{0:"Select open images.",
  29. 1:"Select open directory..",
  30. 2:"Image",
  31. 3:"{} file cant open. Format not found.",
  32. 4:"PyGtk based simple image viewer.",
  33. 5:"Open Image File",
  34. 6:"Open Directory",
  35. 7:"Back Image",
  36. 8:"Zoom In",
  37. 9:"Zoom out",
  38. 10:"90 Rotate - Clock Counter",
  39. 11:"90 Rotate - Clock",
  40. 12:"About",
  41. 13:"Foward Image",
  42. 14:"Print",
  43. 15:"Full Screen",
  44. 16:"Image Info",
  45. 17:"Remove Image on Disk",
  46. 18:"Remove Image!",
  47. 19:"Do you confirm that the picture on the {} road will be deleted permanently?",
  48. 20:"ERROR",
  49. 21:"Image Could Not Be Deleted"}}
  50. l = locale.getdefaultlocale()
  51. l = l[0].split("_")[0]
  52. locales = list(translate.keys())
  53. if l not in locales:
  54. l = "en"
  55. _ = translate[l]
  56. class Resimlik(Gtk.Window):
  57. def __init__(self):
  58. super(Resimlik, self).__init__()
  59. self.images = []
  60. self.scale_factor = 1
  61. self.rotate_factor = 0
  62. self.is_full_screen = 0
  63. self.rotate_angels = {0:GdkPixbuf.PixbufRotation.NONE,
  64. 90:GdkPixbuf.PixbufRotation.COUNTERCLOCKWISE,
  65. 180:GdkPixbuf.PixbufRotation.UPSIDEDOWN,
  66. 270:GdkPixbuf.PixbufRotation.CLOCKWISE}
  67. self.h_bar = Gtk.HeaderBar()
  68. self.h_bar.set_title("Resimlik")
  69. self.set_titlebar(self.h_bar)
  70. self.h_bar.set_show_close_button(True)
  71. #Gtk.STOCK_PRINT
  72. self.print_button = Gtk.ToolButton()
  73. self.print_button.connect("clicked",self.print_button_show)
  74. self.print_button.set_property("has-tooltip", True)
  75. self.print_button.connect("query-tooltip", self.get_query_tooltip,_[14])
  76. self.print_button.set_stock_id(Gtk.STOCK_PRINT)
  77. self.print_button.set_sensitive(False)
  78. self.h_bar.pack_end(self.print_button)
  79. self.about_button = Gtk.ToolButton()
  80. self.about_button.connect("clicked",self.about_button_show)
  81. self.about_button.set_property("has-tooltip", True)
  82. self.about_button.connect("query-tooltip", self.get_query_tooltip,_[12])
  83. self.about_button.set_stock_id(Gtk.STOCK_ABOUT)
  84. self.h_bar.pack_end(self.about_button)
  85. self.open_img_folder_button = Gtk.ToolButton()
  86. self.open_img_folder_button.set_stock_id(Gtk.STOCK_DIRECTORY)
  87. self.open_img_folder_button.connect("clicked", self.open_image_dir)
  88. self.open_img_folder_button.set_property("has-tooltip", True)
  89. self.open_img_folder_button.connect("query-tooltip", self.get_query_tooltip,_[6])
  90. self.h_bar.pack_end(self.open_img_folder_button)
  91. self.open_img_button = Gtk.ToolButton()
  92. self.open_img_button.set_stock_id(Gtk.STOCK_OPEN)
  93. self.open_img_button.connect("clicked", self.open_image)
  94. self.open_img_button.set_property("has-tooltip", True)
  95. self.open_img_button.connect("query-tooltip", self.get_query_tooltip,_[5])
  96. self.h_bar.pack_end(self.open_img_button)
  97. self.back_button = Gtk.ToolButton()
  98. self.back_button.connect("clicked",self.go_back_image)
  99. self.back_button.set_property("has-tooltip", True)
  100. self.back_button.connect("query-tooltip", self.get_query_tooltip,_[7])
  101. self.back_button.set_stock_id(Gtk.STOCK_GO_BACK)
  102. self.back_button.set_sensitive(False)
  103. self.h_bar.pack_start(self.back_button)
  104. self.zoom_in_button = Gtk.ToolButton()
  105. self.zoom_in_button.connect("clicked",self.zoom_in)
  106. self.zoom_in_button.set_property("has-tooltip", True)
  107. self.zoom_in_button.connect("query-tooltip", self.get_query_tooltip,_[8])
  108. self.zoom_in_button.set_stock_id(Gtk.STOCK_ZOOM_IN)
  109. self.zoom_in_button.set_sensitive(False)
  110. self.h_bar.pack_start(self.zoom_in_button)
  111. self.zoom_out_button = Gtk.ToolButton()
  112. self.zoom_out_button.connect("clicked",self.zoom_out)
  113. self.zoom_out_button.set_property("has-tooltip", True)
  114. self.zoom_out_button.connect("query-tooltip", self.get_query_tooltip,_[9])
  115. self.zoom_out_button.set_sensitive(False)
  116. self.zoom_out_button.set_stock_id(Gtk.STOCK_ZOOM_OUT)
  117. self.h_bar.pack_start(self.zoom_out_button)
  118. self.rotate_clock_counter_button = Gtk.ToolButton()
  119. self.rotate_clock_counter_button.connect("clicked",self.rotate_clock_counter)
  120. self.rotate_clock_counter_button.set_property("has-tooltip", True)
  121. self.rotate_clock_counter_button.connect("query-tooltip", self.get_query_tooltip,_[10])
  122. self.rotate_clock_counter_button.set_stock_id(Gtk.STOCK_UNDO)
  123. self.rotate_clock_counter_button.set_sensitive(False)
  124. self.h_bar.pack_start(self.rotate_clock_counter_button)
  125. self.rotate_clock_button = Gtk.ToolButton()
  126. self.rotate_clock_button.connect("clicked",self.rotate_clock)
  127. self.rotate_clock_button.set_property("has-tooltip", True)
  128. self.rotate_clock_button.connect("query-tooltip", self.get_query_tooltip,_[11])
  129. self.rotate_clock_button.set_stock_id(Gtk.STOCK_REDO)
  130. self.rotate_clock_button.set_sensitive(False)
  131. self.h_bar.pack_start(self.rotate_clock_button)
  132. self.foward_button = Gtk.ToolButton()
  133. self.foward_button.connect("clicked",self.go_foward_image)
  134. self.foward_button.set_property("has-tooltip", True)
  135. self.foward_button.connect("query-tooltip", self.get_query_tooltip,_[13])
  136. self.foward_button.set_stock_id(Gtk.STOCK_GO_FORWARD)
  137. self.foward_button.set_sensitive(False)
  138. self.h_bar.pack_start(self.foward_button)
  139. self.img_info_button = Gtk.ToolButton()
  140. self.img_info_button.connect("clicked",self.view_image_info)
  141. self.img_info_button.set_property("has-tooltip", True)
  142. self.img_info_button.connect("query-tooltip", self.get_query_tooltip,_[16])
  143. self.img_info_button.set_stock_id(Gtk.STOCK_INFO)
  144. self.img_info_button.set_sensitive(False)
  145. self.h_bar.pack_start(self.img_info_button)
  146. self.fs_button = Gtk.ToolButton()
  147. self.fs_button.connect("clicked",self.set_fs_resimlik)
  148. self.fs_button.set_property("has-tooltip", True)
  149. self.fs_button.connect("query-tooltip", self.get_query_tooltip,_[15])
  150. self.fs_button.set_stock_id(Gtk.STOCK_FULLSCREEN )
  151. self.h_bar.pack_start(self.fs_button)
  152. self.delete_image_button = Gtk.ToolButton()
  153. self.delete_image_button.connect("clicked",self.delete_image)
  154. self.delete_image_button.set_property("has-tooltip", True)
  155. self.delete_image_button.connect("query-tooltip", self.get_query_tooltip,_[17])
  156. self.delete_image_button.set_stock_id(Gtk.STOCK_REMOVE)
  157. self.delete_image_button.set_sensitive(False)
  158. self.h_bar.pack_start(self.delete_image_button)
  159. scroll = Gtk.ScrolledWindow()
  160. self.add(scroll)
  161. scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
  162. self.image_viewer = Gtk.Image()
  163. scroll.add(self.image_viewer)
  164. enforce_target = Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags(4), 129)
  165. self.drag_dest_set(Gtk.DestDefaults.ALL, [enforce_target], Gdk.DragAction.COPY)
  166. self.connect('size-allocate', self.size_changed)
  167. self.connect('key-press-event',self.key_press)
  168. self.connect("drag-data-received", self.on_drag_data_received)
  169. self.set_default_size(640,480)
  170. self.timer = False
  171. self.width, self.height = self.get_size()
  172. self.active_pixbuf_default_size = []
  173. def delete_image(self, widget):
  174. rm_image = self.images[0]
  175. q = Gtk.MessageDialog(self,0,Gtk.MessageType.QUESTION, Gtk.ButtonsType.OK_CANCEL,_[18])
  176. q.format_secondary_text(_[19].format(rm_image))
  177. ans = q.run()
  178. if ans == Gtk.ResponseType.OK:
  179. q.destroy()
  180. try:
  181. subprocess.Popen(["rm",self.images[0]])
  182. self.images.pop(0)
  183. if len(self.images) == 0:
  184. self.print_button.set_sensitive(False)
  185. self.zoom_in_button.set_sensitive(False)
  186. self.zoom_out_button.set_sensitive(False)
  187. self.rotate_clock_button.set_sensitive(False)
  188. self.img_info_button.set_sensitive(False)
  189. self.rotate_clock_counter_button.set_sensitive(False)
  190. self.delete_image_button.set_sensitive(False)
  191. self.foward_button.set_sensitive(False)
  192. self.back_button.set_sensitive(False)
  193. self.view_images()
  194. except:
  195. dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, _[20])
  196. dialog.format_secondary_text(_[21])
  197. dialog.run()
  198. dialog.destroy()
  199. else:
  200. q.destroy()
  201. def get_query_tooltip(self, widget, x, y, keyboard_mode, tooltip, text):
  202. tooltip.set_text(text)
  203. return True
  204. def print_button_show(self, widget):
  205. pd = Gtk.PrintOperation()
  206. pd.set_n_pages(1)
  207. pd.connect("draw_page",self.draw_page)
  208. result = pd.run(Gtk.PrintOperationAction.PRINT_DIALOG, self)
  209. def draw_page(self, operation=None, context=None, page_nr=None):
  210. ctx = context.get_cairo_context()
  211. a_pf = self.image_viewer.get_pixbuf()
  212. if a_pf != None:
  213. Gdk.cairo_set_source_pixbuf(ctx, a_pf,0,0)
  214. ctx.paint()
  215. def set_fs_resimlik(self, widget):
  216. if self.is_full_screen:
  217. self.is_full_screen = 0
  218. self.unfullscreen()
  219. else:
  220. self.is_full_screen = 1
  221. self.fullscreen()
  222. def about_button_show(self, widget):
  223. about = Gtk.AboutDialog()
  224. about.set_program_name("Resimlik")
  225. about.set_version("1.0")
  226. about.set_logo_icon_name("multimedia-photo-viewer")
  227. about.set_authors(["SonAkinci41"])
  228. about.set_comments(_[4])
  229. about.set_copyright("(c) 2021 Fatih Kaya <sonakinci41@gmail.com>")
  230. about.set_license(" GPL-3.0 License ")
  231. about.set_website("https://mls.akdeniz.edu.tr/git/sonakinci41/Resimlik")
  232. about.run()
  233. about.destroy()
  234. def open_image(self,widget):
  235. dialog = Gtk.FileChooserDialog(_[0], self, Gtk.FileChooserAction.OPEN,
  236. (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
  237. filter_ = Gtk.FileFilter()
  238. filter_.set_name(_[2])
  239. filter_.add_mime_type("image/*")
  240. dialog.add_filter(filter_)
  241. return_dialog = dialog.run()
  242. if return_dialog == Gtk.ResponseType.OK:
  243. self.get_images([dialog.get_filename()])
  244. dialog.destroy()
  245. def open_image_dir(self,widget):
  246. dialog = Gtk.FileChooserDialog(_[1], self, Gtk.FileChooserAction.SELECT_FOLDER,
  247. (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
  248. return_dialog = dialog.run()
  249. if return_dialog == Gtk.ResponseType.OK:
  250. self.get_images([dialog.get_filename()])
  251. dialog.destroy()
  252. def on_drag_data_received(self, widget, drag_context, x, y, data, info, time):
  253. text = data.get_text()
  254. text = text.split("\n")
  255. text.remove("")
  256. imgs = []
  257. for t in text:
  258. t = t.replace("file://","")
  259. imgs.append(t)
  260. self.get_images(imgs)
  261. def key_press(self,widget,event):
  262. keyname = Gdk.keyval_name(event.keyval)
  263. if keyname == "plus" or keyname == "KP_Add":
  264. self.zoom_in(None)
  265. elif keyname == "minus" or keyname == "KP_Subtract":
  266. self.zoom_out(None)
  267. elif keyname == "Right" or keyname == "Up":
  268. if len(self.images) > 1:
  269. self.go_foward_image(None)
  270. elif keyname == "Left" or keyname == "Down":
  271. if len(self.images) > 1:
  272. self.go_back_image(None)
  273. elif keyname == "Escape":
  274. if self.is_full_screen:
  275. self.is_full_screen = 0
  276. self.unfullscreen()
  277. else:
  278. self.destroy()
  279. if keyname == "r":
  280. self.rotate_clock(None)
  281. elif keyname == "R":
  282. self.rotate_clock_counter(None)
  283. def rotate_clock_counter(self,widget):
  284. self.rotate_factor += 90
  285. if self.rotate_factor > 270:
  286. self.rotate_factor = 0
  287. self.view_images()
  288. def rotate_clock(self,widget):
  289. self.rotate_factor -= 90
  290. if self.rotate_factor < 0:
  291. self.rotate_factor = 270
  292. self.view_images()
  293. def refresh_ui(self):
  294. self.scale_factor = 1
  295. self.rotate_factor = 0
  296. self.zoom_in_button.set_sensitive(True)
  297. self.zoom_out_button.set_sensitive(True)
  298. def zoom_in(self, widget):
  299. if self.scale_factor < 1.9:
  300. self.scale_factor += 0.1
  301. self.view_images()
  302. if self.scale_factor == 2:
  303. self.zoom_in_button.set_sensitive(False)
  304. def zoom_out(self,widget):
  305. if self.scale_factor > 0.2:
  306. self.scale_factor -= 0.1
  307. self.view_images()
  308. if self.scale_factor == 0.1:
  309. self.zoom_out_button.set_sensitive(False)
  310. def go_foward_image(self,widget):
  311. f = self.images[0]
  312. self.images.remove(f)
  313. self.images.append(f)
  314. self.refresh_ui()
  315. self.view_images()
  316. def go_back_image(self,widget):
  317. f = self.images[0]
  318. l = self.images[-1]
  319. self.images.remove(f)
  320. self.images.remove(l)
  321. self.images.insert(0,f)
  322. self.images.insert(0,l)
  323. self.refresh_ui()
  324. self.view_images()
  325. def size_changed(self, widget, alloc):
  326. w, h = self.get_size()
  327. if w != self.width or h != self.height:
  328. self.width = w
  329. self.height = h
  330. self.view_images()
  331. def get_file_info(self,url):
  332. g_file = Gio.File.new_for_path(url)
  333. info = g_file.query_info("standard::*",Gio.FileQueryInfoFlags.NONE,None)
  334. c_type = info.get_content_type()
  335. c_type = c_type.split("/")
  336. if "image" in c_type:
  337. return True
  338. else:
  339. return False
  340. def get_pixbuf_screen_size(self,w,h):
  341. self.active_pixbuf_default_size = [w,h]
  342. ws = self.width / w
  343. hs = self.height / h
  344. if ws > hs:
  345. return (hs*w,hs*h)
  346. else:
  347. return (ws*w,ws*h)
  348. def view_image_info(self, widget):
  349. if self.images != []:
  350. g_file = Gio.File.new_for_path(self.images[0])
  351. info = g_file.query_info("standard::*",Gio.FileQueryInfoFlags.NONE,None)
  352. size = info.get_size()
  353. if size < 1024:
  354. size = str(size) + " bytes"
  355. elif 1024 < size < 1024**2:
  356. size = str(round(size/1024,2)) + " KB"
  357. else:
  358. size = str(round(size/1024**2,2)) + " MB"
  359. c_type = info.get_content_type()
  360. v_image_inf = Gtk.Popover()
  361. box = Gtk.Box()
  362. info_label = Gtk.Label()
  363. info_label.set_text("{}x{} px\n{}\n{}".format(*self.active_pixbuf_default_size,size,c_type))
  364. box.pack_start(info_label,1,1,10)
  365. v_image_inf.add(box)
  366. v_image_inf.set_position(Gtk.PositionType.BOTTOM)
  367. v_image_inf.set_relative_to(widget)
  368. v_image_inf.show_all()
  369. v_image_inf.popup()
  370. def view_images(self):
  371. if self.timer:
  372. GLib.source_remove(self.timer)
  373. self.timer = False
  374. try:
  375. self.active_pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(self.images[0],
  376. int(self.width*self.scale_factor),
  377. int(self.height*self.scale_factor),
  378. True)
  379. self.active_pixbuf = self.active_pixbuf.rotate_simple(self.rotate_angels[self.rotate_factor])
  380. self.image_viewer.set_from_pixbuf(self.active_pixbuf)
  381. self.h_bar.set_title(self.images[0])
  382. apb = GdkPixbuf.Pixbuf.new_from_file(self.images[0])
  383. self.active_pixbuf_default_size = [apb.get_width(),apb.get_height()]
  384. except:
  385. try:
  386. self.active_pixbuf = GdkPixbuf.PixbufAnimation.new_from_file(self.images[0])
  387. if self.active_pixbuf.is_static_image():
  388. self.active_pixbuf = self.active_pixbuf.get_static_image()
  389. w,h = self.get_pixbuf_screen_size(self.active_pixbuf.get_width(),self.active_pixbuf.get_height())
  390. self.active_pixbuf.scale_simple(int(w*self.scale_factor),
  391. int(h*self.scale_factor),
  392. True)
  393. self.active_pixbuf = self.active_pixbuf.rotate_simple(self.rotate_angels[self.rotate_factor])
  394. self.image_viewer.set_from_pixbuf(self.active_pixbuf)
  395. else:
  396. iter_ = self.active_pixbuf.get_iter(GLib.TimeVal())
  397. self.timer = GLib.timeout_add(iter_.get_delay_time(),self.view_gif_animation,iter_)
  398. self.h_bar.set_title(self.images[0])
  399. except:
  400. if len(self.images) == 0:
  401. pass
  402. else:
  403. dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, _[20])
  404. dialog.format_secondary_text(_[3].format(self.images[0]))
  405. self.images.pop(0)
  406. dialog.run()
  407. dialog.destroy()
  408. def view_gif_animation(self,iter_):
  409. iter_.advance()
  410. pb = iter_.get_pixbuf()
  411. w,h = self.get_pixbuf_screen_size(pb.get_width(),pb.get_height())
  412. pb = pb.scale_simple(int(w*self.scale_factor),
  413. int(h*self.scale_factor),
  414. True)
  415. pb = pb.rotate_simple(self.rotate_angels[self.rotate_factor])
  416. self.image_viewer.set_from_pixbuf(pb)
  417. return True
  418. def get_images(self, paths):
  419. self.images = []
  420. for path in paths:
  421. if not os.path.exists(path):
  422. continue
  423. if os.path.isfile(path):
  424. dir_, select_ = os.path.split(path)
  425. else:
  426. select_ = False
  427. dir_ = path
  428. dir_items = os.listdir(dir_)
  429. dir_items.sort()
  430. for d in dir_items:
  431. path = os.path.join(dir_,d)
  432. info = self.get_file_info(path)
  433. if info:
  434. if select_ and d == select_:
  435. self.images.insert(0,path)
  436. else:
  437. self.images.append(path)
  438. if len(self.images) < 2:
  439. self.foward_button.set_sensitive(False)
  440. self.back_button.set_sensitive(False)
  441. else:
  442. self.foward_button.set_sensitive(True)
  443. self.back_button.set_sensitive(True)
  444. if len(self.images) > 0:
  445. self.print_button.set_sensitive(True)
  446. self.zoom_in_button.set_sensitive(True)
  447. self.zoom_out_button.set_sensitive(True)
  448. self.rotate_clock_button.set_sensitive(True)
  449. self.img_info_button.set_sensitive(True)
  450. self.rotate_clock_counter_button.set_sensitive(True)
  451. self.delete_image_button.set_sensitive(True)
  452. self.view_images()
  453. if __name__ == '__main__':
  454. app = Resimlik()
  455. args = sys.argv
  456. if "resimlik" in args:
  457. args.remove("resimlik")
  458. if len(args) != 0:
  459. app.get_images(args)
  460. app.connect("destroy", Gtk.main_quit)
  461. app.show_all()
  462. Gtk.main()