January 17th, 2010 @ 4:15pm | njames | Categories Coding | No Comments »
Pour mettre au point un petit annotateur graphique d'image (placement de symboles graphique, différents mode de sélection de patch), j'utilise Apache Batik. Cela me permet de contenir les annotations en SVG, ce qui est bien pratique, autant pour la gestion en interne des annotations (e.g. les layers sont des groupes de symboles graphiques dont la propriétés SVG visibility change), un arbre XML c'est la panacée. J'avais déjà travaillé un peu là dessus, mais c'était codé à la va-vite et uniquement pour afficher les annotations LabelMe:

C'est ainsi que je me suis frotté aux obscurs rouages du pipeline graphique de Batik... et un petit problème que je viens de résoudre est celui-ci: Si un objet JSVGCanvas est dans le viewport d'un JScrollPane, comment positionner une texture de rendu sur le background du JSVGCanvas (i.e. positionner un background particulier sur l'objet qui est dans le viewport du JScrollPane ! ). Il faut faire attention à ce que fait la méthode de rendu paint(...) de JSVGCanvas. En fait, cette méthode paint(...) est héritée de JComponent:

Un objet JSVGCanvas est un JComponent qui contient une liste de CanvasGraphicsNode. Positionnner un background sur JSVGCanvas, revient à positionner un background sur un JComponent, et la méthode paintComponent(Graphics g) est redéfinie dans la classe JGVTComponent, c'est donc dans cette classe que l'on doit faire quelque chose. Il n'y a rien de prévu pour cela dans Batik, la solution que j'ai mise en place est de modifier les sources, ça se fait facilement en modifiant la classe org.apache.batik.swing.gvt.JGVTComponent:
private TexturePaint texpaint;
 
public void setTexturePaint(TexturePaint texpaint){
this.texpaint = texpaint;
}
 
 
/**
* Paints this component.
*/
public void paintComponent(Graphics g) {
   super.paintComponent(g);
 
   Graphics2D g2d = (Graphics2D)g;
 
   Rectangle visRect = getRenderRect();
   g2d.setComposite(AlphaComposite.SrcOver);
 
   //les deux lignes suivantes sont commentées.
   //g2d.setPaint(getBackground());
   //g2d.fillRect(visRect.x, visRect.y, visRect.width, visRect.height);
 
   //et on ajoute les deux lignes suivantes:
   g2d.setPaint(texpaint);
   g2d.fillRect(0, 0, getWidth(), getHeight());
 
   if (image != null) {
       if (paintingTransform != null) {
         g2d.transform(paintingTransform);
            }
            g2d.drawRenderedImage(image, null);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                 RenderingHints.VALUE_ANTIALIAS_OFF);
            Iterator it = overlays.iterator();
            while (it.hasNext()) {
                ((Overlay)it.next()).paint(g);
            }
        }
    }
Rien de bien sorcier: on ajoute de quoi positionner un TexturePaint, et on modifie un brin paintComponent(Graphics g) pour texturer le panel plutôt que peindre avec la couleur de background.

that's it !

Quelques notes à propos de Apache Batik
  • le format PGM n'est pas supporté dans un SVG Batik.
December 11th, 2009 @ 5:18pm | njames | Categories Java | No Comments »
Depuis quelques jours, je m'intéresse à de la génération automatique d'une hiérarchie de topics en utilisant Flickr. Pourquoi Flickr ? pour ses données textuelles (le tagging social des images par les utilisateurs du website) et ses données images. J'intègre tout cela à mon modèle de donnée pour construire des collections d'image, et j'explore ces collections avec des outils que j'ai développé il y a quelques mois, je voudrais pouvoir explorer facilement le dataset et gérer les documents (retrait d'image ou de tag).
C'est ainsi que comparativement à mes autres expérimentations, le modèle textuel associé à mes images contient:
  1. des documents faiblement taggés (weakly tagged).
  2. des informations textuelles qui ne sont pas forcément en anglais, ni basé sur un alphabet latin.
Jusqu'à présent mes images étaient annotées en anglais et avec l'objectif explicite de construire un jeu de donnée image pour la vision par ordinateur, on peut donc dire que ses images étaient annotées par des iconographes de l'ordinaire en le sens que les annotations sont pertinentes (i.e. fiable, c'est pour cela que je dis iconographe) et portent sur des objets de la vie de tous les jours (d'où iconographe de l'ordinaire).

Le sujet de ce billet est le second point, Java gère très bien l'UTF, mais il est évident que l'index des fonts disponibles pour les UI graphique est délégué à l'installeur de Java sur la machine, car on ne peut pas localiser les fonts de façon standard pour tous les OS pour lesquels Java est disponible.

Screenshot-Java - FlickrMiner-src-net-trevize-IIDFBrowser.java - Eclipse

Sur ma machine, j'installe toujours Java à la main, dans /opt, je trouve cela plus propre, je suis contre ce qui est fait pour java-6-openjdk par exemple (mettre les fichiers de configuration de Java dans /etc... pourquoi vouloir complètement intégrer Java à l'OS, je trouve que c'est particulièrement microsoftien comme façon de faire... ).
Le fichier ~jrehome/lib/fontconfig.properties qui renseigne Java sur les fonts disponibles sur le système n'est donc pas renseigné quand on installe Java à la main: dans le cas d'Ubuntu il suffit de piocher le fichier installé pour java-6-openjdk /etc/java-6-openjdk/fontconfig.properties et le copier dans ~jrehome/lib/fontconfig.properties.
August 11th, 2009 @ 9:13pm | njames | Categories Coding | No Comments »
Les TreeTable combinent les fonctionnalités des composants/renderers pour des données arborescentes et des données tabulaires.

http://doc.trolltech.com/4.3/images/simpletreemodel-example.png

Il en existe de très bon en Qt, comme sur l'image précédente, mais en Java, il n'existe pas de tel composant standard en swing/awt, et c'est bien dommage car il y a une forte demande pour de tels widgets.
Un billet sur le weblog Heresylabs parle du problème également.
Ainsi, il y a quelques projets tiers qui apportent ce type de composant graphique, comme:
  • pour commencer, on trouve ce (vieux) tutoriel pour créer des TreeTable avec Swing.
  • SwingLabs, SwingX - JXTreeTable: fonctionne bien mais souffre de bugs graphique (de gros bugs graphique apparaissent lors d'un changement de look'n'feel, par exemple en passant en look'n'feel GTK+... malheureusement pour moi, j'utilise uniquement ce look'n'feel...). Cependant, les classes sont simples à utiliser.
  • JEdit: semble intéressant mais le widget treetable est intégré dans le projet... pas de library pour la gui et donc difficilement utilisable dans un projet.
  • JIDE Software: semble intéressant mais très compliqué apparemment... et propriétaire et payant.
  • Netbeans: le plus stable, pas de bug graphique, et très simple à utiliser, c'est du bonheur en barre. Voir ça et ça et ça.
    Pour afficher un fichier XML, via DOM, dans un treetable NetBeans, c'est relativement simple.
    Récupérer la library org-netbeans-swing-outline.jar dans NetBeans (dans ~netbeans/platformN/modules) et l'ajouter au classpath d'un projet Java.
    Petit exemple en 4 fichiers: XmlTreeNode.java, XmlTreeModel.java, XmlRowModel.java, Test.java.
    Résultat:

    netbeans-treetable2

    Cela reste bien moins joli que du Qt mais je n'ai pas non plus écrit de renderer pour améliorer l'affichage sur ce bout de code.
  • Une autre solution pourrait être d'utiliser QtJambi, mais le binding Qt pour Java n'est plus maintenu par Trolltech, donc c'est une idée à oublier...
August 9th, 2009 @ 5:23pm | njames | Categories Coding | No Comments »
Pour un projet d'annotation de document vidéo (annotation sémantique manuelle), j'investigue du côté des différentes API existantes pour intégrer un player vidéo dans une application Java.

JMF, Java Media Framework
Bien sûr, il y a JMF, Java Media Framework, mais cette API commence à vieillir, et de plus elle cafouille un peu avec Java1.5, il est recommander d'utiliser JMF avec Java1.4 (voir ici ou ), ce qui est potentiellement embêtant.

Screenshot-JMStudio

Quelques liens sur JMF:
Les alternatives
  • des bindings avec ffmpeg, via JNI ou JNA, comme FMJ, Freedom for Media in Java, qui se veut un clone de JMF en quelque sorte. Pour le binding avec ffmpeg, JNA est utilisé.
    Cette API n'embarque pas de version de ffmpeg, et s'appuie sur la version de ffmpeg disponible sur la machine locale.

    Screenshot-FMJ Studio Screenshot-Registry Editor-1

  • jffmpeg: un plugin pour JMF, de nombreux codecs présent dans ffmpeg sont recodés en Java, voir cette page.
    Pour ajouter le plugin jffmpeg au JMFRegistry voir cette page (contrairement, à FOBS, il n'y a pas de détection des codecs, il faut enregistrer les Mime Types, Plugins et Codecs à la main dans le JMFRegistry).
  • FOBS, qui est un wrapper objet au dessus de ffmpeg, et apporte des API C++, Java et python au dessus de ce wrapper. Côté Java, c'est via un plugin JMF, FOBS4JMF, qu'opère l'API Java de FOBS, (vu les performances décevantes au décodage d'un XVID, il faut utiliser une JVM1.4 pour JMF, c'est plus fluide mais pas encore assez cependant, ce n'est pas très beau, ffplay fait beaucoup mieux).
    FOBS embarque sa propre version de ffmpeg et de jmf.
    Pour le tester, après son installation, aller dans ~FOBS/dist/jmf, et utiliser le JMStudio de JMF java -cp fobs4jmf.jar:jmf.jar JMStudio.
  • JVLC.
  • gstreamer-java: un binding-java pour gstreamer, fonctionne vraiment très bien! Le binding est basé sur JNA.
    Cependant le projet est encore assez jeune, et il y a de nombreuses fonctionnalités que j'aimerais y trouver qui ne sont pas disponibles: choisir le flux dans le container (vidéo et/ou audio), pause puis passer à la frame suivante, lecture accélérée -1 ou +1 etc..

    Screenshot-VideoPlayer-1

  • Xuggle-Xuggler: binding sur ffmpeg.
  • Quelques liens à propos de la nouvelle API de sun, la Java Media Components API:
July 29th, 2009 @ 11:05pm | njames | Categories Coding | No Comments »
Difficile de se passer d'un gestionnaire de to do lists, pour ma part en tous les cas, que ce soit qtodo (celui que j'utilise depuis un bon moment maintenant), ou via evolution, RTM, Lightning, GTodo, KOrganizer, ReminderFox, etc.

L'inconvénient de tous ces softwares est que la liste des tâches n'est disponible qu'en local (sauf pour evolution ou RTM).
Pendant quelques temps j'ai utilisé une page wiki de mon dokuwiki comme to-do list, mais il y a plus pratique.

C'est ainsi que j'avais commencé un petit projet surnommé SuperDo il y a 1 an, utilisant Google Calendar pour stocker les items des to do lists.
Il est possible de créer des hidden calendars dans Google Calendar, ce qui est très pratique pour un calendrier nommé par exemple Superdo-Tasklist et d'y stocker les items d'une to do list.

Le projet est en sommeil depuis presque 1 an, une bonne partie du code est écrit, il ne manque plus grand chose pour avoir quelque chose de pleinement fonctionnel, je l'ai ressorti aujourd'hui pour voir si je pouvais l'utiliser avec Google Tasks qui est la nouvelle application Google pour la gestion de tâches, via gmail avec une sorte de widget ou via google calendar avec un calendrier nommé Tasks (attention la synchro gmail / google calendar demande quelques secondes): et bien non, raté, il semblerait que le calendar nommé Tasks ne soit pas un Google Calendar classique, et impossible de récupérer ce calendar via la Google API, dommage...
D'autant plus qu'il n'y a pas d'URL disponible pour un ical sur le calendrier Tasks (ce qu'on a pour les autres calendrier de Google Calendar), donc on ne peut pas visualiser non plus ce calendrier via un client sur sa machine genre sunbird ou assimilé...
July 7th, 2009 @ 11:22pm | njames | Categories Serendipity | No Comments »
June 29th, 2009 @ 9:09pm | njames | Categories Development tools | No Comments »
  • Pour la gestion de dépôt SVN, le plugin Subversive accompagné du connector SVN de Polarion est un brin buggy, sur certain (gros) dépôts SVN il me fait un heap space error, plutôt embêtant... Le plus étrange, c'est cette gestion d'erreur de la part d'Eclipse:

    screenshot-operation-failed

    Un fonctionnement anormal est détecté mais l'action "send report" est indisponible.

  • Pourquoi diable le gestionnaire de plugins/packages sous Eclipse est aussi complexe ? et surtout aussi LENT !! c'est purement incroyable ! et ça empire avec Eclipse Galileo (la nouvelle mouture d'Eclipse fraîchement sortie) pour ma part sur ma machine !

  • Avec Eclipse Galileo, il y a une nouvelle gestion des libraries (.jar et .jar externes). Pour ma part, j'aime bien avoir un sous-répertoire ./lib dans mon projet dans lequel je mets mes libraries (.jar et .so). C'est bien pratique de faire ainsi car le répertoire apparait dans l'arborescence du projet Eclipse, et les .jar qu'il contient apparaissent aussi dans Referenced Libraries:

    eclipse_annoyance1

    Avec Eclipse Galileo, le répertoire disparait de la vue arborescente, un développeur a trouvé pertinent de faire disparaitre le répertoire car il contient les libraries... je trouve cela complètement stupide: faire une vue système de fichier et une autre vue conceptualisée, orientée application Java qui ne reflète pas le système de fichier, oui! NetBeans le fait très bien, mais mélanger les deux... je suis tatillon mais je trouve cela stupide.

    Note: en fait c'est un comportement de l'import de jar automatique (une des nouveautés de Eclipse Galileo Java, voir la section Classpath resolution honors the 'Class-Path' header of JAR manifest file), on peut aller dans Referenced Libraries, clic droit sur le répertoire > remove from Referenced Libraries, ce qui fait réapparaitre le répertoire dans le package explorer.
    (Voir la page New and Noteworthy sur le site d'Eclipse pour toutes les nouveautés de Galileo).
June 22nd, 2009 @ 8:30pm | njames | Categories Development tools, Java | No Comments »
(Voir l'épisode précédent).
Nouvelle version de Galatee, mon petit projet de navigation dans une collection d'image en Java: Galatee_0.3.jar. Le projet est sous licence GPL.
(Attention: Je n'ai pas vérifié que l'application fonctionne bien sous d'autres systèmes d'exploitation (comme windows), je développe exclusivement sous GNU/Linux, et j'avoue que par exemple je n'utilise pas System.getProperty("path.separator")).
  • correction de bugs,
  • ajout et suppression de colonnes à la table d'affichage avec les touches '+' et '-',
  • activation du modèle de table dynamique (nombre de colonnes dans la table d'affichage fonction de la largeur de la fenêtre),
  • activation de la navigation dans la liste d'images avec pagination.
Pour tester le jar: java -jar Galatee-0.3.jar $path
L'application test est codée pour lancer la commande display de ImageMagick pour les images double-clickées.

Il reste encore un petit problème que je voudrais régler: une queue bornée pour les images chargées en mémoire (avec une gestion multi-pages, i.e. prenant en considération la pagination des documents), mais une stratégie intelligente (et la plus légère possible) pour cela, n'est pas facile à écrire.
May 14th, 2009 @ 6:33pm | njames | Categories Development tools, Java | 2 Comments »
Dans ce billet, je parlais d'une application SWT basée sur le widget SWT Nebula Gallery pour naviguer dans une collection en Java/SWT.
J'avais codé un thread de chargement pour avoir un load-when-you-see, et le tout fonctionne plutôt bien.

MAIS, c'est du SWT et cela m'embête un brin. Le but de ce projet est de naviguer dans de grande collection d'images, et il faut aussi que je puisse afficher un certain nombre de metadata associées à chaque image, ainsi je voulais afficher un petit ScrollPane pour chaque image contenant les metadata sous forme textuelle, et faire cela en SWT est apparemment une chose ardue.
C'est ainsi que je me suis mis à coder un widget similaire pour swing, j'ai renommé mon projet utilisant SWT Nebula Gallery en SWTGalatee, et mon nouveau projet swing devient Galatee.
Je pensais utiliser pour cela une JTable et un custom renderer pour les cellules de cette table. Ce custom renderer prendrait son rendu sur un JPanel qui contiendrait une image et un JScrollPane, mais c'est sans savoir comment fonctionne un Renderer en swing (voir ça), en fait un renderer ne produit que des images de composant swing: il ne faut pas s'attendre à une réponse d'événements souris ou clavier sur une image de composant.
Et un JScrollPane sans interaction via la souris, c'est inutile !

Solution adoptée: ne pas utiliser de JScrollPane pour afficher mes metadata, mais plutôt faire un JTextArea de la hauteur nécessaire pour afficher toutes les metadata.
Ainsi, la JTable à des lignes de hauteurs différentes, chaque ligne est de la hauteur de la cellule sur cette ligne qui a la hauteur max.

Le résultat sur la base MIRFlickr:

screenshot-iidf-browser


Plusieurs points sont à préciser tout de même:
  • pour le moment, je conserve en mémoire les thumbnails calculées pour le rendu, en fonction de leurs tailles, on peut vite être confronté à un java.lang.OutOfMemoryError: Java heap space.
    Pour le moment, utiliser les paramètres de la JVM -Xms<initial heap size> -Xmx<maximum heap size> est une solution à court terme. Une amélioration pourrait être d'améliorer le thread d'affichage en utilisant une liste bornée en taille pour les items chargés en mémoire.
  • le widget swing est plus lent que le widget SWT Nebula Gallery (sauf pour le temps de chargement du widget en lui même, swing est beaucoup plus rapide), sur deux points:
    • pour le calcul des thumbnails: dans un premier temps, j'ai utilisé BufferedImage.scaleInstance(...), puis dans un second temps JAI (j'ai testé avec et sans la library C, d'ailleurs étonnamment la library native de JAI est plus lente que la library pure java). Dans les deux cas SWT fait appel à des routines plus rapides.
    • pour l'affichage, la JTable est un widget assez rigide, il y a peut être des paramètres pour assouplir le scrolling mais je ne les connais pas. J'ai quand même positionné l'unité d'incrémentation du scroll (via sp.getVerticalScrollBar().setUnitIncrement(42), sp étant le JScrollPane de ma JTable, pour que le scrolling ne se fasse pas row par row mais sur une quantité de pixels.
  • le layout: avec SWT Nebula Gallery, le layout est dynamique, si la largeur de la fenêtre change le nombre de colonne de la grille d'images s'adapte pour afficher autant de colonnes que possible. Dans mon widget, la JTable empêche ce genre de chose.
    Je pourrais faire écouter le redimensionnement de la JTable et changer son modèle en fonction, mais j'ai peur que cela alourdisse cruellement l'affichage.
    Une solution à adopter serait peut être de changer le modèle sur demande de l'utilisateur, par exemple avec les touches '+' et '-', pour ajouter ou retirer des colonnes au modèle.
    edit 09-05-16: j'ai ajouté les deux comportements (1) '+' et '-' pour modifier le nombre de colonne, et (2) un modèle de table dynamique en fonction de la taille du JScrollPane contenant la JTable, ça se fait bien en codant futé pour modifier au minimum le modèle.
    Ainsi j'ai dû coder aussi l'update de la cellule sélectionnée dans le nouveau modèle (i.e. nouveau modèle car redimensionnement de la table, il faut que la cellule qui était sélectionnée dans l'ancien modèle soit toujours une cellule sélectionnée dans le nouveau modèle), et un scroll de la JTable pour que la cellule sélectionnée soit affichée (un scroll du rendu du nouveau modèle pour que la cellule sélectionnée soit affichée).

Archives:
  • Galatee-0.1.jar
  • edit 09-05-17: nouvelle version avec l'edit 09-05-16 (voir plus haut): Galatee-0.2.jar. Ajout également d'une interface GalateeListener à implémenter pour répondre aux événements sur la grille d'image:
    public interface GListener extends EventListener {
    	public void itemClicked(GEvent e);
     
    	public void itemDoubleClicked(GEvent e);
     
    	public void selectionChanged(GEvent e);
     
    	public void focusChanged(GEvent e);
    }
  • SWTGalatee-0.1.jar

Autres approches éventuellement possibles (mais que je n'ai pas investigué) pour réaliser un tel widget:
  • utiliser un Panel avec un GridLayout, spécifier la taille de la grille du layout en fonction du nombre d'images. Trouver un moyen pour savoir quand une cellule du panel doit être affichée et quand elle n'est plus sur l'écran. Quand elle doit être affichées faire un setComponentAt(...) de la cellule avec un custom panel pour mon image+metadata. Dès que la cellule quitte l'affichage de la fenêtre (par un scrolling), faire un setComponentAt(..., ..., null).
  • ne pas utiliser une table mais une succession de JList, ce qui permettrait de ne pas avoir des lignes de tailles fixes (et pas de ligne du tout d'ailleurs), cependant ce n'est peut être pas visuellement très louable.
April 22nd, 2009 @ 2:47pm | njames | Categories Java | No Comments »
Pour rediriger les sorties standard output et error de la console eclipse vers un fichier de log:
  1. configuration du lancement du main > onglet common
  2. cocher File
  3. indiquer le chemin vers le fichier de log
[source]
April 21st, 2009 @ 9:51pm | njames | Categories Java | 2 Comments »
Ces derniers temps, je cherchais un widget graphique en Java pour naviguer dans une collection d'image (éventuellement assez grande, genre 25.000 documents), quelque chose à la GThumb (en stand alone, pas une application web), avec un chargement dynamique et qui ne vampirise pas le thread d'affichage.
Mais je n'ai rien trouvé qui me convienne vraiment, car de plus, je voudrais pouvoir afficher près de chaque image, des métadonnées issues de traitement d'image (des informations stockées dans un fichier XML à la mpeg-7).

Dans le toolkit SWT, il y a le Nebula project qui a été lancé pour apporter des customs widgets à SWT: CalendarCombo, CDateTime, CollapsibleButtons, CompositeTable, DateChooser, DateChooserCombo, FormattedText, Gallery, Grid, GanttChart, PGroup, PShelf.

Le widget Gallery est très intéressant:

Nebula Gallery SWT widget

En partant d'un snippet pour afficher une collection d'image, j'ai fait un petit projet nommé Galatee, affichant les images avec un chargement dynamique des documents load-when-you-see.
J'ai codé un ImageLoaderThreadPoolThread qui est un thread Java classique, qui vide une queue d'images à charger, et qui démarre un thread SWT GUI de mise à jour de l'affichage une fois qu'une image est chargée (et redimensionnée pour son affichage).

L'application sur le jeu de donnée MIRFlickr:

screenshot-iidf-browser


Un problème cependant: l'intégration de widgets graphique en SWT est une chose un brin... problématique: je voudrais utiliser un scrollpane dans chaque cellule de ma grille d'images, et ajouter la liste de mes métadonnées dans ce scrollpane. En swing on peut faire cela avec un custom components (le widget est instancié une seule fois mais dessiné plusieurs fois, dans un JTableRenderer), mais en SWT c'est plus délicat car les widgets sont des widgets système...
March 5th, 2009 @ 5:32pm | njames | Categories Java | No Comments »
Dans le cadre de mes travaux de thèse, j'implémente une méthode d'annotation d'image basée sur des graphes et un modèle markovien. J'ai codé un premier prototype en Java, je construis mon graphe avec la bibliothèque Jung, et obtiens ma matrice d'adjacence ainsi:
SparseDoubleMatrix2D matrix = GraphMatrixOperations.graphToSparseMatrix(g);
SparseDoubleMatrix2D est un objet de la bibliothèque Colt du CERN. Cependant:
RWR.runRWR: begin.
RWR.runRWR: loading the graph.
RWR.runRWR: loading the LIRE index associated to the graph.
RWR.runRWR: loading the query image in a BufferedImage.
RWR.runRWR: search by similarity in the LIRE index.
RWR.runRWR: we search the vertex which is the NN in the graph.
RWR.runRWR: retrieve the indice of the image query for building the restart vector.
RWR.runRWR: preparing the RWR computing.
RWR.runRWR: the graph contains 49197 nodes, 144484 edges.
Exception in thread "main" java.lang.IllegalArgumentException: matrix too large
	at cern.colt.matrix.impl.AbstractMatrix2D.setUp(Unknown Source)
	at cern.colt.matrix.impl.AbstractMatrix2D.setUp(Unknown Source)
	at cern.colt.matrix.impl.SparseDoubleMatrix2D.<init>(Unknown Source)
	at cern.colt.matrix.impl.SparseDoubleMatrix2D.<init>(Unknown Source)
	at edu.uci.ics.jung.algorithms.GraphMatrixOperations.graphToSparseMatrix(GraphMatrixOperations.java:244)
	at edu.uci.ics.jung.algorithms.GraphMatrixOperations.graphToSparseMatrix(GraphMatrixOperations.java:223)
	at net.trevize.cbiaproto.dataformer.RWR.runRWR(RWR.java:155)
	at net.trevize.cbiaproto.dataformer.RWR.main(RWR.java:382)
Ce qui me parait assez étrange, le graphe fait environ 50.000 nœuds mais la matrice d'adjacence est très creuse, et la matrice demandée est sparse... Apparemment ce n'est pas un problème de mémoire. A propos de Colt: http://www.semiophore.net/v4/index.php?option=com_myblog&show=Extension-pour-librairie-Colt.html&Itemid=1&lang=en.
January 16th, 2009 @ 7:51pm | njames | Categories Java, XML/XSD | No Comments »
Voici une façon de le faire rapidement et proprement. Ici le but du jeu est de mettre à jour le contenu texte du nœud name (en lui appliquant un trim-plus-plus, version améliorée d'un String.trim()).
String file_path = dir_dataset_path + "/" + dir_path + "/" + file_name;
 
Document d = null;
try {
	d = dbfactory.newDocumentBuilder().parse(new InputSource(file_path));
} catch (SAXException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
} catch (ParserConfigurationException e) {
	e.printStackTrace();
}
NodeList nl = d.getElementsByTagName("name");
for (int i = 0; i < nl.getLength(); ++i) {
	Node n = nl.item(i);
	n.setTextContent(trimpp(n.getTextContent()));
}
Result result = new StreamResult(new File(file_path));
Source source = new DOMSource(d);
try {
	transformer.transform(source, result);
} catch (TransformerException e) {
	e.printStackTrace();
}
Mais cela reste du DOM, quand j'aurais le temps je garderai du côté de StAX ou WAX...
January 16th, 2009 @ 5:07pm | njames | Categories Java, XML/XSD | No Comments »
Pour écrire des scripts XQuery sous Eclipse, il n'y a pas pléthore de plugins pour apporter de l'autocomplétion, coloration syntaxique, et de la vérification de syntaxe.
  • DataDirect XQuery
  • XQDT
  • xqIde: coloration syntaxique, vérification de syntaxe, génération de xqDoc, et intégration avec la database Marklogic pour l'exécution de requête XQuery.
Bug avec XQDT: Si dans votre précédente session d'Eclipse, le Workbench contenait un ficher .xq ouvert, le prochain lancement d'Eclipse est bloqué par l'exception suivante:
Exception in thread "Thread-2" org.eclipse.swt.SWTException: Device is
disposed
at org.eclipse.swt.SWT.error(SWT.java:3777)
at org.eclipse.swt.SWT.error(SWT.java:3695)
at org.eclipse.swt.SWT.error(SWT.java:3666)
at org.eclipse.swt.widgets.Display.error(Display.java:1142)
at org.eclipse.swt.widgets.Display.wake(Display.java:4068)
at
org.eclipse.ui.application.WorkbenchAdvisor$1.run(WorkbenchAdvisor.java:797
)
Cette exception bloque complètement le chargement d'Eclipse. Si il n'y a pas de .xq d'ouvert dans la session précédente de Eclipse, il n'y a pas de problèmes, le plugin fonctionne correctement. Problème rencontré avec Java1.6, Ubuntu 8.04 Hardy Heron et Eclipse Ganymede for Java developer Linux GTK.
December 8th, 2008 @ 3:00pm | njames | Categories Desktop environment, Java | No Comments »
Pour faire des notifications Desktop depuis Java sur un système GNU/Linux:
  • Un moyen de faire est d'utiliser le TrayIcon introduit dans Java1.6 pour ajouter une icône de notification dans le System Tray (nommé notification area sous GNU/Linux, et Taskbar Status Area sous Windows), puis utiliser la méthode: TrayIcon.displayMessage(caption, text, TrayIcon.MessageType.INFO);. Cette approche a le mérite d'être multi-plateforme. voir http://java.sun.com/developer/technicalArticles/J2SE/Desktop/javase6/systemtray/
  • Utiliser libnotify:
    1. soit par un script python par exemple:
      #!/usr/bin/python
       
      from pynotify import *
      import sys
       
      def notify(title="", message=""):
      	n = Notification(title, message)
      	n.show()
      	#n.set_hint("x", 0)
      	#n.set_hint("y", 0)
       
      init("cli notify")
      if len(sys.argv)>2:
      	notify(sys.argv[1], sys.argv[2])
      else:
      	notify()
      voir http://roscidus.com/desktop/node/336.
    2. soit en utilisant une commande système avec notify-send (apportée par le paquet libnotify-bin sous Ubuntu).
Notes: pour changer le thème de libnotify, cela peut être fait directement dans le gconf-editor (apps > notification-daemon), la variable theme, par défaut à "ubuntu", peut être mise à "normal".
November 3rd, 2008 @ 4:49pm | njames | Categories Java | No Comments »
J'utilise beaucoup jconsole pour monitorer certaines de mes applications Java, notamment quand elles traitent beaucoup de données et consomment une proportion non négligeable de la RAM disponible sur la machine. Sur mon portable du boulot équipé d'un JDK 1.6.0_10-beta l'outil jconsole fonctionne parfaitement, mais sur ma machine perso équipée d'un JDK 1.6.0_10-rc, jconsole n'arrive pas à se connecter au process Java... Après installation d'une 1.6.0_10-beta à la place, et ça fonctionne... étrange...
November 1st, 2008 @ 1:58am | njames | Categories CBIR, Research, XML/XSD | No Comments »
J'investigue sur LabelMe, en ce moment sur les annotations faites manuellement et disponible sous la forme de fichiers XML générés par la toolbox MATLAB du projet. Ainsi je traite les documents XML, et un outil très pratique est http://www.hitsw.com/xml_utilites/ pour retrouver une grammaire XSD à partir d'une instance, c'est très pratique. Cela m'a permis d'obtenir une grammaire des annotations LabelMe, d'où la génération d'un XML-Binding et un (un)marshalling en Java.
October 31st, 2008 @ 3:41pm | njames | Categories Java, XML/XSD | No Comments »
Pour un petit projet j'ai intégré une grammaire XSD de DublinCore avec l'élément import dans une grammaire perso issue de mes travaux, imageLibrary.xsd.
A propos: une ressource documentaire très intéressante sur les XSD est: http://www.datypic.com/books/defxmlschema/chapter04.html.

Dans le cas présent, c'est une application Web de recherche d'imagette de livre depuis les AWS, Amazon Web Services, puis Ajout ou Retrait d'une imagette à un profil de lecture. Les imagettes sont stockées en local sur le serveur, et pour chaque profil je construis un fichier XML contenant les informations sur les imagettes (metadata physiques, i.e. location, size etc.) ainsi que les données relatives au document obtenues par les AWS et intégrées dans des éléments XML DublinCore (creator, title etc.).
Je génère des pages XHTML qui contiennent mes éléments DublinCore marshallés, il faut ainsi que JAXB génère des fragments XML et non un document XML complet.
Ainsi pour faire en sorte que JAXB ne génère pas l'instruction processing du document XML lors de l'opération de marshalling, il faut utiliser la propriété suivante:

m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
m étant un Marshaller.

Autre point: bien que j'ai spécifié que mon élément contenant mes données DublinCore comme élément du document XML, (i.e. il fait partie des éléments déclarés dans ma XSD), JAXB ne veut pas marshaller uniquement cet élément.
Une exception est levée disant qu'il manque l'annotation @XmlRootElement dans la classe de binding de cet élément. Ce post sur java.net en parle mais ne répond pas vraiment au problème.
Ajouter cette annotation à la classe de binding résout le problème mais l'élément étant déclaré dans ma XSD, cette modification ne devrait pas être nécessaire...
Cependant, pour Unmarshaller un fragment XML, on peut passer par un XMLStreamReader, et passer cet objet à l'unmarshaller (une rapide overview), on doit pouvoir en faire de même pour le marshalling.

October 22nd, 2008 @ 2:38pm | njames | Categories Research | No Comments »
Dans le cadre de mes travaux de thèse, je construis des graphes à l'aide de la bibliothèque Java Jung (la 1.7 cependant, pas la 2.x qui inclus les generics et encore en beta), et qui utilise Colt pour les opérations sur les matrices. Pour les formats de stockage des graphes, il existe de nombreux standards:
  • dot graphviz
  • GML, Graph Modelling Language, non XML
  • GML-XML
  • GraphML
Jung ne permet de sérialiser les graphes que dans le format GraphML, donc pas de Graphviz dot, c'est assez embêtant car les applications de visualisation de graphe prennent en entrée du Graphviz dot ou du GML, et assez rarement du GraphML. C'est un point de vue personnel, mais le GraphML est vraiment un format de stockage pour les graphes au sens type de donnée abstrait, comparé à Graphviz dot ou GML qui attaquent aussi directement le rendu du graphe. De plus, les détracteurs du GraphML peuvent dire que c'est du XML donc verbeux et coûteux en parsing mais GML n'est pas moins verbeux... Cependant, il est intéressant de convertir du GraphML en Graphviz dot, par exemple pour illustrer un article car il existe de nombreuses macros latex pour importer du Graphviz dot.
Pour la conversion de standard, par exemple convertir de GraphML vers Graphviz dot
  • avec graph-easy, un script perl, cependant j'ai un problème avec graph-easy, il semble qu'il n'aime pas les GraphML en input. Il imprime sur la sortie d'erreur mon fichier GraphML suivi de:

    not recognized by Graph::Easy::Parser::Graphviz at /usr/local/bin/graph-easy line 87
    En précisant le format d'entrée, ça ne fonctionne pas mieux:
    nicolas@trantor:~/Desktop$ graph-easy --from graphml graph.xml graph.dot
    Unknown input format 'graphml' at /usr/local/bin/graph-easy line 332.
  • graph-tool: Très long à compiler, comme indiqué sur la page d'accueil du projet. Si un prefix est précisé dans le configure, il faut modifier le script python graph-tool, car il ne trouve pas la library, alors ajouter dans le script:

    sys.path.append("../lib/python2.5/site-packages")
Visualisation
  • avec GraphViz:
    dot -Tps graph.dot -o graph.ps
Visualisation interactive
  • tulip, très intéressant celui là.
  • zgrviewer: voir http://zvtm.sourceforge.net/zgrviewer.html#download (mais bug sous linux, probablement à cause de la JVM et le forwarding sous X, j'avais vu une exception là dessus, mais j'arrive pas à la reproduire). Mais en le recompilant, ça fonctionne bien http://zvtm.sourceforge.net/zgrviewer/doc/build.html. Le problème vient probablement du bug dans Java 1.6 pour Linux à propos de Xlib/XCB qui a été corrigé depuis. Voir aussi
  • gephi
  • InfoVis cyberinfrastructure, ivc (s'appuie très largement sur Jung, je pense que ce n'est pas adapté aux large graphs).
  • InfoVis Toolkit, ivtk (INRIA futurs, LRI, IN-SITU project)
  • Walrus
  • Pajek
Remarques
  • visualiser des Graphviz dot avec une application web, http://ashitani.jp/gv/.
  • il existe un plugin Eclipse pour écrire des Graphviz dot, Graphviz Eclipse Plugin. Cependant la présence de ce plugin fait que les icônes de certains types d'images, dans l'arborescence d'un projet, sont remplacées par l'icône "fichier texte" (notamment les jpg et png)... un bug ?
July 31st, 2008 @ 3:44pm | njames | Categories GNU/Linux, Java, Web development | No Comments »
Mémo de l'installation sur mon serveur: Je ne veux pas installer les paquets tomcat-5.5, tomcat5.5-admin et tomcat5.5-webapps présent dans les dépôts Ubuntu. Car avec ces paquets:
  • le fichier de configuration du service tomcat est /etc/default/tomcat.
  • les fichiers server.xml et web.xml se trouvent dans /etc/tomcat, mais le reste des fichiers de configuration sont dans /var/lib/tomcat.
  • les webapps sont dans /var/lib/tomcat/webapps, mais l'application Tomcat se trouve dans /usr/share/tomcat.
  • on a un script de gestion du service /etc/init.d/tomcat.
Cette intégration dans le système peut être intéressante sous certains abords, mais je n'en ai pas l'utilité et puis, c'est surtout pas pratique du tout. Il est beaucoup plus propre d'installer manuellement un Tomcat dans /home/tomcat, et donc sur la partition /home du système sous l'utilisateur et le groupe www-data. Ainsi, ça ne pourri pas /usr, et de plus les applications Web à déployer peuvent être volumineuses, ou si une application Web écrit des données dans son webContent (le répertoire où elle est déployée), c'est pas très pro. sans doute, mais c'est pratique. Pour créer un service système pour un Tomcat installé manuellement, il suffit d'écrire un fichier /etc/init.d/tomcat tel que:
# Tomcat auto-start
#
# description: Auto-starts tomcat
# processname: tomcat
# pidfile: /var/run/tomcat.pid
 
export JAVA_HOME=/opt/jdk1.6.0_10
 
case "$1" in
start)
start-stop-daemon --start --chuid www-data:www-data --exec /home/tomcat/apache-tomcat-6.0.16/bin/startup.sh -- -d -r /home/tomcat/apache-tomcat-6.0.16/
;;
stop)
#start-stop-daemon --stop --exec /home/tomcat/apache-tomcat-6.0.16/bin/shutdown.sh
/home/tomcat/apache-tomcat-6.0.16/bin/shutdown.sh
;;
restart)
$0 stop
$0 start
;;
esac
exit 0
Il faut disposer les droits idoines sur le fichier:
chmod 755 /etc/init.d/tomcat
Puis l'ajouter aux scripts systèmes:
ln -s /etc/init.d/tomcat /etc/rc1.d/K99tomcat
ln -s /etc/init.d/tomcat /etc/rc2.d/S99tomcat
L'étape suivante pour une installation qui va bien, est d'utiliser le connecteur Tomcat jk_connector. Pour Apache, c'est le module mod_jk pour accéder à Tomcat depuis Apache, et ainsi l'abstraire du port 8080 pour accéder aux applications web déployées sous Tomcat. Ce qui en plus d'être plus simple et pratique dans l'écriture des URL, peut s'avérer nécessaire, par exemple si vous faites un appel à une servlet depuis un script PHP qui est lui, hébergé sur un autre serveur sur lequel la création d'une socket sur un port autre que 80 est interdit (par exemple, les serveurs de free.fr). Pour mod_jk, installer le paquet libapache2-mod-jk, et éditer le fichier /etc/apache2/mods-available/jk.load:
LoadModule jk_module /usr/lib/apache2/modules/mod_jk.so
JkLogFile /var/log/apache2/mod_jk.log
JkLogLevel debug
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
JkMount / worker1
JkMount /* worker1
Les JkMount sont les points de montages des applications Web que vous voulez monter. Editer ensuite le fichier /etc/apache2/workers.properties :
workers.tomcat_home=/home/tomcat/apache-tomcat-6.0.16
workers.java_home=/opt/jdk1.6.0_10
ps=/
worker.list=worker1
worker.worker1.port=8009
worker.worker1.host=localhost
worker.worker1.type=ajp13
worker.worker1.lbfactor=1
Il ne suffit plus qu'a redémarrer Apache. Cette configuration fonctionne bien, mais n'est pas sensitive aux sous-domaines éventuels de votre configuration d'Apache, ainsi http://trevize.net/Bouquinoscope et http://njames.trevize.net/Bouquinoscope pointe vers la même webapp Tomcat. Une solution assez simple est de créer un VirtualHost pour notre Tomcat, par exemple http://webapps.trevize.net, pour cela éditer le fichier worker.properties:
workers.tomcat_home=/home/tomcat/apache-tomcat-6.0.16
workers.java_home=/opt/jdk1.6.0_10
ps=/
worker.list=worker1
worker.webapps.port=8009
worker.webapps.host=localhost
worker.webapps.type=ajp13
worker.webapps.lbfactor=1
Commentez les points de montage JkMount indiqués précédemment dans /etc/apache2/mods-available/jk.load. Pour finir, il suffit d'ajouter le VirtualHost en éditant un fichier /etc/apache2/sites-available/webapps:
<VirtualHost *:80>
ServerAdmin nicolas.james@gmail.com
ServerName webapps.trevize.net
# Send servlet for context /servlets-examples to worker named worker1
JkMount /* worker1
# Send JSPs for context /jsp-examples to worker named worker1
JkMount /*.jsp worker1
</VirtualHost>
Il ne suffit plus qu'a monter le site avec a2ensite webapps, et redémarrer Apache. Configuré ainsi, Tomcat est accessible uniquement sur http://webapps.trevize.net. Pour que l'accès aux webapps sur le site soit plus eye-candy, un coup d'URL-rewriting avec le module rewrite pourra par exemple faire pointer http://trevize.net/Bouquinoscope vers http://webapps.trevize.net/Bouquinoscope.


 Valid XHTML 1.0 Transitional Valid CSS! WordPress