Vous n'êtes pas identifié(e).
Introduction
1 / Echec de dpkg-repack sous KissOs-7.0
2 / téléchargement du paquet cyclope (pour debian) depuis le dépôt handylinux
3 / Création d'un dossier de travail
4 / Echec de l’utilisation du paquet alien pour transformer le paquet cyclope (pour debian) en paquet pour fedora
5 / Procédure d’extraction du paquet cyclope (pour debian)
6 / Lancement du script python dans l’environnement linux (cela marche également quelque soit l’unix utilisé, linux, BSD ...)
7 / Manuel d’utilisation du script cyclope
8 / Script cyclope à lancer avec python
Conclusion
Sources
Il s’agit ici non seulement de vous présenter le paquet cyclope, visionneuse photo ultra-légère, conçu par Thuban) mais encore de vous permettre de l’utiliser sur n’importe quelle système unix [linux (Arch, debian, fedora, gentoo, void, …) ou BSD (Net, Open …) et que sais-je encore !
Ma plate-forme de travail a autant été :
- un acer aspire 9410 sous KissOs-0.7 mono-boot :
- un lenovo G50-45 UEFI SECURE BOOT sous Viperr Fedora remix 9 fc 26, dopée aux kickstarts fedora labs (https://github.com/SamsungARTIK/fedora-spin-kickstarts). D’abord dual boot avec Windows 8/10, puis mono boot (mais toujours UEFI SECURE BOOT!) car j’en avais marre des mises à jour longues de Windows dont je ne me sers plus à la maison depuis 2010 environ.
stevie@kiss0s ~
$ dpkg-repack cyclope
dpkg-repack: Fatal Error: This program should be run as root (or you could use fakeroot -u). Aborting.
stevie@kiss0s ~
$ fakeroot -u
bash: fakeroot : commande introuvable
stevie@kiss0s ~
$ sudo apt-get -y install fakeroot
[sudo] Mot de passe de stevie :
Lecture des listes de paquets... Fait
Construction de l'arbre des dépendances
Lecture des informations d'état... Fait
The following additional packages will be installed:
libfakeroot
Les NOUVEAUX paquets suivants seront installés :
fakeroot libfakeroot
0 mis à jour, 2 nouvellement installés, 0 à enlever et 1 non mis à jour.
Il est nécessaire de prendre 134 ko dans les archives.
Après cette opération, 369 ko d'espace disque supplémentaires seront utilisés.
Réception de:1 http://deb.debian.org/debian stretch/main i386 libfakeroot i386 1.21-3.1 [46,8 kB]
Réception de:2 http://deb.debian.org/debian stretch/main i386 fakeroot i386 1.21-3.1 [86,8 kB]
134 ko réceptionnés en 0s (231 ko/s)
Sélection du paquet libfakeroot:i386 précédemment désélectionné.
(Lecture de la base de données... 80611 fichiers et répertoires déjà installés.)
Préparation du dépaquetage de .../libfakeroot_1.21-3.1_i386.deb ...
Dépaquetage de libfakeroot:i386 (1.21-3.1) ...
Sélection du paquet fakeroot précédemment désélectionné.
Préparation du dépaquetage de .../fakeroot_1.21-3.1_i386.deb ...
Dépaquetage de fakeroot (1.21-3.1) ...
Traitement des actions différées (« triggers ») pour libc-bin (2.24-11+deb9u1) ...
Paramétrage de libfakeroot:i386 (1.21-3.1) ...
Traitement des actions différées (« triggers ») pour man-db (2.7.6.1-2) ...
Paramétrage de fakeroot (1.21-3.1) ...
update-alternatives: utilisation de « /usr/bin/fakeroot-sysv » pour fournir « /usr/bin/fakeroot » (fakeroot) en mode automatique
Traitement des actions différées (« triggers ») pour libc-bin (2.24-11+deb9u1) ...
stevie@kiss0s ~
$ fakeroot -u
root@kiss0s ~
$ sudo dpkg-repack cyclope
ERROR: ld.so: object 'libfakeroot-sysv.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
dpkg-query: le paquet « cyclope » n'est pas installé et aucune information n'est disponible
Utilisez dpkg --info (= dpkg-deb --info) pour examiner les fichiers
archives, et dpkg --contents (= dpkg-deb --contents) pour afficher leur
contenu.
Use of uninitialized value in pattern match (m//) at /usr/bin/dpkg-repack line 138.
Use of uninitialized value in concatenation (.) or string at /usr/bin/dpkg-repack line 139.
dpkg-repack: Fatal Error: Package cyclope not fully installed:
root@kiss0s ~
$ exit
exit
stevie@kiss0s ~
$ fakeroot -u
root@kiss0s ~
$ dpkg-repack cyclope
dpkg-query: le paquet « cyclope » n'est pas installé et aucune information n'est disponible
Utilisez dpkg --info (= dpkg-deb --info) pour examiner les fichiers
archives, et dpkg --contents (= dpkg-deb --contents) pour afficher leur
contenu.
Use of uninitialized value in pattern match (m//) at /usr/bin/dpkg-repack line 138.
Use of uninitialized value in concatenation (.) or string at /usr/bin/dpkg-repack line 139.
dpkg-repack: Fatal Error: Package cyclope not fully installed:
root@kiss0s ~
$
En partant du sources.list d'Handylinux (http://repo.handylinux.org/handylinux.list) :
## HandyLinux v1 ##
deb http://handylinux.org/repo/debian stable main
#deb-src http://handylinux.org/repo/debian stable main
## HandyLinux v1 Compiz ##
deb http://handylinux.org/repo/debian compiz main
#deb-src http://handylinux.org/repo/debian compiz main
## HandyLinux v2 Jessie ##
deb http://handylinux.org/repo/debian jessie main
#deb-src http://handylinux.org/repo/debian jessie main
## HandyLinux Testing ##
deb http://handylinux.org/repo/debian testing main
#deb-src http://handylinux.org/repo/debian testing main
=> Extraire la "bonne adresse", soit "http://handylinux.org/repo/debian/".
Nous obtenons ceci :
Index of /repo/debian
Icon Name Last modified Size Description[DIR] Parent Directory -
[DIR] conf/ 06-Jun-2017 18:58 -
[DIR] db/ 06-Jun-2017 18:58 -
[DIR] dists/ 06-Jun-2017 18:58 -
[DIR] lists/ 06-Jun-2017 18:58 -
[DIR] pool/ 06-Jun-2017 18:58
=> Se rendre dans le dossier "pool" :
=> Naviguer dans le dépôt jusqu'à l'url "http://handylinux.org/repo/debian/pool/main/c/"
Index of /repo/debian/pool/main/c
Icon Name Last modified Size Description[DIR] Parent Directory -
[DIR] ccsm/ 06-Jun-2017 18:59 -
[DIR] compiz-deskmenu/ 06-Jun-2017 18:59 -
[DIR] compiz-fusion-plugin..> 06-Jun-2017 19:02 -
[DIR] compiz-fusion-plugin..> 06-Jun-2017 19:00 -
[DIR] compiz/ 06-Jun-2017 19:01 -
[DIR] compizconfig-python/ 06-Jun-2017 18:59 -
[DIR] copcoll/ 06-Jun-2017 18:59 -
[DIR] cyclope/ 06-Jun-2017 19:01
=> Entrer dans cyclope : url "http://handylinux.org/repo/debian/pool/main/c/cyclope"
Index of /repo/debian/pool/main/c/cyclope
Icon Name Last modified Size Description[DIR] Parent Directory -
[ ] cyclope_1.5-5.debian..> 06-Jun-2017 19:01 5.1K
[TXT] cyclope_1.5-5.dsc 06-Jun-2017 19:01 841
[ ] cyclope_1.5-5_all.deb 06-Jun-2017 19:01 20K
[ ] cyclope_1.5.orig.tar.xz 06-Jun-2017 19:01 201K
$ mkdir /home/$user/CYCLOPE
=> Télécharger le fichier "cyclope_1.5-5_all.deb" par un clic droit souris
stevie ~ CYCLOPE dir
cyclope_1.5-5_all.deb
stevie ~ CYCLOPE ls
cyclope_1.5-5_all.deb
=> les commandes ls et dir fonctionnent sous debian et sous fedora pour déterminer le contenu d'un dossier.
stevie ~ CYCLOPE su
Mot de passe :
[root@Host-002 CYCLOPE]# alien -r *.deb
cyclope-1.5-6.noarch.rpm generated
[root@Host-002 CYCLOPE]# rpm -ivh *.rpm
Préparation... ################################# [100%]
le fichier /usr/bin de l'installation de cyclope-1.5-6.noarch entre en conflit avec le fichier du paquet viperr-obkey-8.0-viperr.fc24.noarch
le fichier /usr/bin de l'installation de cyclope-1.5-6.noarch entre en conflit avec le fichier du paquet viperrconf-9.7-viperr.fc24.noarch
le fichier /usr/bin de l'installation de cyclope-1.5-6.noarch entre en conflit avec le fichier du paquet viperr-conposite-8.0-viperr.fc24.noarch
le fichier / de l'installation de cyclope-1.5-6.noarch entre en conflit avec le fichier du paquet filesystem-3.2-40.fc26.x86_64
le fichier /usr/bin de l'installation de cyclope-1.5-6.noarch entre en conflit avec le fichier du paquet filesystem-3.2-40.fc26.x86_64
=> Le paquet cyclope alienisé en version fedora entre en conflit avec plusieurs paquets fedora. Il ne peut donc être utilisé tel quel.
=> vous noterez que alien rajoute un numéro à cyclope en le convertissant de debian (cyclope_1.5-5_all.deb) à fedora (cyclope-1.5-6.noarch.rpm)
Vérification si ce paquet aurait été toutefois installé :
[root@Host-002 CYCLOPE]# rpm -e *.rpm
erreur : le paquet cyclope-1.5-6.noarch.rpm n'est pas installé
=> Le paquet cyclope ne peut être désintallé, puisqu'il n'a pas été installé.
[root@Host-002 CYCLOPE]# exit
Si tout est script dans unix, et si linux est un unix qui s'ignore, alors il reste la solution d'utiliser cyclope comme un simple script python, plutôt que comme un paquet en bonne et due forme malheureusement conflictuel.
L'idée est donc de suivre la procédure classique d'extraction d'un paquet deb
stevie ~ CYCLOPE ar xv *.deb
x - debian-binary
x - control.tar.gz
x – data.tar.xz
=> Il en résulte trois fichiers dénommés debian-binary, control.tar.gz et data.tar.xz, soit :
Dépaquetage un paquet *.deb
$ ar xv *.deb
Cela nous fournit 3 fichiers:
- debian-binary : fichier indiquant la version du paquet deb, soit 2.0, très différent de 1.5.5 affiché en dénomination du paquet ...
- data.tar.xz : fichier compressé contenant le code de cyclope,
- control.tar.gz : fichier compressé de contrôl.
A ce stade, il convient de procéder au désossage de chaque sous-fichier :
$ tar xvf control.tar.gz
stevie ~ CYCLOPE tar xvf control.tar.gz
./
./control
./md5sums
=> le fichier md5sums permet de vérifier l'intégrité de l'archive.
=> Ici, pas de fichier de configuration, sauf s'il a disparu en cours de route …
En naviguant dans le système avec le gestionnaire de fichier « ranger », le contenu du fichier « control » apparait alors :
Package: cyclope
Version: 1.5-5
Architecture: all
Maintainer: arnault perret <arpinux@member.fsf.org>
Installed-Size: 99
Depends: python (>= 2.7), python-gtk2
Section: x11
Priority: optional
Homepage: https://handylinux.org/wiki/doku.php/fr/media#cyclope
Description: Une visionneuse d'images minimale.
Cyclope vous permet de visionner, pivoter ou zoomer
vos images simplement.
Vous pouvez aussi lancer un diaporama ou envoyer vos
images vers d'autres applications.
.
C'est la visionneuse rapide du bureau HandyLinux.
~
~
~
"~/CYCLOPE/control" 16L, 524C
=> Notons les dépendances python (>= 2.7) et python-gtk2 !
Et oui, cyclope participe d'Handylinux ! Mais également de KissOs-7.0 !
Décompression du fichier « data.tar.xz »
$ tar xvf data.tar.xz
Résultat :
stevie ~ CYCLOPE tar xvf data.tar.xz
./
./usr/
./usr/share/
./usr/share/doc/
./usr/share/doc/cyclope/
./usr/share/doc/cyclope/changelog.Debian.gz
./usr/share/doc/cyclope/copyright
./usr/share/man/
./usr/share/man/man1/
./usr/share/man/man1/cyclope.1.gz
./usr/share/locale/
./usr/share/locale/en/
./usr/share/locale/en/LC_MESSAGES/
./usr/share/locale/en/LC_MESSAGES/cyclope.mo
./usr/share/locale/fr/
./usr/share/locale/fr/LC_MESSAGES/
./usr/share/locale/fr/LC_MESSAGES/cyclope.mo
./usr/share/applications/
./usr/share/applications/cyclope.desktop
./usr/share/pixmaps/
./usr/share/pixmaps/cyclope_icon.png
./usr/bin/
./usr/bin/cyclope
En gros : un dossier usr, qui contient lui-même deux sous-dossiers bin et share :
Le sous-dossier share comprend à son tour 5 sous-dossiers :
- pixmaps, icone du paquet
- locale, usage du paquet en langue française et anglaise
- man, manpage
- doc,
* changelog,
=>
* copyright :
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: cyclope
Files: *
Copyright: 2012 mickyz
2015 Xavier Cartron <thuban@yeuxdelibad.net>
2015 arpinux <arpinux@member.fsf.org>
License: GPL-3+
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
.
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
- applications,
fichier cyclope-desktop :
[Desktop Entry]
Name=Cyclope
Comment=Minimalist image viewer
Comment[fr]=Visionneuse d'images minimaliste
Exec=/usr/bin/cyclope
Icon=cyclope_icon
StartupNotify=true
Terminal=false
Type=Application
Categories=GTK;Graphics;Viewer;
Le sous-dossier bin comprend à son tour 1 seul fichier dénommé cyclope, constitué par un script python qui va nous intéresser désormais.
Il nous reste donc à lancer le script python dans un environnement linux :
Après avoir installé les dépendances vues plus hauts python (>= 2.7) et python-gtk2, exécuter le script comme suit :
$ python cyclope # soit python nom_du_script_python_à_lancer
=> chez moi, cela donne cela :
stevie ~ cd /home/stevie/CYCLOPE/CYCLOPE-TRAVAIL/usr/bin/
stevie … CYCLOPE-TRAVAIL usr bin dir
cyclope
stevie … CYCLOPE-TRAVAIL usr bin python cyclope
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:88: Incapable de localiser le fichier image dans le chemin des pixmaps : « assets/combo-entry-border.png »
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:92: Background image options specified without filename
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:98: Incapable de localiser le fichier image dans le chemin des pixmaps : « assets/combo-entry-border-focus.png »
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:102: Background image options specified without filename
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:109: Incapable de localiser le fichier image dans le chemin des pixmaps : « assets/combo-entry-border-rtl.png »
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:113: Background image options specified without filename
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:119: Incapable de localiser le fichier image dans le chemin des pixmaps : « assets/combo-entry-border-focus-rtl.png »
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:123: Background image options specified without filename
/usr/share/themes/Arc-REDemption/gtk-2.0/xfce-notify.rc:1: error: unexpected character '\', expected keyword - e.g. `style'
Une fenêtre de choix de fichiers images s'ouvre alors et permet de choisir les fichiers images à visionner. Il convient de naviguer sur le disque dur, car cyclope s'ouvrira sur le dossier de localisation du script !
Manuel raccourci de l'utilisation de cyclope :
Le menu clic-droit souris de cyclope propose plusieurs entrées (items) :
***
- ouvrir
- tourner côté droit,
- tourner côté gauche
- zoom,
- enclencher le défilement des photos,
- traiter l'image avec Gimp, logiciel reconnu par cyclope comme installé dans le système
- Traiter l'image avec Shotwell, logiciel reconnu par cyclope comme installé dans le système
- Aide :
cyclope
version : 1.5
author : Thuban
licence : GPLv3
homepage : https://handylinux.org
---
usage : # utilisation :
Use arrows, b and n keys to change image # utiliser les flèches ou les touches b et n pour faire défiler les images
Double click or press f key to enlarge the window # Double cliquer ou appuyer la lettre « f » pour augmenter la taille de l’image
Press o to open a new image # utiliser la touche o pour ouvrir une image
Press d or g to turn the image # utiliser les touches d ou g pour faire pivoter l'image
Press z to toggle zoom mode # Appuyer la lettre « z » pour zoomer
Press = to restore the image # utiliser la touche z pour passer en mode zoom : sélectionner alors une zone avec votre curseur, le zoom sera lancé une fois le clic laché
Press p to start slideshow mode # utiliser la touche p pour lancer ou stopper le diaporama
Press m or right click to show the menu # utiliser la touche m ou le clic-droit pour afficher le menu
Press left click to show the menu # maintenir le clic-gauche pour déplacer la fenêtre
Press Escape or q to quit # utiliser ESC ou q pour quitter
=> Chez moi, cela fonctionne parfaitement.
=> Cette aide s’avère légèrement modifier quant à la version originale. En effet, la ligne « Press left click to show the menu # maintenir le clic-gauche pour déplacer la fenêtre » a été rajouté, afin de paralléliser le fichier d’aide avec le fichier cyclope.1.gz
=> Dans le cas où vous ne sachiez pas configurer un paquet, ne modifiez rien, laissez tout comme cela …
=> La traduction française n’est de moi mais de Thuban à copié à partir du fichier cyclope.1.gz décompressable à l’adresse /home/$user/…/ usr/share/man/man1/ soit :
.TH CYCLOPE 1 "Sept, 08 2015"
.SH NAME
cyclope \- une visionneuse d'images par thuban
.SH DESCRIPTION
.B cyclope
est une visionneuse d'image en python ultra-légère
.br
.SH USAGE
utiliser les flèches ou les touches b et n pour faire défiler les images
.br
utiliser la touche o pour ouvrir une image
.br
utiliser la touche p pour lancer ou stopper le diaporama
.br
utiliser la touche m ou le clic-droit pour afficher le menu
.br
utiliser la touche f ou le double-clic pour dés/activer le plein-écran.
.br
utiliser les touches d ou g pour faire pivoter l'image
.br
utiliser la touche z pour passer en mode zoom : sélectionner alors une zone avec votre curseur, le zoom sera lancé une fois le clic laché.
.br
utiliser la touche = pour quitter le mode zoom
.br
maintenir le clic-gauche pour déplacer la fenêtre
.br
utiliser ESC ou q pour quitter.
.br
.TH cyclope
- fermer
Pour installer le script cyclope dans votre système, il existe deux solutions s’offre à l’utilisateur :
- soit créer son propre paquet cyclope *.rpm car celui-ci n’existe pas encore,
- soit installer le script et se contenter de le rendre opérationnel, sans plus.
A titre personnel, j’utilise la deuxième solution, car actuellement je ne sais pas construire un paquet rpm !
Il s’avère toutefois possible d’intégrer cyclope au menu clic-droit souris via le paquet via le menu.xml ou via le paquet obmenu.
Ce qui nous donne :
Nous lisons bien « python /home/stevie/CYCLOPE/CYCLOPE-TRAVAIL/usr/bin/cyclope » ce qui correspond à la ligne de commande personnel de lancement de cyclope.
De plus, venant de Livarp, j’ai l’habitude de concevoir une distribution ou sa dérivée, comme une suite de script relié ensemble pour que cela fonctionne. « Dans unix, tout est script !».
Exemple de clic-droit souris intégrant le script cyclope dans le menu openbox :
Nota bene : Ce serait la même chose avec le terminal, en intégrant le chemin de lancement du script
$ python /chemin_vers_votre_script_cyclope/cyclope
Une fois lancée, le script cyclope ouvre une fenêtre de choix des fichiers à ouvrir :
Choix d’ouvrir le dossier images, une fois le script lancée à partir du menu :
Exemple de visionnage d’une photo sans l’option de plein écran :
Traitement photo avec le logiciel Gimp :
Photo visionné en plein écran :
Fermeture du logiciel cyclope en clic-droit souris lors du visionnage d’une image en plein écran :
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# This application is released under the GNU General Public License
# v3 (or, at your option, any later version). You can find the full
# text of the license under http://www.gnu.org/licenses/gpl.txt
# By using, editing and/or distributing this software you agree to
# the terms and conditions of this license.
#_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
# original application : eyez - !v1.0~mickyz(c)2012
# simplified to cyclope, a simple image viewer - thuban (yeuxdelibad.net) © 2015
import sys
import os
import gobject
import gtk
from gtk import gdk
import gettext
progname = "cyclope"
version = "1.5"
auteur = "Thuban"
licence = "GPLv3"
homepage= "https://handylinux.org"
cyclopeicon = "/usr/share/pixmaps/cyclope_icon.png"
minimal_w = 420
minimal_h = 180
screen_ratio = 0.85
EXT = ('.bmp','.ico','.gif','.jpg','.jpeg','.png','.svg','.svgz','.tif','.tiff')
editors = [{'app' :'gimp', 'name' :'gimp'},\
{'app' :'lodraw', 'name' :'Libreoffice Draw'},
{'app' :'gthumb', 'name' :'gthumb'},\
{'app' :'gpaint', 'name' :'gpaint'},\
{'app' :'shotwell', 'name' :'shotwell'}]
gettext.bindtextdomain(progname, '/usr/share/locale')
gettext.textdomain(progname)
_ = gettext.gettext
def listFiles(directory):
files = [ f for f in sorted(os.listdir(directory)) if os.path.splitext(f.lower())[1] in EXT ]
return(files)
def help():
print("usage : {} /path/to/picture".format(sys.argv[0]))
def error_dlg(error):
m = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,\
buttons = gtk.BUTTONS_OK)
m.set_markup(_("""Error while opening this file. Sorry \n {}""").format(error))
ret = m.run()
if ret == gtk.RESPONSE_DELETE_EVENT or ret == gtk.RESPONSE_OK:
m.destroy()
sys.exit(1)
def select_image():
"""return choosed filename or None"""
chooser = gtk.FileChooserDialog(title=_("Open a picture"),action=gtk.FILE_CHOOSER_ACTION_OPEN,\
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
chooser.set_current_folder(os.getcwd())
filter = gtk.FileFilter()
filter.set_name(_("Images"))
mimes = ["image/png", "image/jpeg", "image/gif"]
for m in mimes:
filter.add_mime_type(m)
patterns = [ "*.bmp", "*.ico", "*.gif", "*.jpg", "*.jpeg", "*.png",\
"*.svg", "*.svgz", "*.tif", "*.tiff" ]
for p in patterns :
filter.add_pattern(p)
chooser.add_filter(filter)
response = chooser.run()
if response == gtk.RESPONSE_OK:
i = chooser.get_filename()
chooser.destroy()
return(i)
else:
print(_('Closed, no files selected'))
chooser.destroy()
return(None)
class Cyclope():
def __init__(self, img):
# variables
self.imginfo = { 'path': str(), 'pixbuf': str(), 'is_static': True, 'width':0, 'height':0 }
self.isfull = False # fullscreen or not
self.oldtime = 0
# to zoom or not to zoom
self.zoommode = False
self.tozoom = False
self.xz, self.yz, self.wz, self.hz = 0, 0, 0, 0
self.diapomode = False
self.image = gtk.Image() # L'image affichée
# La fenêtre principale
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_position(gtk.WIN_POS_CENTER_ALWAYS)
self.window.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#222222")) # Fond sombre
# La taille de l'écran
self.sw,self.sh = gdk.screen_width() *screen_ratio, gdk.screen_height() *screen_ratio
# Les boutons de la fenêtre
self.rightarrow = gtk.Button(stock=gtk.STOCK_GO_FORWARD)
self.leftarrow = gtk.Button(stock=gtk.STOCK_GO_BACK)
self.fullbtn = gtk.Button(stock=gtk.STOCK_FULLSCREEN)
self.quitbtn = gtk.Button(stock=gtk.STOCK_QUIT)
self.rightarrow.connect("button_release_event", lambda x,y: self.skipImage(+1))
self.leftarrow.connect("button_release_event", lambda x,y: self.skipImage(-1))
self.fullbtn.connect("button_release_event", lambda x,y: self.toggle_fullscreen())
self.quitbtn.connect("button_release_event", lambda x,y: self.quit_app())
self.buttons = gtk.HBox(True,0)
self.buttons.pack_start(self.leftarrow,False, True,0)
self.buttons.pack_start(self.rightarrow, False,True,0)
self.buttons.pack_start(self.fullbtn, False,True,0)
self.buttons.pack_start(self.quitbtn, False,True,0)
for i in self.buttons: # disable keyboard focus
if type(i) == gtk.Button: i.set_can_focus(False)
# boite contenant l'image
self.evbox = gtk.EventBox()
self.evbox.add(self.image)
self.evbox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#222222')) # fond sombre
# pour récupérer les informations nécessaires au zoom
self.evbox.connect("button_release_event", self.apply_zoom)
self.evbox.connect("motion_notify_event", self.motion_notify_event)
# pour pas que la evbox prenne toute la place
imgbox = gtk.HBox(False,0)
imgbox.pack_start(self.evbox,True,False,0)
# La boite qui contient tout
self.container = gtk.VBox(False,0)
self.container.pack_start(imgbox, True, False,0)
self.container.pack_start(self.buttons, False, False, 0)
# configuration de la fenêtre
self.window.add(self.container)
self.window.set_border_width(4) # pour avoir une bordure
self.window.set_decorated(False)
if os.path.isfile(cyclopeicon):
self.window.set_icon_from_file(cyclopeicon)
self.window.add_events(gdk.BUTTON_PRESS_MASK | gdk.KEY_PRESS_MASK | gdk.SCROLL_MASK)
self.window.connect('button_press_event', self.onButtonPress)
self.window.connect('key_release_event', self.onKeyPress)
self.window.connect('delete_event', self.quit_app)
self.window.show_all()
self.set_image(img)
gtk.main()
def quit_app(self):
self.window.hide()
gtk.main_quit()
return(True)
def diaporama(self):
if not self.diapomode:
self.diapomode = True
gobject.timeout_add(2000, self.diapo_cycle)
else:
self.diapomode = False
def diapo_cycle(self):
if self.diapomode:
self.skipImage(+1)
gobject.timeout_add(3000, self.diapo_cycle)
def back_to_nomal(self):
self.set_image(self.imginfo['path'])
self.updateimage()
def toggle_zoom(self):
if self.zoommode == True:
self.zoommode = False
self.evbox.window.set_cursor(None)
self.back_to_nomal()
else:
self.zoommode = True
watch = gtk.gdk.Cursor(gtk.gdk.CROSS)
self.evbox.window.set_cursor(watch)
def apply_zoom(self, widget, event):
# on appuie sur entrée pour valider le zoom
if self.zoommode and self.imginfo['is_static'] and self.tozoom : # pas besoin d'aller plus loin sinon
# dimensions de la grande image
oldw, oldh = self.imginfo['width'], self.imginfo['height']
pix=self.image.get_pixbuf() # on récupère l'image actuelle
zoomed_pix = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, self.wz, self.hz)
pix.copy_area(self.xz, self.yz, self.wz, self.hz, zoomed_pix, 0, 0) # on garde que la zone souhaitée
# on met l'image aux dimensions de la fenêtre précédente
ow,oh = self.sw, self.hz*self.sw/self.wz
zoomed_pix = zoomed_pix.scale_simple(int(ow),int(oh), gdk.INTERP_BILINEAR)
# mise à jour des informations de l'image
self.imginfo['pixbuf'] = zoomed_pix
self.imginfo['width'], self.imginfo['height'] = zoomed_pix.get_width(), zoomed_pix.get_height()
self.image.set_from_pixbuf(zoomed_pix)
self.updateimage()
self.tozoom = False
del pix
del zoomed_pix
def motion_notify_event(self, widget, event):
if self.zoommode and self.imginfo['is_static']: # pas besoin d'aller plus loin sinon
# dimensions de la grande image
oldw, oldh = self.imginfo['width'], self.imginfo['height']
# récupération des données
x, y = int(event.x), int(event.y)
# attention au dépassements
if x > oldw : x = oldw
if x < 0 : x = 0
if y > oldh : y = oldh
if y < 0 : y = 0
if x > self.xz_orig:
self.wz = x - self.xz_orig
self.xz = self.xz_orig
else:
self.wz = abs(x - self.xz_orig)
self.xz = x
if y > self.yz_orig:
self.hz = y - self.yz_orig
self.yz = self.yz_orig
else:
self.hz = abs(y - self.yz_orig)
self.yz = y
state = event.state
if state & gtk.gdk.BUTTON1_MASK:
cr = self.image.window.cairo_create()
cr.set_source_pixbuf(self.image.get_pixbuf(),0,0) # pour effacer l'ancien rect
cr.paint()
cr.stroke()
cr.set_source_rgba(0.25, 0.69, 1, 0.5)
cr.rectangle(self.xz, self.yz, self.wz, self.hz)
cr.fill()
self.tozoom = True
def set_image(self, img):
""" Render the Pixbuf and show the image """
self.get_infos(img)
self.updateimage()
# Quelques infos dans le titre de la fenêtre
self.window.set_title('{} ! {}x{}'.format(\
os.path.basename(img), self.imginfo['width'], self.imginfo['height']))
def get_infos(self, img):
"""put image path, pixbuf and bool_static in self.imginfo"""
if img.endswith('.gif'):
pix = gdk.PixbufAnimation(img)
if pix.is_static_image():
self.imginfo = { 'path': '', 'pixbuf': '', 'is_static': True, 'width':0, 'height':0 }
self.imginfo['path'] = img
self.imginfo['pixbuf'] = pix.get_static_image().apply_embedded_orientation()
self.imginfo['is_static'] = True
else:
self.imginfo['path'] = img
self.imginfo['pixbuf'] = pix
self.imginfo['is_static'] = False
else:
self.imginfo['path'] = img
self.imginfo['pixbuf'] = gdk.pixbuf_new_from_file(img).apply_embedded_orientation()
self.imginfo['is_static'] = True
self.imginfo['width'] = self.imginfo['pixbuf'].get_width()
self.imginfo['height'] = self.imginfo['pixbuf'].get_height()
def updateimage(self):
gap = self.buttons.get_allocation().height # taille des boutons à réserver
pix = self.imginfo['pixbuf']
iw,ih = self.imginfo['width'], self.imginfo['height']
# on cherche la taille de l'image la plus adaptée
ow,oh = iw,ih
if not self.isfull:
if iw > self.sw:
ow,oh = self.sw, ih*self.sw/iw
if oh > self.sh:
ow,oh = iw*self.sh/ih, self.sh
else:
if iw > self.sw or ih > self.sh:
ow,oh = self.sw/screen_ratio, ih*self.sw/screen_ratio/iw - gap
if oh > self.sh:
ow,oh = iw*self.sh/screen_ratio/ih, self.sh/screen_ratio - gap
# on redimensionne l'image
if self.imginfo['is_static']:
pix = pix.scale_simple(int(ow),int(oh), gdk.INTERP_BILINEAR)
self.image.set_from_pixbuf(pix)
else:
self.image.set_from_animation(pix)
del pix
# on change la taille de la fenêtre
if self.isfull:
self.window.resize(gdk.screen_width(),gdk.screen_height())
else:
if ow < minimal_w:
self.window.resize(minimal_w, int(oh+gap))
else:
self.window.resize(int(ow),int(oh+gap))
def toggle_fullscreen(self):
if self.isfull: # on passe en taille normale
self.window.unfullscreen()
self.buttons.show()
self.isfull = False
self.updateimage()
self.fullbtn.set_label(_("Fullscreen"))
image = gtk.Image()
image.set_from_stock(gtk.STOCK_FULLSCREEN, gtk.ICON_SIZE_MENU)
self.fullbtn.set_image(image)
else:# On passe en plein écran
self.isfull = True
self.window.fullscreen()
self.buttons.hide()
self.updateimage()
self.fullbtn.set_label(_("Restore screen"))
image = gtk.Image()
image.set_from_stock(gtk.STOCK_UNDO, gtk.ICON_SIZE_MENU)
self.fullbtn.set_image(image)
def open_image(self):
i = select_image()
if i :
self.set_image(i)
def onButtonPress(self, widget, event):
if self.zoommode and self.imginfo['is_static']: # pas besoin d'aller plus loin sinon
if event.button == 1:
self.xz_orig, self.yz_orig = int(event.x), int(event.y)
else:
if event.button == 1 :
if event.type == gdk._2BUTTON_PRESS: # double clic gauche
self.toggle_fullscreen()
elif not self.isfull and (event.get_time() - self.oldtime > 500 ):
self.window.begin_move_drag(event.button, int(event.x_root), int(event.y_root), event.time)
self.oldtime = event.get_time()
if event.button == 3 or event.button == 2: # n'importe quel autre bouton
self.onMenuPopup(event.get_time())
def onKeyPress(self, win, event):
key = gdk.keyval_name(event.keyval)
if key == 'Escape' or key == 'q':
if not self.isfull:
self.quit_app()
else:
if self.diapomode :
self.diapomode = False
self.toggle_fullscreen()
elif key == 'p':
self.diaporama()
elif key == 'z':
self.toggle_zoom()
elif key == 'equal':
self.back_to_nomal()
elif key == 'f':
self.toggle_fullscreen()
elif key == 'Right' or key == 'n':
self.skipImage(+1)
elif key == 'Left' or key == 'b':
self.skipImage(-1)
elif key == 'o':
self.open_image()
elif key == 'm':
self.onMenuPopup(event.get_time())
elif key == 'd':
self.rotate(90)
elif key == 'g':
self.rotate(-90)
elif key == 'h':
self.window.set_title("Handylinux rocks!")
elif key == 'a':
self.window.set_title("arpinux needs beers!")
def onMenuPopup(self, time=0):
self.app_menu = self.set_menu()
self.app_menu.show_all()
self.app_menu.popup(None, None, None, 3, time, 0)
def set_menu(self):
menu = gtk.Menu()
op = gtk.ImageMenuItem(gtk.STOCK_OPEN)
op.connect('activate', lambda w: self.open_image())
menu.append(op)
menu.append(gtk.SeparatorMenuItem())
rotater = gtk.ImageMenuItem(gtk.STOCK_CONVERT)
rotater.set_label(_("Rotate right"))
rotater.connect('activate', lambda w: self.rotate(90))
menu.append(rotater)
rotatel = gtk.ImageMenuItem(gtk.STOCK_CONVERT)
rotatel.set_label(_("Rotate left"))
rotatel.connect('activate', lambda w: self.rotate(-90))
menu.append(rotatel)
zoom = gtk.ImageMenuItem(gtk.STOCK_ZOOM_IN)
if self.zoommode :
zoom.set_label(_("Disable zoom"))
zoom.connect('activate', lambda w: self.toggle_zoom())
else:
zoom.set_label(_("Zoom"))
zoom.connect('activate', lambda w: self.toggle_zoom())
menu.append(zoom)
if self.diapomode:
diapo = gtk.ImageMenuItem(gtk.STOCK_MEDIA_STOP)
diapo.set_label(_("Disable slideshow"))
else:
diapo = gtk.ImageMenuItem(gtk.STOCK_MEDIA_PLAY)
diapo.set_label(_("Enable slideshow"))
diapo.connect('activate', lambda w: self.diaporama())
menu.append(diapo)
for editor in editors:
if os.path.exists('/usr/bin/{}'.format(editor['app'])):
edit = gtk.ImageMenuItem(gtk.STOCK_EDIT)
edit.set_label(_("Edit with {}").format(editor['name']))
edit.connect('activate', self.openWith, editor['app'])
menu.append(edit)
menu.append(gtk.SeparatorMenuItem())
apropos = gtk.ImageMenuItem(gtk.STOCK_HELP)
apropos.connect('activate', self.about)
menu.append(apropos)
close = gtk.ImageMenuItem(gtk.STOCK_CLOSE)
close.connect('activate', lambda w: self.quit_app())
menu.append(close)
return menu
def skipImage(self, position):
path = self.imginfo['path']
d, f = os.path.dirname(path), os.path.basename(path)
files = listFiles(d)
for n,i in enumerate(files):
if f == i:
try: f = files[n+position]
except: f = files[0]
self.set_image(os.path.join(d, f))
break
def rotate(self,angle):
pix = self.imginfo['pixbuf']
if angle == 90:
rotated = pix.rotate_simple(gtk.gdk.PIXBUF_ROTATE_CLOCKWISE)
elif angle == -90:
rotated = pix.rotate_simple(gtk.gdk.PIXBUF_ROTATE_COUNTERCLOCKWISE)
self.imginfo['pixbuf'] = rotated
self.imginfo['width'], self.imginfo['height'] = rotated.get_width(), rotated.get_height()
if self.imginfo['is_static']:
self.image.set_from_pixbuf(rotated)
else:
self.image.set_from_animation(rotated)
self.updateimage()
del pix
del rotated
def openWith(self, widget, data=None):
import subprocess
try:
subprocess.Popen([data, self.imginfo['path']])
except:
print("Error at opening {} with {}".format(self.imginfo['path'], data))
def about(self, wid=None, data=None):
# fenêtre à propos.
m = gtk.MessageDialog(type=gtk.MESSAGE_INFO,\
buttons = gtk.BUTTONS_OK)
m.set_markup(_("""<b>{}</b>
version : {}
author : {}
licence : {}
homepage : {}
---
usage :
Use arrows, b and n keys to change image
Double click or press f key to enlarge the window
Press o to open a new image
Press d or g to turn the image
Press z to toggle zoom mode
Press = to restore the image
Press p to start slideshow mode
Press m or right click to show the menu
Press Escape or q to quit""").format(progname, version, auteur, licence, homepage))
ret = m.run()
if ret == gtk.RESPONSE_DELETE_EVENT or ret == gtk.RESPONSE_OK:
m.destroy()
def main():
if len(sys.argv) == 1 : # si aucune image en argument
img = select_image()
if not img :
sys.exit() # on quitte s'il n'y a pas d'image choisie
elif len(sys.argv) == 2:
img = os.path.abspath(sys.argv[1])
if os.path.isdir(img): # si c'est un répertoire
imglist = sorted(os.listdir(img))
if len(imglist) > 0: # on ouvre les images du répertoire
img = os.path.join(img,imglist[0])
try:
window = Cyclope(img) # ouverture d'une image
except Exception as e:
help()
error_dlg(e)
return 0
if __name__ == '__main__':
main()
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
Voilà, cyclope fonctionne bien sous Fedora (n, n+1, ...).
Le principe devrait être le même quelque soit le système unix employé, y compris NetBSD et OpenBSD.
Ne sachant pas faire de paquet rpm, je me contente de cette démarche empirique, mais qui fonctionne, puisque fondée sur le principe basique que tout est script sous unix.
En vous souhaitant un bon usage du script cyclope.
Bien à vous.
Mr. S.
- Sources.list d’Handylinux : http://repo.handylinux.org/handylinux.list,
- article « fabrication de package rpm » : http://eric.gerbier.free.fr/fabrication-rpm.html,
- article « Créer un package RPM » : http://wiki.gantzer.eu/index.php/Cr%C3% … ackage_RPM,
- forum openclassroom : https://openclassrooms.com/forum/sujet/ … -sur-linux,
- fonds d’écran « Viperr 9 » : https://viperr.org/site/img/DesktopV9.png.
Hors ligne
j'avous pas eu le courage de tout lire par manque de balise "code"
quand c'est une sortie de terminal merci de mettre les bonne balises.
vi est mon ami pour la vie
Ph'nglui nglw-nafh Cthulhu R'lyeh wgah-nagl fhtagn
Hors ligne
j'avous pas eu le courage de tout lire par manque de balise "code"
quand c'est une sortie de terminal merci de mettre les bonne balises.
Je confirme, c'est illisible sans mise en forme.
Utiliser des logiciels propriétaires, c'est comme les plats préparés, on est incapable de dire les conservateurs qu'ils contiennent, on dira toujours que c'est bon, mais ça ne remplacera jamais le repas fait maison par sa maman.
]:D #! Crunchbang & Archlinux GNU/Linux User ]:D
Hors ligne
Bonjour,
Pourriez-vous m'expliquer comment rédiger avec ce que vous appelez des balises codes ?
En effet, cela me permettrait de reprendre ce tutoriel de manière à le rendre plus lisible et compréhensible.
Par ailleurs, comment intégrer les photos dans le texte du post ?
Je possède quelques tutoriels en réserves que j'hésite à vous communiquer pour cette raison.
Merci d'avance.
Mr. S.
Hors ligne
Normalement tu as les boutons au dessus de la zone texte pour mettre en forme le texte.
Sinon une balise code c'est ceci
[code]ton code ici[/code]
Pour les images c'est
[img]lien vers l'image ici[/img]
exemple:
[img]https://upload.wikimedia.org/wikipedia/commons/thumb/5/53/GNU_and_Tux.svg/620px-GNU_and_Tux.svg.png[/img]
Ce qui donne:
Utiliser des logiciels propriétaires, c'est comme les plats préparés, on est incapable de dire les conservateurs qu'ils contiennent, on dira toujours que c'est bon, mais ça ne remplacera jamais le repas fait maison par sa maman.
]:D #! Crunchbang & Archlinux GNU/Linux User ]:D
Hors ligne
Bonjour tout le monde,
Je viens de refaire ma copie en tenant compte de vos remarques tout à fait justifiées.
J'espère que je ne me suis pas trop trompé dans l'usage des balises codes.
Merci donc à Viperr et à IceFox.
Bonne lecture à tous donc et que ce tutoriel vous soit des plus utiles !
Introduction
1 / Echec de dpkg-repack sous KissOs-7.0
2 / téléchargement du paquet cyclope (pour debian) depuis le dépôt handylinux
3 / Création d'un dossier de travail
4 / Echec de l’utilisation du paquet alien pour transformer le paquet cyclope (pour debian) en paquet pour fedora
5 / Procédure d’extraction du paquet cyclope (pour debian)
6 / Lancement du script python dans l’environnement linux (cela marche également quelque soit l’unix utilisé, linux, BSD ...)
7 / Manuel d’utilisation du script cyclope
8 / Script cyclope à lancer avec python
Conclusion
Sources
Il s’agit ici non seulement de vous présenter le paquet cyclope, visionneuse photo ultra-légère, conçu par Thuban) mais encore de vous permettre de l’utiliser sur n’importe quelle système unix [linux (Arch, debian, fedora, gentoo, void, …) ou BSD (Net, Open …) et que sais-je encore !
Ma plate-forme de travail a autant été :
- un acer aspire 9410 sous KissOs-0.7 mono-boot :
Exemple de mon bureau sur KissOs-0.7 : un simple rajout de cairo-dock qui rend bien service !
- un lenovo G50-45 UEFI SECURE BOOT sous Viperr Fedora remix 9 fc 26, dopée aux kickstarts fedora labs (https://github.com/SamsungARTIK/fedora-spin-kickstarts). D’abord dual boot avec Windows 8/10, puis mono boot (mais toujours UEFI SECURE BOOT!) car j’en avais marre des mises à jour longues de Windows dont je ne me sers plus à la maison depuis 2010 environ.
Ce qui nous donne ceci :
stevie@kiss0s ~
$ dpkg-repack cyclope
dpkg-repack: Fatal Error: This program should be run as root (or you could use fakeroot -u). Aborting.
stevie@kiss0s ~
$ fakeroot -u
bash: fakeroot : commande introuvable
stevie@kiss0s ~
$ sudo apt-get -y install fakeroot
[sudo] Mot de passe de stevie :
Lecture des listes de paquets... Fait
Construction de l'arbre des dépendances
Lecture des informations d'état... Fait
The following additional packages will be installed:
libfakeroot
Les NOUVEAUX paquets suivants seront installés :
fakeroot libfakeroot
0 mis à jour, 2 nouvellement installés, 0 à enlever et 1 non mis à jour.
Il est nécessaire de prendre 134 ko dans les archives.
Après cette opération, 369 ko d'espace disque supplémentaires seront utilisés.
Réception de:1 http://deb.debian.org/debian stretch/main i386 libfakeroot i386 1.21-3.1 [46,8 kB]
Réception de:2 http://deb.debian.org/debian stretch/main i386 fakeroot i386 1.21-3.1 [86,8 kB]
134 ko réceptionnés en 0s (231 ko/s)
Sélection du paquet libfakeroot:i386 précédemment désélectionné.
(Lecture de la base de données... 80611 fichiers et répertoires déjà installés.)
Préparation du dépaquetage de .../libfakeroot_1.21-3.1_i386.deb ...
Dépaquetage de libfakeroot:i386 (1.21-3.1) ...
Sélection du paquet fakeroot précédemment désélectionné.
Préparation du dépaquetage de .../fakeroot_1.21-3.1_i386.deb ...
Dépaquetage de fakeroot (1.21-3.1) ...
Traitement des actions différées (« triggers ») pour libc-bin (2.24-11+deb9u1) ...
Paramétrage de libfakeroot:i386 (1.21-3.1) ...
Traitement des actions différées (« triggers ») pour man-db (2.7.6.1-2) ...
Paramétrage de fakeroot (1.21-3.1) ...
update-alternatives: utilisation de « /usr/bin/fakeroot-sysv » pour fournir « /usr/bin/fakeroot » (fakeroot) en mode automatique
Traitement des actions différées (« triggers ») pour libc-bin (2.24-11+deb9u1) ...
stevie@kiss0s ~
$ fakeroot -u
root@kiss0s ~
$ sudo dpkg-repack cyclope
ERROR: ld.so: object 'libfakeroot-sysv.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
dpkg-query: le paquet « cyclope » n'est pas installé et aucune information n'est disponible
Utilisez dpkg --info (= dpkg-deb --info) pour examiner les fichiers
archives, et dpkg --contents (= dpkg-deb --contents) pour afficher leur
contenu.
Use of uninitialized value in pattern match (m//) at /usr/bin/dpkg-repack line 138.
Use of uninitialized value in concatenation (.) or string at /usr/bin/dpkg-repack line 139.
dpkg-repack: Fatal Error: Package cyclope not fully installed:
root@kiss0s ~
$ exit
exit
stevie@kiss0s ~
$ fakeroot -u
root@kiss0s ~
$ dpkg-repack cyclope
dpkg-query: le paquet « cyclope » n'est pas installé et aucune information n'est disponible
Utilisez dpkg --info (= dpkg-deb --info) pour examiner les fichiers
archives, et dpkg --contents (= dpkg-deb --contents) pour afficher leur
contenu.
Use of uninitialized value in pattern match (m//) at /usr/bin/dpkg-repack line 138.
Use of uninitialized value in concatenation (.) or string at /usr/bin/dpkg-repack line 139.
dpkg-repack: Fatal Error: Package cyclope not fully installed:
root@kiss0s ~
$
Ce qui donne ceci en copie écran :
En partant du sources.list d'Handylinux (http://repo.handylinux.org/handylinux.list) :
## HandyLinux v1 ##
deb http://handylinux.org/repo/debian stable main
#deb-src http://handylinux.org/repo/debian stable main
## HandyLinux v1 Compiz ##
deb http://handylinux.org/repo/debian compiz main
#deb-src http://handylinux.org/repo/debian compiz main
## HandyLinux v2 Jessie ##
deb http://handylinux.org/repo/debian jessie main
#deb-src http://handylinux.org/repo/debian jessie main
## HandyLinux Testing ##
deb http://handylinux.org/repo/debian testing main
#deb-src http://handylinux.org/repo/debian testing main
=> Extraire la "bonne adresse", soit "http://handylinux.org/repo/debian/".
Nous obtenons ceci :
Index of /repo/debian
Icon Name Last modified Size Description[DIR] Parent Directory -
[DIR] conf/ 06-Jun-2017 18:58 -
[DIR] db/ 06-Jun-2017 18:58 -
[DIR] dists/ 06-Jun-2017 18:58 -
[DIR] lists/ 06-Jun-2017 18:58 -
[DIR] pool/ 06-Jun-2017 18:58
=> Se rendre dans le dossier "pool" :
=> Naviguer dans le dépôt jusqu'à l'url "http://handylinux.org/repo/debian/pool/main/c/"
Index of /repo/debian/pool/main/c
Icon Name Last modified Size Description[DIR] Parent Directory -
[DIR] ccsm/ 06-Jun-2017 18:59 -
[DIR] compiz-deskmenu/ 06-Jun-2017 18:59 -
[DIR] compiz-fusion-plugin..> 06-Jun-2017 19:02 -
[DIR] compiz-fusion-plugin..> 06-Jun-2017 19:00 -
[DIR] compiz/ 06-Jun-2017 19:01 -
[DIR] compizconfig-python/ 06-Jun-2017 18:59 -
[DIR] copcoll/ 06-Jun-2017 18:59 -
[DIR] cyclope/ 06-Jun-2017 19:01
=> Entrer dans cyclope : url "http://handylinux.org/repo/debian/pool/main/c/cyclope"
Index of /repo/debian/pool/main/c/cyclope
Icon Name Last modified Size Description[DIR] Parent Directory -
[ ] cyclope_1.5-5.debian..> 06-Jun-2017 19:01 5.1K
[TXT] cyclope_1.5-5.dsc 06-Jun-2017 19:01 841
[ ] cyclope_1.5-5_all.deb 06-Jun-2017 19:01 20K
[ ] cyclope_1.5.orig.tar.xz 06-Jun-2017 19:01 201K
$ mkdir /home/$user/CYCLOPE
=> Télécharger le fichier "cyclope_1.5-5_all.deb" par un clic droit souris
stevie ~ CYCLOPE dir
cyclope_1.5-5_all.deb
stevie ~ CYCLOPE ls
cyclope_1.5-5_all.deb
=> les commandes ls et dir fonctionnent sous debian et sous fedora pour déterminer le contenu d'un dossier.
stevie ~ CYCLOPE su
Mot de passe :
[root@Host-002 CYCLOPE]# alien -r *.deb
cyclope-1.5-6.noarch.rpm generated
[root@Host-002 CYCLOPE]# rpm -ivh *.rpm
Préparation... ################################# [100%]
le fichier /usr/bin de l'installation de cyclope-1.5-6.noarch entre en conflit avec le fichier du paquet viperr-obkey-8.0-viperr.fc24.noarch
le fichier /usr/bin de l'installation de cyclope-1.5-6.noarch entre en conflit avec le fichier du paquet viperrconf-9.7-viperr.fc24.noarch
le fichier /usr/bin de l'installation de cyclope-1.5-6.noarch entre en conflit avec le fichier du paquet viperr-conposite-8.0-viperr.fc24.noarch
le fichier / de l'installation de cyclope-1.5-6.noarch entre en conflit avec le fichier du paquet filesystem-3.2-40.fc26.x86_64
le fichier /usr/bin de l'installation de cyclope-1.5-6.noarch entre en conflit avec le fichier du paquet filesystem-3.2-40.fc26.x86_64
=> Le paquet cyclope alienisé en version fedora entre en conflit avec plusieurs paquets fedora. Il ne peut donc être utilisé tel quel.
=> vous noterez que alien rajoute un numéro à cyclope en le convertissant de debian (cyclope_1.5-5_all.deb) à fedora (cyclope-1.5-6.noarch.rpm)
Vérification si ce paquet aurait été toutefois installé :
[root@Host-002 CYCLOPE]# rpm -e *.rpm
erreur : le paquet cyclope-1.5-6.noarch.rpm n'est pas installé
=> Le paquet cyclope ne peut être désintallé, puisqu'il n'a pas été installé.
[root@Host-002 CYCLOPE]# exit
Si tout est script dans unix, et si linux est un unix qui s'ignore, alors il reste la solution d'utiliser cyclope comme un simple script python, plutôt que comme un paquet en bonne et due forme malheureusement conflictuel.
L'idée est donc de suivre la procédure classique d'extraction d'un paquet deb
stevie ~ CYCLOPE ar xv *.deb
x - debian-binary
x - control.tar.gz
x – data.tar.xz
Soit en copie-écran :
=> Il en résulte trois fichiers dénommés debian-binary, control.tar.gz et data.tar.xz, soit :
Dépaquetage un paquet *.deb
$ ar xv *.deb
Cela nous fournit 3 fichiers:
- debian-binary : fichier indiquant la version du paquet deb, soit 2.0, très différent de 1.5.5 affiché en dénomination du paquet ...
- data.tar.xz : fichier compressé contenant le code de cyclope,
- control.tar.gz : fichier compressé de contrôl.
A ce stade, il convient de procéder au désossage de chaque sous-fichier :
$ tar xvf control.tar.gz
stevie ~ CYCLOPE tar xvf control.tar.gz
./
./control
./md5sums
=> le fichier md5sums permet de vérifier l'intégrité de l'archive.
=> Ici, pas de fichier de configuration, sauf s'il a disparu en cours de route …
En naviguant dans le système avec le gestionnaire de fichier « ranger », le contenu du fichier « control » apparait alors :
Package: cyclope
Version: 1.5-5
Architecture: all
Maintainer: arnault perret <arpinux@member.fsf.org>
Installed-Size: 99
Depends: python (>= 2.7), python-gtk2
Section: x11
Priority: optional
Homepage: https://handylinux.org/wiki/doku.php/fr/media#cyclope
Description: Une visionneuse d'images minimale.
Cyclope vous permet de visionner, pivoter ou zoomer
vos images simplement.
Vous pouvez aussi lancer un diaporama ou envoyer vos
images vers d'autres applications.
.
C'est la visionneuse rapide du bureau HandyLinux.
~
~
~
"~/CYCLOPE/control" 16L, 524C
=> Notons les dépendances python (>= 2.7) et python-gtk2 !
Et oui, cyclope participe d'Handylinux ! Mais également de KissOs-7.0 !
Décompression du fichier « data.tar.xz »
$ tar xvf data.tar.xz
Résultat :
stevie ~ CYCLOPE tar xvf data.tar.xz
./
./usr/
./usr/share/
./usr/share/doc/
./usr/share/doc/cyclope/
./usr/share/doc/cyclope/changelog.Debian.gz
./usr/share/doc/cyclope/copyright
./usr/share/man/
./usr/share/man/man1/
./usr/share/man/man1/cyclope.1.gz
./usr/share/locale/
./usr/share/locale/en/
./usr/share/locale/en/LC_MESSAGES/
./usr/share/locale/en/LC_MESSAGES/cyclope.mo
./usr/share/locale/fr/
./usr/share/locale/fr/LC_MESSAGES/
./usr/share/locale/fr/LC_MESSAGES/cyclope.mo
./usr/share/applications/
./usr/share/applications/cyclope.desktop
./usr/share/pixmaps/
./usr/share/pixmaps/cyclope_icon.png
./usr/bin/
./usr/bin/cyclope
En gros : un dossier usr, qui contient lui-même deux sous-dossiers bin et share :
Le sous-dossier share comprend à son tour 5 sous-dossiers :
- pixmaps, icone du paquet
- locale, usage du paquet en langue française et anglaise
- man, manpage
- doc,
* changelog,
=>
* copyright :
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: cyclope
Files: *
Copyright: 2012 mickyz
2015 Xavier Cartron <thuban@yeuxdelibad.net>
2015 arpinux <arpinux@member.fsf.org>
License: GPL-3+
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
.
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
- applications,
fichier cyclope-desktop :
[Desktop Entry]
Name=Cyclope
Comment=Minimalist image viewer
Comment[fr]=Visionneuse d'images minimaliste
Exec=/usr/bin/cyclope
Icon=cyclope_icon
StartupNotify=true
Terminal=false
Type=Application
Categories=GTK;Graphics;Viewer;
Le sous-dossier bin comprend à son tour 1 seul fichier dénommé cyclope, constitué par un script python qui va nous intéresser désormais.
Il nous reste donc à lancer le script python dans un environnement linux :
Après avoir installé les dépendances vues plus hauts python (>= 2.7) et python-gtk2, exécuter le script comme suit :
$ python cyclope # soit python nom_du_script_python_à_lancer
=> chez moi, cela donne cela :
stevie ~ cd /home/stevie/CYCLOPE/CYCLOPE-TRAVAIL/usr/bin/
stevie … CYCLOPE-TRAVAIL usr bin dir
cyclope
stevie … CYCLOPE-TRAVAIL usr bin python cyclope
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:88: Incapable de localiser le fichier image dans le chemin des pixmaps : « assets/combo-entry-border.png »
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:92: Background image options specified without filename
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:98: Incapable de localiser le fichier image dans le chemin des pixmaps : « assets/combo-entry-border-focus.png »
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:102: Background image options specified without filename
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:109: Incapable de localiser le fichier image dans le chemin des pixmaps : « assets/combo-entry-border-rtl.png »
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:113: Background image options specified without filename
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:119: Incapable de localiser le fichier image dans le chemin des pixmaps : « assets/combo-entry-border-focus-rtl.png »
/usr/share/themes/Arc-REDemption/gtk-2.0/apps.rc:123: Background image options specified without filename
/usr/share/themes/Arc-REDemption/gtk-2.0/xfce-notify.rc:1: error: unexpected character '\', expected keyword - e.g. `style'
Soit en copie-écran :
Une fenêtre de choix de fichiers images s'ouvre alors et permet de choisir les fichiers images à visionner. Il convient de naviguer sur le disque dur, car cyclope s'ouvrira sur le dossier de localisation du script !
Manuel raccourci de l'utilisation de cyclope :
Le menu clic-droit souris de cyclope propose plusieurs entrées (items) :
***
- ouvrir
- tourner côté droit,
- tourner côté gauche
- zoom,
- enclencher le défilement des photos,
- traiter l'image avec Gimp, logiciel reconnu par cyclope comme installé dans le système
- Traiter l'image avec Shotwell, logiciel reconnu par cyclope comme installé dans le système
- Aide :
cyclope
version : 1.5
author : Thuban
licence : GPLv3
homepage : https://handylinux.org
---
usage : # utilisation :
Use arrows, b and n keys to change image # utiliser les flèches ou les touches b et n pour faire défiler les images
Double click or press f key to enlarge the window # Double cliquer ou appuyer la lettre « f » pour augmenter la taille de l’image
Press o to open a new image # utiliser la touche o pour ouvrir une image
Press d or g to turn the image # utiliser les touches d ou g pour faire pivoter l'image
Press z to toggle zoom mode # Appuyer la lettre « z » pour zoomer
Press = to restore the image # utiliser la touche z pour passer en mode zoom : sélectionner alors une zone avec votre curseur, le zoom sera lancé une fois le clic laché
Press p to start slideshow mode # utiliser la touche p pour lancer ou stopper le diaporama
Press m or right click to show the menu # utiliser la touche m ou le clic-droit pour afficher le menu
Press left click to show the menu # maintenir le clic-gauche pour déplacer la fenêtre
Press Escape or q to quit # utiliser ESC ou q pour quitter
=> Chez moi, cela fonctionne parfaitement.
=> Cette aide s’avère légèrement modifier quant à la version originale. En effet, la ligne « Press left click to show the menu # maintenir le clic-gauche pour déplacer la fenêtre » a été rajouté, afin de paralléliser le fichier d’aide avec le fichier cyclope.1.gz
=> Dans le cas où vous ne sachiez pas configurer un paquet, ne modifiez rien, laissez tout comme cela …
=> La traduction française n’est de moi mais de Thuban à copié à partir du fichier cyclope.1.gz décompressable à l’adresse /home/$user/…/ usr/share/man/man1/ soit :
.TH CYCLOPE 1 "Sept, 08 2015"
.SH NAME
cyclope \- une visionneuse d'images par thuban
.SH DESCRIPTION
.B cyclope
est une visionneuse d'image en python ultra-légère
.br
.SH USAGE
utiliser les flèches ou les touches b et n pour faire défiler les images
.br
utiliser la touche o pour ouvrir une image
.br
utiliser la touche p pour lancer ou stopper le diaporama
.br
utiliser la touche m ou le clic-droit pour afficher le menu
.br
utiliser la touche f ou le double-clic pour dés/activer le plein-écran.
.br
utiliser les touches d ou g pour faire pivoter l'image
.br
utiliser la touche z pour passer en mode zoom : sélectionner alors une zone avec votre curseur, le zoom sera lancé une fois le clic laché.
.br
utiliser la touche = pour quitter le mode zoom
.br
maintenir le clic-gauche pour déplacer la fenêtre
.br
utiliser ESC ou q pour quitter.
.br
.TH cyclope
- fermer
Pour installer le script cyclope dans votre système, il existe deux solutions s’offre à l’utilisateur :
- soit créer son propre paquet cyclope *.rpm car celui-ci n’existe pas encore,
- soit installer le script et se contenter de le rendre opérationnel, sans plus.
A titre personnel, j’utilise la deuxième solution, car actuellement je ne sais pas construire un paquet rpm !
Il s’avère toutefois possible d’intégrer cyclope au menu clic-droit souris via le paquet via le menu.xml ou via le paquet obmenu.
Ce qui nous donne :
Nous lisons bien « python /home/stevie/CYCLOPE/CYCLOPE-TRAVAIL/usr/bin/cyclope » ce qui correspond à la ligne de commande personnel de lancement de cyclope.
De plus, venant de Livarp, j’ai l’habitude de concevoir une distribution ou sa dérivée, comme une suite de script relié ensemble pour que cela fonctionne. « Dans unix, tout est script !».
Exemple de clic-droit souris intégrant le script cyclope dans le menu openbox :
Nota bene : Ce serait la même chose avec le terminal, en intégrant le chemin de lancement du script
$ python /chemin_vers_votre_script_cyclope/cyclope
Une fois lancée, le script cyclope ouvre une fenêtre de choix des fichiers à ouvrir :
Choix d’ouvrir le dossier images, une fois le script lancée à partir du menu :
Exemple de visionnage d’une photo sans l’option de plein écran :
Traitement photo avec le logiciel Gimp :
Photo visionné en plein écran :
Fermeture du logiciel cyclope en clic-droit souris lors du visionnage d’une image en plein écran :
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# This application is released under the GNU General Public License
# v3 (or, at your option, any later version). You can find the full
# text of the license under http://www.gnu.org/licenses/gpl.txt
# By using, editing and/or distributing this software you agree to
# the terms and conditions of this license.
#_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
# original application : eyez - !v1.0~mickyz(c)2012
# simplified to cyclope, a simple image viewer - thuban (yeuxdelibad.net) © 2015
import sys
import os
import gobject
import gtk
from gtk import gdk
import gettext
progname = "cyclope"
version = "1.5"
auteur = "Thuban"
licence = "GPLv3"
homepage= "https://handylinux.org"
cyclopeicon = "/usr/share/pixmaps/cyclope_icon.png"
minimal_w = 420
minimal_h = 180
screen_ratio = 0.85
EXT = ('.bmp','.ico','.gif','.jpg','.jpeg','.png','.svg','.svgz','.tif','.tiff')
editors = [{'app' :'gimp', 'name' :'gimp'},\
{'app' :'lodraw', 'name' :'Libreoffice Draw'},
{'app' :'gthumb', 'name' :'gthumb'},\
{'app' :'gpaint', 'name' :'gpaint'},\
{'app' :'shotwell', 'name' :'shotwell'}]
gettext.bindtextdomain(progname, '/usr/share/locale')
gettext.textdomain(progname)
_ = gettext.gettext
def listFiles(directory):
files = [ f for f in sorted(os.listdir(directory)) if os.path.splitext(f.lower())[1] in EXT ]
return(files)
def help():
print("usage : {} /path/to/picture".format(sys.argv[0]))
def error_dlg(error):
m = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,\
buttons = gtk.BUTTONS_OK)
m.set_markup(_("""Error while opening this file. Sorry \n {}""").format(error))
ret = m.run()
if ret == gtk.RESPONSE_DELETE_EVENT or ret == gtk.RESPONSE_OK:
m.destroy()
sys.exit(1)
def select_image():
"""return choosed filename or None"""
chooser = gtk.FileChooserDialog(title=_("Open a picture"),action=gtk.FILE_CHOOSER_ACTION_OPEN,\
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
chooser.set_current_folder(os.getcwd())
filter = gtk.FileFilter()
filter.set_name(_("Images"))
mimes = ["image/png", "image/jpeg", "image/gif"]
for m in mimes:
filter.add_mime_type(m)
patterns = [ "*.bmp", "*.ico", "*.gif", "*.jpg", "*.jpeg", "*.png",\
"*.svg", "*.svgz", "*.tif", "*.tiff" ]
for p in patterns :
filter.add_pattern(p)
chooser.add_filter(filter)
response = chooser.run()
if response == gtk.RESPONSE_OK:
i = chooser.get_filename()
chooser.destroy()
return(i)
else:
print(_('Closed, no files selected'))
chooser.destroy()
return(None)
class Cyclope():
def __init__(self, img):
# variables
self.imginfo = { 'path': str(), 'pixbuf': str(), 'is_static': True, 'width':0, 'height':0 }
self.isfull = False # fullscreen or not
self.oldtime = 0
# to zoom or not to zoom
self.zoommode = False
self.tozoom = False
self.xz, self.yz, self.wz, self.hz = 0, 0, 0, 0
self.diapomode = False
self.image = gtk.Image() # L'image affichée
# La fenêtre principale
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_position(gtk.WIN_POS_CENTER_ALWAYS)
self.window.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#222222")) # Fond sombre
# La taille de l'écran
self.sw,self.sh = gdk.screen_width() *screen_ratio, gdk.screen_height() *screen_ratio
# Les boutons de la fenêtre
self.rightarrow = gtk.Button(stock=gtk.STOCK_GO_FORWARD)
self.leftarrow = gtk.Button(stock=gtk.STOCK_GO_BACK)
self.fullbtn = gtk.Button(stock=gtk.STOCK_FULLSCREEN)
self.quitbtn = gtk.Button(stock=gtk.STOCK_QUIT)
self.rightarrow.connect("button_release_event", lambda x,y: self.skipImage(+1))
self.leftarrow.connect("button_release_event", lambda x,y: self.skipImage(-1))
self.fullbtn.connect("button_release_event", lambda x,y: self.toggle_fullscreen())
self.quitbtn.connect("button_release_event", lambda x,y: self.quit_app())
self.buttons = gtk.HBox(True,0)
self.buttons.pack_start(self.leftarrow,False, True,0)
self.buttons.pack_start(self.rightarrow, False,True,0)
self.buttons.pack_start(self.fullbtn, False,True,0)
self.buttons.pack_start(self.quitbtn, False,True,0)
for i in self.buttons: # disable keyboard focus
if type(i) == gtk.Button: i.set_can_focus(False)
# boite contenant l'image
self.evbox = gtk.EventBox()
self.evbox.add(self.image)
self.evbox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#222222')) # fond sombre
# pour récupérer les informations nécessaires au zoom
self.evbox.connect("button_release_event", self.apply_zoom)
self.evbox.connect("motion_notify_event", self.motion_notify_event)
# pour pas que la evbox prenne toute la place
imgbox = gtk.HBox(False,0)
imgbox.pack_start(self.evbox,True,False,0)
# La boite qui contient tout
self.container = gtk.VBox(False,0)
self.container.pack_start(imgbox, True, False,0)
self.container.pack_start(self.buttons, False, False, 0)
# configuration de la fenêtre
self.window.add(self.container)
self.window.set_border_width(4) # pour avoir une bordure
self.window.set_decorated(False)
if os.path.isfile(cyclopeicon):
self.window.set_icon_from_file(cyclopeicon)
self.window.add_events(gdk.BUTTON_PRESS_MASK | gdk.KEY_PRESS_MASK | gdk.SCROLL_MASK)
self.window.connect('button_press_event', self.onButtonPress)
self.window.connect('key_release_event', self.onKeyPress)
self.window.connect('delete_event', self.quit_app)
self.window.show_all()
self.set_image(img)
gtk.main()
def quit_app(self):
self.window.hide()
gtk.main_quit()
return(True)
def diaporama(self):
if not self.diapomode:
self.diapomode = True
gobject.timeout_add(2000, self.diapo_cycle)
else:
self.diapomode = False
def diapo_cycle(self):
if self.diapomode:
self.skipImage(+1)
gobject.timeout_add(3000, self.diapo_cycle)
def back_to_nomal(self):
self.set_image(self.imginfo['path'])
self.updateimage()
def toggle_zoom(self):
if self.zoommode == True:
self.zoommode = False
self.evbox.window.set_cursor(None)
self.back_to_nomal()
else:
self.zoommode = True
watch = gtk.gdk.Cursor(gtk.gdk.CROSS)
self.evbox.window.set_cursor(watch)
def apply_zoom(self, widget, event):
# on appuie sur entrée pour valider le zoom
if self.zoommode and self.imginfo['is_static'] and self.tozoom : # pas besoin d'aller plus loin sinon
# dimensions de la grande image
oldw, oldh = self.imginfo['width'], self.imginfo['height']
pix=self.image.get_pixbuf() # on récupère l'image actuelle
zoomed_pix = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, self.wz, self.hz)
pix.copy_area(self.xz, self.yz, self.wz, self.hz, zoomed_pix, 0, 0) # on garde que la zone souhaitée
# on met l'image aux dimensions de la fenêtre précédente
ow,oh = self.sw, self.hz*self.sw/self.wz
zoomed_pix = zoomed_pix.scale_simple(int(ow),int(oh), gdk.INTERP_BILINEAR)
# mise à jour des informations de l'image
self.imginfo['pixbuf'] = zoomed_pix
self.imginfo['width'], self.imginfo['height'] = zoomed_pix.get_width(), zoomed_pix.get_height()
self.image.set_from_pixbuf(zoomed_pix)
self.updateimage()
self.tozoom = False
del pix
del zoomed_pix
def motion_notify_event(self, widget, event):
if self.zoommode and self.imginfo['is_static']: # pas besoin d'aller plus loin sinon
# dimensions de la grande image
oldw, oldh = self.imginfo['width'], self.imginfo['height']
# récupération des données
x, y = int(event.x), int(event.y)
# attention au dépassements
if x > oldw : x = oldw
if x < 0 : x = 0
if y > oldh : y = oldh
if y < 0 : y = 0
if x > self.xz_orig:
self.wz = x - self.xz_orig
self.xz = self.xz_orig
else:
self.wz = abs(x - self.xz_orig)
self.xz = x
if y > self.yz_orig:
self.hz = y - self.yz_orig
self.yz = self.yz_orig
else:
self.hz = abs(y - self.yz_orig)
self.yz = y
state = event.state
if state & gtk.gdk.BUTTON1_MASK:
cr = self.image.window.cairo_create()
cr.set_source_pixbuf(self.image.get_pixbuf(),0,0) # pour effacer l'ancien rect
cr.paint()
cr.stroke()
cr.set_source_rgba(0.25, 0.69, 1, 0.5)
cr.rectangle(self.xz, self.yz, self.wz, self.hz)
cr.fill()
self.tozoom = True
def set_image(self, img):
""" Render the Pixbuf and show the image """
self.get_infos(img)
self.updateimage()
# Quelques infos dans le titre de la fenêtre
self.window.set_title('{} ! {}x{}'.format(\
os.path.basename(img), self.imginfo['width'], self.imginfo['height']))
def get_infos(self, img):
"""put image path, pixbuf and bool_static in self.imginfo"""
if img.endswith('.gif'):
pix = gdk.PixbufAnimation(img)
if pix.is_static_image():
self.imginfo = { 'path': '', 'pixbuf': '', 'is_static': True, 'width':0, 'height':0 }
self.imginfo['path'] = img
self.imginfo['pixbuf'] = pix.get_static_image().apply_embedded_orientation()
self.imginfo['is_static'] = True
else:
self.imginfo['path'] = img
self.imginfo['pixbuf'] = pix
self.imginfo['is_static'] = False
else:
self.imginfo['path'] = img
self.imginfo['pixbuf'] = gdk.pixbuf_new_from_file(img).apply_embedded_orientation()
self.imginfo['is_static'] = True
self.imginfo['width'] = self.imginfo['pixbuf'].get_width()
self.imginfo['height'] = self.imginfo['pixbuf'].get_height()
def updateimage(self):
gap = self.buttons.get_allocation().height # taille des boutons à réserver
pix = self.imginfo['pixbuf']
iw,ih = self.imginfo['width'], self.imginfo['height']
# on cherche la taille de l'image la plus adaptée
ow,oh = iw,ih
if not self.isfull:
if iw > self.sw:
ow,oh = self.sw, ih*self.sw/iw
if oh > self.sh:
ow,oh = iw*self.sh/ih, self.sh
else:
if iw > self.sw or ih > self.sh:
ow,oh = self.sw/screen_ratio, ih*self.sw/screen_ratio/iw - gap
if oh > self.sh:
ow,oh = iw*self.sh/screen_ratio/ih, self.sh/screen_ratio - gap
# on redimensionne l'image
if self.imginfo['is_static']:
pix = pix.scale_simple(int(ow),int(oh), gdk.INTERP_BILINEAR)
self.image.set_from_pixbuf(pix)
else:
self.image.set_from_animation(pix)
del pix
# on change la taille de la fenêtre
if self.isfull:
self.window.resize(gdk.screen_width(),gdk.screen_height())
else:
if ow < minimal_w:
self.window.resize(minimal_w, int(oh+gap))
else:
self.window.resize(int(ow),int(oh+gap))
def toggle_fullscreen(self):
if self.isfull: # on passe en taille normale
self.window.unfullscreen()
self.buttons.show()
self.isfull = False
self.updateimage()
self.fullbtn.set_label(_("Fullscreen"))
image = gtk.Image()
image.set_from_stock(gtk.STOCK_FULLSCREEN, gtk.ICON_SIZE_MENU)
self.fullbtn.set_image(image)
else:# On passe en plein écran
self.isfull = True
self.window.fullscreen()
self.buttons.hide()
self.updateimage()
self.fullbtn.set_label(_("Restore screen"))
image = gtk.Image()
image.set_from_stock(gtk.STOCK_UNDO, gtk.ICON_SIZE_MENU)
self.fullbtn.set_image(image)
def open_image(self):
i = select_image()
if i :
self.set_image(i)
def onButtonPress(self, widget, event):
if self.zoommode and self.imginfo['is_static']: # pas besoin d'aller plus loin sinon
if event.button == 1:
self.xz_orig, self.yz_orig = int(event.x), int(event.y)
else:
if event.button == 1 :
if event.type == gdk._2BUTTON_PRESS: # double clic gauche
self.toggle_fullscreen()
elif not self.isfull and (event.get_time() - self.oldtime > 500 ):
self.window.begin_move_drag(event.button, int(event.x_root), int(event.y_root), event.time)
self.oldtime = event.get_time()
if event.button == 3 or event.button == 2: # n'importe quel autre bouton
self.onMenuPopup(event.get_time())
def onKeyPress(self, win, event):
key = gdk.keyval_name(event.keyval)
if key == 'Escape' or key == 'q':
if not self.isfull:
self.quit_app()
else:
if self.diapomode :
self.diapomode = False
self.toggle_fullscreen()
elif key == 'p':
self.diaporama()
elif key == 'z':
self.toggle_zoom()
elif key == 'equal':
self.back_to_nomal()
elif key == 'f':
self.toggle_fullscreen()
elif key == 'Right' or key == 'n':
self.skipImage(+1)
elif key == 'Left' or key == 'b':
self.skipImage(-1)
elif key == 'o':
self.open_image()
elif key == 'm':
self.onMenuPopup(event.get_time())
elif key == 'd':
self.rotate(90)
elif key == 'g':
self.rotate(-90)
elif key == 'h':
self.window.set_title("Handylinux rocks!")
elif key == 'a':
self.window.set_title("arpinux needs beers!")
def onMenuPopup(self, time=0):
self.app_menu = self.set_menu()
self.app_menu.show_all()
self.app_menu.popup(None, None, None, 3, time, 0)
def set_menu(self):
menu = gtk.Menu()
op = gtk.ImageMenuItem(gtk.STOCK_OPEN)
op.connect('activate', lambda w: self.open_image())
menu.append(op)
menu.append(gtk.SeparatorMenuItem())
rotater = gtk.ImageMenuItem(gtk.STOCK_CONVERT)
rotater.set_label(_("Rotate right"))
rotater.connect('activate', lambda w: self.rotate(90))
menu.append(rotater)
rotatel = gtk.ImageMenuItem(gtk.STOCK_CONVERT)
rotatel.set_label(_("Rotate left"))
rotatel.connect('activate', lambda w: self.rotate(-90))
menu.append(rotatel)
zoom = gtk.ImageMenuItem(gtk.STOCK_ZOOM_IN)
if self.zoommode :
zoom.set_label(_("Disable zoom"))
zoom.connect('activate', lambda w: self.toggle_zoom())
else:
zoom.set_label(_("Zoom"))
zoom.connect('activate', lambda w: self.toggle_zoom())
menu.append(zoom)
if self.diapomode:
diapo = gtk.ImageMenuItem(gtk.STOCK_MEDIA_STOP)
diapo.set_label(_("Disable slideshow"))
else:
diapo = gtk.ImageMenuItem(gtk.STOCK_MEDIA_PLAY)
diapo.set_label(_("Enable slideshow"))
diapo.connect('activate', lambda w: self.diaporama())
menu.append(diapo)
for editor in editors:
if os.path.exists('/usr/bin/{}'.format(editor['app'])):
edit = gtk.ImageMenuItem(gtk.STOCK_EDIT)
edit.set_label(_("Edit with {}").format(editor['name']))
edit.connect('activate', self.openWith, editor['app'])
menu.append(edit)
menu.append(gtk.SeparatorMenuItem())
apropos = gtk.ImageMenuItem(gtk.STOCK_HELP)
apropos.connect('activate', self.about)
menu.append(apropos)
close = gtk.ImageMenuItem(gtk.STOCK_CLOSE)
close.connect('activate', lambda w: self.quit_app())
menu.append(close)
return menu
def skipImage(self, position):
path = self.imginfo['path']
d, f = os.path.dirname(path), os.path.basename(path)
files = listFiles(d)
for n,i in enumerate(files):
if f == i:
try: f = files[n+position]
except: f = files[0]
self.set_image(os.path.join(d, f))
break
def rotate(self,angle):
pix = self.imginfo['pixbuf']
if angle == 90:
rotated = pix.rotate_simple(gtk.gdk.PIXBUF_ROTATE_CLOCKWISE)
elif angle == -90:
rotated = pix.rotate_simple(gtk.gdk.PIXBUF_ROTATE_COUNTERCLOCKWISE)
self.imginfo['pixbuf'] = rotated
self.imginfo['width'], self.imginfo['height'] = rotated.get_width(), rotated.get_height()
if self.imginfo['is_static']:
self.image.set_from_pixbuf(rotated)
else:
self.image.set_from_animation(rotated)
self.updateimage()
del pix
del rotated
def openWith(self, widget, data=None):
import subprocess
try:
subprocess.Popen([data, self.imginfo['path']])
except:
print("Error at opening {} with {}".format(self.imginfo['path'], data))
def about(self, wid=None, data=None):
# fenêtre à propos.
m = gtk.MessageDialog(type=gtk.MESSAGE_INFO,\
buttons = gtk.BUTTONS_OK)
m.set_markup(_("""<b>{}</b>
version : {}
author : {}
licence : {}
homepage : {}
---
usage :
Use arrows, b and n keys to change image
Double click or press f key to enlarge the window
Press o to open a new image
Press d or g to turn the image
Press z to toggle zoom mode
Press = to restore the image
Press p to start slideshow mode
Press m or right click to show the menu
Press Escape or q to quit""").format(progname, version, auteur, licence, homepage))
ret = m.run()
if ret == gtk.RESPONSE_DELETE_EVENT or ret == gtk.RESPONSE_OK:
m.destroy()
def main():
if len(sys.argv) == 1 : # si aucune image en argument
img = select_image()
if not img :
sys.exit() # on quitte s'il n'y a pas d'image choisie
elif len(sys.argv) == 2:
img = os.path.abspath(sys.argv[1])
if os.path.isdir(img): # si c'est un répertoire
imglist = sorted(os.listdir(img))
if len(imglist) > 0: # on ouvre les images du répertoire
img = os.path.join(img,imglist[0])
try:
window = Cyclope(img) # ouverture d'une image
except Exception as e:
help()
error_dlg(e)
return 0
if __name__ == '__main__':
main()
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
Voilà, cyclope fonctionne bien sous Fedora (n, n+1, ...).
Le principe devrait être le même quelque soit le système unix employé, y compris NetBSD et OpenBSD.
Ne sachant pas faire de paquet rpm, je me contente de cette démarche empirique, mais qui fonctionne, puisque fondée sur le principe basique que tout est script sous unix.
En vous souhaitant un bon usage du script cyclope.
Bien à vous.
Mr. S.
- Sources.list d’Handylinux : http://repo.handylinux.org/handylinux.list,
- article « fabrication de package rpm » : http://eric.gerbier.free.fr/fabrication-rpm.html,
- article « Créer un package RPM » : http://wiki.gantzer.eu/index.php/Cr%C3% … ackage_RPM,
- forum openclassroom : https://openclassrooms.com/forum/sujet/ … -sur-linux,
- fonds d’écran « Viperr 9 » : https://viperr.org/site/img/DesktopV9.png.
Hors ligne
Re-bonjour,
Les photos ne passent pas. Dommage, car j'ai suivi les instructions. Le texte s'avère toutefois plus lisible.
Je vais reformater les tutoriels que je possède en réserve.
Bien à vous.
Hors ligne
J'ai tenté de corriger les images mais il y en as trop, tu confond url et image dans tes balises.
Utiliser des logiciels propriétaires, c'est comme les plats préparés, on est incapable de dire les conservateurs qu'ils contiennent, on dira toujours que c'est bon, mais ça ne remplacera jamais le repas fait maison par sa maman.
]:D #! Crunchbang & Archlinux GNU/Linux User ]:D
Hors ligne
Merci beaucoup IceFox.
En fait, il y a 23 photos et le forum n'en supporte que 20.
Je vais retravailler ma copie.
D'autant plus que les photos se mélangent maintenant à la sortie pour celles qui émergent du néant. Pas trop grave en soi.
Je possède une version en odt et en pdf. Je ne sais pas si cela peut être basculé sur le forum; ce serait plus pratique. Le côté positif, c'est que j'apprends des choses nouvelles !
Hors ligne
Bonjour tout le monde,
Je viens de refaire ma copie en tenant compte des remarques d'IceFox.
J'ai réduit le nombre de photos au strict minimum, mais elle n'apparaisse toujours pas. Alors tant pis, ce qui compte c'est le code !
Le texte se suffit largement à lui-même.
Bonne lecture et bon usage !
#################
Edit: j'ai mis le tuto sur ton premier post pour plus de lisibilité.
Hors ligne
hA là ca donne envis !
Merci pour ton taf, je lirais cela a tete reposé.
Merci
vi est mon ami pour la vie
Ph'nglui nglw-nafh Cthulhu R'lyeh wgah-nagl fhtagn
Hors ligne
bon taf et bonne détermination continu comme ça
Mess With The Bests
Die Like The Rest
Hors ligne