Install and use tesseract on iOS with tesseract-ios

Update 10/10/12

I updated tesseract-ios-lib with a (fake) armv7s slice. There is no need to remove armv7s from build architectures anymore. More informations about this change on my previous post.

Introduction

In my last article about how to compile tesseract for iOS SDK 6, I quickly posted two links to my github repos:

Some comments complained about the lack of guide to install and use this wrapper. I’m going to show you how to build a new iOS project with tesseract, from scratch.

(more…)

Compile tesseract for iOS SDK 6.0

Update 10/25/12

Added instructions to integrate an armv7s slice in liblept.a and libtesseract_all.a.

Update 09/24/12

To make the iOS integration easier, I made a Github repo containing an Objective-C wrapper for Tesseract. It relies on an other repo containing tesseract & leptonica libs. Feel free to improve them !

More informations about these repos on my next article.

Introduction

I had troubles while following the compiling guide from this blog: http://tinsuke.wordpress.com/2011/11/01/how-to-compile-and-use-tesseract-3-01-on-ios-sdk-5/. Some dependencies are missing on a fresh Mountain Lion with Xcode 4.5, and more importantly: the build_dependencies.sh won’t work.

Here is why: Xcode 4.5 and iOS SDK 6.0 don’t support armv6 anymore.

So here are the steps to build tesseract-ocr for iOS SDK 6.0.

(more…)

Watch TV on Raspberry Pi with OpenELEC media-build

I’m using an Elgato EyeTV DTT to watch TV on my Macbook Pro. I wanted to use this USB tuner on my Rasperry Pi with Raspbian, but VLC doesn’t support hardware-accelerated video yet. So I found this post on Tiago Pires’ blog, which describes how to build OpenElec from scratch including media-build. Unfortunately, some things are missing in this post, and some others are unnecessary. A lot of things in this post comes from his article, so thank you ;)

Media-build is just a script that will get the most up-to-date dvb drivers and include them in OpenElec. I don’t think it’s required if your DVB tuner is supported for a longtime by Linux, but let’s include it anyway.

(more…)

django-wkhtmltopdf on a linux (Webfaction) server

Generating PDF with python is not an easy thing. Here is what I’ve tried:

  • xhtml2pdf: the worst. It has a very bad CSS interpreter and it is pretty impossible to make a clean PDF out from a complex html page.
  • WeasyPrint: that’s better. It has its own HTML and CSS2 interpreters, and despite some minor issues it is fairly reliable. However it requires some big dependencies, and I eventually had some memory issues on my webserver.
  • wkhtmltopdf with its Django wrapper: for now, the best. It makes use of Webkit to render HTML+CSS+JS(!) pages, I don’t think you can do better. However, it requires QT, and this is big. Well, not the “classical” QT, a patched QT (that’s even worse) that allows to run without an X server. This is what I’m using for now in my projects

We’ll see here how to build wkhtmltopdf and a basic django-wkhtmltopdf usage. These steps has been tested on a Webfaction server (CentOS 6) through SSH.

(more…)

Python – Install WeasyPrint on a linux (Webfaction) server

WeasyPrint is a great python library to generate PDFs from HTML. It beats hands down xhtml2pdf, by interpreting CSS and HTML the right way.

However, it has a lot of dependencies and it just can’t fit in a simple python virtual environment. It took me a whole day to install on Webfaction, so I think it would be helpful to show how to do it properly.

These steps has been tested on a Webfaction CentOS 6 server (python2.7), and they should be the same for others Linux systems. If your system is not exactly the same, you might have to install other dependencies manually. Linux From Scratch is your helpful friend in this kind of situation.

(more…)

Django – UnicodeDecodeError using i18n

If you’re using i18n in your django website, you may encounter this issue. It took me two hours to find where the problem came from: you have to use ugettext instead of gettext if your translated strings contains non-ascii characters.

(more…)

Django – Absolute media URIs from templates

Sometimes, you need to build an absolute URI to a media file from your templates:

1
http://example.com/media/sample.jpg

After following this small tutorial, you’ll be able to do this:

1
2
{% load mytemplatetags %}
{{ media_name|absolute_media_url:request }}

(more…)

MantisBT et PHPMailer: problème avec l’envoi de mails

Je me suis retrouvé récemment face à un problème assez facheux. MantisBT, un logiciel de tracking de bugs, n’envoyait plus de mail. Que ce soit lors d’un ajout de bug ou lors de la procédure de réinitialisation du mot de passe: rien, nada. Pourtant, MantisBT affirmait que le mail était envoyé.

Un petit coup d’oeil dans le fichier core/email_api.php permet de voir que Mantis prend en compte les erreurs de PHPMailer via les try/catch suivants:

1
2
3
4
5
6
7
8
9
10
// Insertion du mail dans la BDD
try
{
  // Envoi du mail
  // Suppression du mail dans la BDD
}
catch ( phpmailerException $e )
{
  // Rien
}

Mais vous l’avez bien compris, MantisBT ne génère pas de message d’erreur (ni de log) si l’envoi du mail n’est pas correctement effectué. Par contre, il laisse le mail dans la BDD pour qu’il puisse être envoyé dès que le système marche à nouveau (voir core/email_queue_api.php).

Pour débugger mon affaire, j’ai donc du insérer une petite ligne de code juste après le catch:

1
echo $e->getMessage();

Et là, bingo: Could not instantiate mail function.

Pourtant, j’avais bien vérifié que la fonction mail fonctionnait correctement avec un petit if (mail("toto@test.com", "sujet", "message")) echo "ok";. Chose que je ne savais pas: si PHP est en safe_mode, la fonction mail() est amputée d’un argument:

Fonctions désactivées par le Safe Mode:
mail(): Si le Safe Mode est actif, le 5ème paramètre est désactivé (note : uniquement affecté depuis PHP 4.2.3)

Super.

Il faut donc vérifier que safe_mode = On dans php.ini pour que tout ça marche. Autre solution si votre hébergeur ne vous permet pas d’accéder au fichier de configuration, ajouter php_flag safe_mode off dans votre .htaccess.

Cela montre encore une fois que PHP est totalement imprévisible. Il y a tellement d’endroits où l’on peut écraser les paramètres d’une configuration que l’on ne peut savoir si telle ou telle fonction va marcher. Mais bon, problème résolu !

Bloquer ou monitorer AJAX à partir d’un script GreaseMonkey (ou Userscript)

Facebook a récemment ajouté une fonctionnalité qui m’est très désagréable: la notification de la lecture des messages à l’expéditeur. Impossible dès lors d’ignorer un message instantané sans que la personne le sache, or c’est un droit immuable qui devrait être inscrit au burin dans la roche des droits de l’homme.

Modification de XMLHttpRequest

Pour empêcher ces notifications, il faut empêcher l’envoi de données vers http(s)://www.facebook.com/ajax/mercury/change_read_status.php à partir d’un script Greasemonkey. Le principe du blocage consiste en la modification de l’objet XMLHttpRequest pour que la méthode open n’autorise pas l’ouverture du socket vers la page en question:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// On sauvegarde la méthode open originale
window.XMLHttpRequest.prototype.trueOpen = window.XMLHttpRequest.prototype.open;

// On modifie la méthode open avec la notre
window.XMLHttpRequest.prototype.open = function() {
   
  // Du code pour bloquer ou logger ce qui se passe
  // On peut notamment regarder ce qu'il y a dans arguments
  // pour bloquer: return;

  // Si on ne souhaite pas bloquer l'ouverture du socket,
  // on fait appel à la méthode originale
  this.trueOpen.apply(this, arguments);
};

Vous pouvez ainsi intercepter chaque appel aux méthodes de XMLHttpRequest, et les bloquer ou les rerouter à votre guise. Pour la liste complète des méthodes en question, je vous invite à consulter sa documentation W3C.

Dans le cas d’un blocage (pas d’appel à trueOpen), voici ce qu’il va se passer du côté de la page monitorée:

1
2
3
4
5
6
// Instanciation normale de notre objet
var xhr = new XMLHttpRequest();
// Rien ne se passe, l'instance de xhr n'est pas modifiée et le socket n'est pas ouvert
xhr.open("get", "page_bloquee.html?param=1", true);
// Le send échoue car le socket n'est pas ouvert
xhr.send()

L’appel à xhr.send ne provoque aucune erreur, du moins sous Chrome.

Le script Greasemonkey

Le script abordé précédemment suppose que vous soyez dans le scope de la page dont vous souhaitez monitorer les appels AJAX. Ce n’est pas le cas pour les scripts GreaseMonkey. Comme expliqué très judicieusement dans ce post sur StackOverflow, Firefox et Chrome exécutent ces scripts dans une sandbox qui ne permet pas d’accéder à l’environnement javascript de la page concernée.

Néanmoins, il existe une méthode assez simple pour sortir de cette sandbox: injecter un élément script dans la page en question qui exécutera le code de notre choix.

1
2
3
4
5
6
7
8
9
function main() {
  // Notre code précédent
}

// On crée un élément <script></script> et on l'injecte dans la page à contrôler
// Dans cet élément, on copie la fonction main afin qu'elle soit exécutée
var script = document.createElement("script");
script.textContent = "(" + main.toString() + ")();";
document.body.appendChild(script);

Le code final

1
2
3
4
5
6
7
8
9
10
11
12
function main() {
  window.XMLHttpRequest.prototype.trueOpen = window.XMLHttpRequest.prototype.open;

  window.XMLHttpRequest.prototype.open = function() {
    // ...
    // this.trueOpen.apply(this, arguments);
  };
}

var script = document.createElement("script");
script.textContent = "(" + main.toString() + ")();";
document.body.appendChild(script);

En ce qui concerne le blocage de la notification facebook, voici facebook-read-status-disabler. Il est également à noter que ce monitoring ne fonctionnera pas avec Internet Explorer car celui-ci utilise un autre objet pour les requêtes AJAX. Un script plus complet est disponible sur github: AJAX Calls Intercepter, avec notamment la prise en compte d’Internet Explorer.

Un PDF à l’image de votre CV en ligne avec wkpdf

Tout comme il est intéressant pour un employeur d’avoir accès au CV en ligne d’une potentielle nouvelle recrue, il est également pratique de pouvoir imprimer ce CV dans un format qui convient.

La génération automatique d’un PDF associé au contenu de votre site présente plusieurs avantages:

  • Le PDF est constamment à jour du contenu de votre site
  • Le PDF adopte le design de votre site
  • C’est totalement la classe

Voici donc un petit aperçu hautement égocentré de ce que vous pourrez faire:

       

Comme vous l’aurez remarqué, divers détails graphiques comme l’arrière-plan gris ou le ruban bleu ont été effacés afin de proposer une version épurée prête à l’impression.

Pour parvenir à ce résultat, nous allons utiliser un petit logiciel nommé wkpdf associé à une feuille de style spéciale.

La feuille de style

Depuis la version 4 de la norme HTML, il est possible d’inclure une feuille de style en précisant le type de périphérique auquel elle est adressée. On peut ainsi inclure une une feuille de style spécifique aux télévisions:

1
<link rel="stylesheet" media="tv" href="css/tv.css" />

Il est même possible depuis la version 2 de la norme CSS de déclarer des règles spécifiques à un media directement dans votre feuille de style principale:

1
2
3
4
5
6
7
/* Avec @import */
@import url("tv.css") tv;

/* Ou avec @media */
@media print {
  /* Règles spécifiques */
}

Voici la liste des valeurs de l’attribut media:


1
2
3
4
5
6
7
8
9
10
all         Suitable for all devices.
braille     Intended for braille tactile feedback devices.
embossed    Intended for paged braille printers.
handheld    Intended for handheld devices (typically small screen, limited bandwidth).
print       Intended for paged material and for documents viewed on screen in print preview mode.
projection  Intended for projected presentations, for example projectors.
screen      Intended primarily for color computer screens.
speech      Intended for speech synthesizers.
tty         Intended for media using a fixed-pitch character grid (such as teletypes, terminals, or portable devices with limited display capabilities).
tv          Intended for television-type devices (low resolution, color, limited-scrollability screens, sound available).

Il est à noter que si vous ne précisez pas de media, la valeur de l’attribut est “all” (pour tous les périphériques).
Nous voyons ici que la valeur “print” permet de personnaliser un document destiné à être imprimé, c’est donc celui-ci que nous allons utiliser:

1
<link rel="stylesheet" media="print" href="css/print.css" />

Dans cette feuille de style, supprimons tout ce qui n’est plus nécessaire, par exemple:

1
2
3
4
5
6
7
8
9
/* Suppression d'un élément inutile */
.classe-de-l-element {
  display:none;
}

/* Suppression de l'arrière plan */
body {
  background: none;
}

Vous pouvez tester ces nouvelles règles en modifiant temporairement l’attribut media de “print” à “all”.

Génération du PDF

Nous allons utiliser wkpdf pour générer notre fichier. Malheureusement ce dernier n’est disponible que sur Mac, mais il existe une alternative multiplateforme, wkhtmltopdf, qui semble fonctionner sur le même principe.

Ces logiciel a un énorme avantage: au lieu de posséder son propre moteur d’interprétation de la structure HTML, il utilise le fameux Webkit (le moteur de rendu de Chrome et Safari, notamment). Le rendu sera donc fidèle à ce que vous pourrez voir dans un navigateur web conventionnel.

Il vous suffit donc d’exécuter wkpdf en ligne de commande:


1
$ wkpdf --source http://monsite.com/ --output cv.pdf --margins 0 --stylesheet-media print --print-background

De plus, si votre site met en place des éléments graphiques à l’aide de Javascript, ajoutez les arguments suivants:


1
--enable-javascript --save-delay [temps_avant_capture_en_secondes]

Vous devriez ainsi obtenir un beau PDF prêt à l’emploi. Il vous faudra sûrement adapter certaines règles CSS pour que tout tienne sur une page, etc…

Bonus: impression directe à partir du site

La feuille de style “media=print” sert également à votre navigateur lors de l’impression d’une page. Néanmoins, certaines limitations sont mises en place par la plupart des navigateurs:

  • Les arrières-plans ne sont pas pris en compte. background-color et background-image ne fonctionneront donc pas.
  • Le Javascript n’est pas pris en charge, aucune modification ne pourra être faite dynamiquement avant l’impression.

Note concernant le comportement des navigateurs lors de l’impression:

  • Aucune référence ou documentation n’est disponible à ce sujet, du moins pour le moment
  • Dans certaines versions de Firefox, et sous certains systèmes d’exploitation, il est possible d’activer la prise en charge des arrière-plans (couleur et image) ainsi que le Javascript. Là encore, aucune documentation.
  • Internet Explorer propose un event onbeforeprint permettant de modifier le DOM lorsque le navigateur s’apprête à imprimer. Plus d’informations par ici.

Si vous avez des renseignements supplémentaires concernant les différents comportements adoptés par les navigateurs, n’hésitez pas à m’en informer !

Toute l’astuce consistera donc à remplacer les arrières plans par des images (qui elles seront affichées), ou de tenter de mettre en place une sorte de “graceful degradation” afin de simuler certains éléments graphiques. Par exemple, les barres de compétences mises en place sur mon CV ne sont pas pleines lors de leur impression, j’ai donc dû ajouter un border-color pour symboliser les limites de ces dernières.

Et après ?

On peut maintenant aisément imaginer un système qui génèrerait automatiquement votre PDF à chaque modification du site web. Si vous utilisez un système de versioning, aucun soucis. Je vous invite à chercher du côté de pre-commit si vous gérez tout ça avec svn ou git. Il vous suffira de modifier ces hooks en insérant la commande de génération, et d’ajouter au commit le fichier PDF ainsi généré.