Basculer le décodage des codes-barres de ZXing.Net vers zbar

L'ISBN 9782846391009 n'était pas décodé par l'application, alors qu'il
l'était par une application d'essai utilisant zbar, sur le même livre et
le même appareil.

⚠️ Le raisonnement qui avait écarté cette piste était faux : CLAUDE.md
concluait que « le décodeur n'y est pour rien » à partir de mesures de
VITESSE (4-6 ms/frame). La vitesse ne dit rien du taux de réussite.

Le décodage quitte donc le C# pour zbar compilé en WebAssembly, dont les
assets viennent du paquet ZBar.Blazor.

Ce que la bascule apporte, au-delà du code lu :
- plus aucun pixel ne traverse le pont JS→C# (un byte[] par frame avant),
  seule la valeur décodée le fait ;
- l'image ENTIÈRE est analysée, à 960 px, là où l'ancienne version
  recadrait sur la bande centrale à 640 px pour alléger ce transfert —
  c'était la seconde cause possible des codes non lus, elle disparaît ;
- zbar.wasm est chargé À LA DEMANDE, à la première ouverture du scanner.

⚠️ Le composant ZBarCamera du paquet n'est PAS utilisé : il ouvre la
caméra lui-même et avale les erreurs. On y perdrait les messages qui
distinguent permission refusée, absence de caméra, caméra occupée et
contexte non sécurisé, ainsi que facingMode environment (caméra arrière)
et l'indication de résolution. Seuls zbar.js et zbar.wasm sont empruntés.

Poids, comparaison de deux publish Release complets (somme brotli) :
  _framework  3 281 558 → 2 978 700 o   (−296 Kio au démarrage)
  total       3 281 558 → 3 125 541 o   (−152 Kio)
L'écart vient de la traîne que ZXing imposait au trimmer :
System.Text.RegularExpressions retombe de 98 374 à 7 137 o, et
System.Runtime.Numerics disparaît.

⚠️ Coût assumé : six tests de décodage disparaissent avec IsbnScanner,
le décodeur n'étant plus en C#. Le décodage a été vérifié dans le
navigateur sur un EAN-13 rendu en canvas — 9782846391009 ressort bien en
ZBAR_EAN13 — mais cela reste une vérification, pas un garde-fou.
À confirmer avec le livre en main.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mathieu
2026-08-19 00:51:56 +02:00
co-authored by Claude Opus 5
parent 718df2c986
commit 278d6579f7
8 changed files with 269 additions and 438 deletions
+72 -123
View File
@@ -59,101 +59,22 @@ ce qui suit est la matière brute, classée par sujet, avec ce que le diagnostic
### Le scan caméra rate souvent sur ordinateur
**La douchette USB est faite** (voir `CLAUDE.md`, « La douchette USB est le vrai remède ») :
champ focalisé à l'ouverture, validation sur `Entrée`. Reste à confirmer en usage réel qu'elle
suffit.
**Deux remèdes appliqués**, tous deux dans `CLAUDE.md` : la **douchette USB** (champ focalisé,
validation sur `Entrée`) et surtout la **bascule de ZXing.Net vers zbar** — c'était bien le
décodeur, contrairement à ce qu'on avait conclu de mesures de vitesse.
Si elle ne suffit pas, pistes non traitées : choisir la caméra quand il y en a plusieurs,
demander une résolution plus haute, exposer un curseur de zoom/torche là où l'API le permet,
et laisser **déposer une photo** du code-barres à décoder (ZXing lit un fichier aussi bien
qu'une frame).
Reste à confirmer en usage réel. Si cela ne suffisait toujours pas : choisir la caméra quand il
y en a plusieurs, exposer un curseur de zoom/torche là où l'API le permet, et laisser **déposer
une photo** du code-barres à décoder.
### ISBN `9782846391009` : le scan n'aboutit pas
### ISBN `9782846391009` : résolu — c'était le décodeur
**La donnée existe pourtant côté BnF** — vérifié le 2026-08-18 :
Le livre existe bien à la BnF : l'échec était **au décodage de l'image**. Confirmé le
2026-08-19 — zbar lit ce code-barres, ZXing.Net ne le lisait pas, sur le même appareil et le
même livre. La bascule est faite (voir `CLAUDE.md`).
```
bib.isbn all "9782846391009" → 1 notice
dc:title = La thérapie émotivo-rationnelle / Albert Ellis et Robert A. Harper
dc:creator = Ellis, Albert (1913-2007). Auteur du texte
dc:creator = Harper, Robert A. (1915-2004). Auteur du texte
(la forme ISBN-10 « 2846391009 » ne renvoie rien : ici c'est bien l'ISBN-13 qui indexe)
```
L'échec est donc **au décodage de l'image**, pas au lookup. Rejoint le point ci-dessus.
⚠️ À reproduire en saisissant l'ISBN à la main avant de conclure : si la saisie manuelle échoue
aussi, le défaut est ailleurs et ce diagnostic tombe.
## Choix de la bibliothèque de lecture de code-barres — à trancher
**Constat qui rouvre le sujet, 2026-08-19.** L'ISBN `9782846391009` n'est pas décodé par
l'application, alors qu'il l'est par une application d'essai (`~/Code/TestBarcode`) sur le
**même appareil et le même livre**, avec **ZBar**.
⚠️ **Le raisonnement qui écartait ce sujet était faux.** `CLAUDE.md` conclut que « le décodeur
n'y est pour rien » à partir de mesures de **vitesse** (4-6 ms/frame en WASM interprété). Or la
vitesse ne dit **rien du taux de réussite** : un décodeur peut être rapide et rater. Les mesures
existantes ne pouvaient donc pas soutenir cette conclusion, et l'essai la contredit.
### Ce que l'essai établit, et ce qu'il n'établit pas
**Établi** : ZBar lit ce code-barres, ZXing.Net (portage C#) ne le lit pas, dans les mêmes
conditions physiques.
**Non établi** : que le moteur soit seul en cause. Notre implémentation ne fait pas que décoder,
elle **prétraite** — réduction à 640 px de large, puis **recadrage sur la bande centrale**
(`PartHauteur = 0,45`). ZBar, lui, analyse l'image entière. Deux causes candidates cohabitent
donc, et l'essai ne les sépare pas :
1. le moteur (ZXing.Net est un portage d'une version ancienne de ZXing, réputé moins robuste que
`zbar` ou que `zxing-js`) ;
2. notre prétraitement (bande trop étroite, ou résolution insuffisante pour la largeur de module
à la distance de prise de vue).
Adopter ZBar rendrait la seconde question sans objet : le composant gère lui-même la caméra et
l'image.
### Le poids : mesuré, et à l'inverse de ce qu'on croyait
Somme brotli réelle du publish `Release` de l'application d'essai :
| Fichier | brotli |
|---|---|
| `zbar.wasm` (moteur C compilé) | 138 938 o |
| `ZBar.Blazor.<empreinte>.wasm` (assembly .NET) | 21 232 o |
| `zbar.js` | 5 247 o |
| `camera.js` + `image.js` + `scanner.js` | 2 457 o |
| CSS isolé | 199 o |
| **Total ZBar** | **≈ 168 Ko** |
À comparer au coût de ZXing.Net **déjà documenté dans `CLAUDE.md`** : **≈ 346 Ko brotli**, dont
seulement 192 Ko d'assembly — le reste étant les assemblies BCL que le trimmer ne peut plus
retirer (`System.Text.RegularExpressions` passant de 7 à 98 Ko parce que ZXing utilise Regex,
plus `System.Runtime.Numerics`).
Vérifié dans le publish d'essai : `System.Text.RegularExpressions` y pèse **7 137 o**, et
`System.Runtime.Numerics` est **absent**. ZBar ne traîne pas cette queue.
**Le remplacement allégerait donc l'application d'environ 180 Ko brotli**, au lieu de l'alourdir.
⚠️ Chiffre à confirmer par une comparaison de deux publish de *notre* application, comme l'a été
celui de ZXing.Net : le coût d'une bibliothèque n'est pas le poids de son assembly.
### Ce qu'on perdrait
- **Le décodage quitte le C#.** C'est l'argument qui avait fait retenir ZXing.Net : « réutilisable
hors navigateur si le projet évolue en scanner de bibliothèque ». Cet usage est **hypothétique
et n'a jamais été exercé** ; il se paie aujourd'hui en codes-barres non lus.
- **`IsbnScanner`, `BancEssaiScan`, `ScannerCodeBarres` et `wwwroot/js/scanner-camera.js`**
disparaîtraient au profit du composant `ZBarCamera`.
- **Une dépendance jeune** : `ZBar.Blazor` 1.1.0. À regarder avant de s'engager (maintenance,
licence, taille de la communauté).
### Ce qu'on gagnerait, au-delà du code lu
- **Le format est remonté** (`ISBN_13` vs `EAN_13`), là où nous le déduisons du préfixe.
- **Les add-ons EAN-5 (prix) et EAN-2 (numéro) sont décodés** et rattachables au code principal —
l'EAN-2 est précisément ce qui accompagne les périodiques en `977`.
- **Plus de pipeline image maison** à entretenir (capture, réduction, recadrage, `RGBLuminanceSource`).
⚠️ **À confirmer avec le livre en main** : la vérification faite jusqu'ici porte sur un EAN-13
rendu en canvas, pas sur une image de caméra.
---
@@ -181,28 +102,23 @@ quand même ? »), plutôt que l'index unique qui interdirait le second exemplai
d'envies, elle, refuse — mais elle décrit une envie, pas un objet, et deux exemplaires d'une
envie n'ont pas de sens.
## À l'ajout d'un livre, retirer l'envie correspondante
## À l'ajout d'un livre, signaler l'envie correspondante
Demandé : si le livre ajouté figure dans la liste d'envies, l'en retirer.
**Décidé le 2026-08-19 : on ne supprime rien, on signale.** La liste d'envies marque l'entrée
« déjà au catalogue ».
⚠️ **La difficulté est la portée, pas le rapprochement.** Le catalogue est **commun**, la liste
d'envies est **personnelle** — ce sont les deux portées que `CLAUDE.md` oppose explicitement.
« Retirer l'envie » n'a donc pas une seule réponse :
Pourquoi pas la suppression, qui était la demande initiale :
- **la sienne uniquement** : simple, sûr, ne franchit aucune frontière. Mais si Camille souhaitait
le livre et que Mathieu l'ajoute, Camille garde une envie pour un livre que le foyer possède.
- **celle de tout le monde** : cohérent avec « le livre est commun », mais **modifie
silencieusement la liste d'un autre**, et lui fait perdre sa note (« demandé à Noël »). L'API
ne sait pas — délibérément — écrire dans la liste d'autrui : ce serait une brèche à ouvrir
dans un invariant tenu jusqu'ici.
- **ne rien supprimer, mais signaler** : la liste d'envies marque l'entrée « déjà au catalogue ».
Non destructif, respecte la frontière, et l'écran de bibliographie sait déjà distinguer
`Possede` de `Souhaite`.
- le catalogue est **commun**, la liste d'envies **personnelle**. Supprimer l'envie d'un autre
modifierait sa liste en silence et lui ferait perdre sa note (« demandé à Noël ») ; l'API ne
sait pas — délibérément — écrire dans la liste d'autrui, et l'ouvrir serait une brèche dans un
invariant tenu partout ailleurs ;
- le rapprochement se fait par `CleOeuvre` + auteur, donc **faillible** (titre retraduit, tome,
intégrale — voir `CLAUDE.md`). Une suppression fondée sur un rapprochement faux est
irréversible ; un signalement se corrige d'un coup d'œil.
⚠️ Le rapprochement se ferait par `CleOeuvre` + auteur, avec les mêmes limites que la
bibliographie (titre retraduit, tome, intégrale — voir `CLAUDE.md`). Une suppression sur un
rapprochement faillible est **irréversible** ; un signalement ne l'est pas. C'est un argument de
poids pour la troisième voie.
Reste à implémenter : le marquage dans `SouhaitDto`, calculé comme l'est déjà `Possede` dans la
bibliographie, et son rendu sur l'écran des envies.
## Bandes dessinées et magazines
@@ -222,24 +138,57 @@ rien.
Champs propres à la BD (série, tome, scénariste/dessinateur) : à ne faire que si le besoin se
confirme. Le modèle actuel met tous les auteurs dans `LivreAuteur` sans distinguer les rôles.
### Les magazines : cela rouvre une décision actée
### Les magazines : une fiche par revue, les numéros à l'intérieur
⚠️ `CLAUDE.md` (lot 1) écarte **délibérément** le catalogage des périodiques : « le modèle de
données n'a ni numéro ni date de parution, et les deux chiffres de parution du code ne sont pas
exploitables comme numéro fiable — douze numéros d'un même magazine partagent leur ISSN et
créeraient douze fiches identiques ». Le scan d'un code `977` nomme donc la revue et bascule sur
la saisie manuelle, **sans** l'ISBN.
⚠️ Rouvre la décision du lot 1, qui écartait le catalogage des périodiques faute de modèle.
Le modèle est maintenant choisi.
Les supporter vraiment demande de lever exactement ce qui avait motivé le refus :
**Décidé le 2026-08-19 : une fiche par REVUE**, et dans sa page, la sélection d'un numéro
précis. C'est exactement ce qui évite le défaut redouté — douze numéros d'un même magazine ne
font plus douze fiches identiques, puisqu'ils partagent la fiche de leur revue.
- un **ISSN** distinct de l'ISBN (le ranger dans `Livre.Isbn` casserait tout lookup ultérieur) ;
- un **numéro** et une **date de parution**, seuls capables de distinguer deux exemplaires ;
- de décider si un magazine est **une fiche par numéro** ou **une fiche par revue avec des
numéros rattachés** — c'est le vrai choix de modélisation, et il change la migration ;
- de reprendre le flux `977` pour qu'il crée au lieu d'expliquer.
Ce que cela demande :
À trancher avant tout code. Le reste (filtres, prêts, hors-ligne) suit mécaniquement une fois le
modèle arrêté.
- un **ISSN** sur la fiche de revue, distinct de l'ISBN. ⚠️ Ranger un code `977` dans
`Livre.Isbn` casserait tout lookup ultérieur sur cette fiche ;
- une table de **numéros** rattachés à la revue, portant au minimum un numéro et une date de
parution ;
- reprendre le flux `977` : il nomme aujourd'hui la revue et bascule sur la saisie manuelle, il
devra créer ou compléter la fiche puis proposer d'ajouter le numéro scanné. ⚠️ Les deux
chiffres de parution du code-barres **ne sont pas un numéro fiable** ; l'add-on **EAN-2**, que
zbar sait maintenant décoder, est le bon candidat — à vérifier sur des magazines réels ;
- décider ce qu'un **prêt** signifie pour une revue : on prête un numéro, pas un abonnement.
## Sagas et cycles : plusieurs livres, un ordre de lecture
Demandé le 2026-08-19. Cas donné : [Drizzt Do'Urden](https://fr.wikipedia.org/wiki/Drizzt_Do%27Urden)
**plusieurs regroupements de plusieurs livres, à lire dans un ordre précis**. Vaut pour les
romans comme pour les BD.
C'est la première demande du projet qui porte sur une **relation entre livres** plutôt que sur
un livre. Ce que le cas Drizzt impose, et qu'un simple champ « série » ne couvrirait pas :
- **Deux niveaux.** *La Légende de Drizzt* regroupe plusieurs trilogies (*L'Elfe noir*,
*La Séquence de l'Icewind Dale*…) : un cycle contient des séries, qui contiennent des tomes.
Un champ texte plat perdrait ce regroupement.
- **L'ordre de lecture n'est pas l'ordre de publication.** *L'Elfe noir* est une préquelle écrite
après. C'est précisément l'information qu'on vient chercher : elle doit être **stockée**, pas
déduite de l'année.
- **Un livre peut appartenir à plusieurs regroupements** (une intégrale, une série, un cycle).
- **Ce qu'on possède est partiel.** L'intérêt de l'écran est de montrer les trous — « il vous
manque le tome 3 » — comme la bibliographie montre déjà ce qui manque d'un auteur.
Questions à trancher avant tout modèle :
- **D'où viennent les séries ?** La BnF ne les expose pas de façon exploitable en Dublin Core.
Saisie à la main, déduction depuis le titre (« Tome 3 »), ou source tierce ?
- **Portée** : commune au foyer, comme le catalogue, ou personnelle ? L'ordre de lecture est une
propriété de l'œuvre et non du lecteur — donc commune, a priori.
- **Les tomes non possédés** existent-ils en base, ou sont-ils seulement affichés ? S'ils
existent, ils ressemblent beaucoup à des envies, et il faudra dire comment les deux cohabitent.
⚠️ Ne pas confondre avec le regroupement d'œuvres de la bibliographie (`CleOeuvre`), qui réunit
les **rééditions d'un même titre**. Ici, ce sont des titres **différents** qui se suivent.
## Auteurs et bibliographie