On the Android app, adding an item to a catalog does not have to mean typing its numbers. Scan barcode looks the product up on Open Food Facts; Read the label photographs its Nutrition Facts table and reads the text on the phone. Either one fills the same item form a person would have typed into — the name, the serving line and each value — and nothing is saved until they check it against the package and press Save, or Use it in the log dialog. Every scan says what it did and asks for that check.
One result, two readers
Each reader turns its input into a printed label (PrintedLabel): the item’s name if known, the serving its numbers are printed per (“2 cookies”, 34 g), and rows of a printed name, an amount and a unit (“Fat”, 3, “g”). One generic step then fills the form from it (fillFromLabel): the serving becomes the serving line, and each row that names one of the catalog’s number fields becomes that field’s value. A row is used only in a unit its field can be typed in, so a number is never read in the wrong unit; a field the label does not mention stays blank, which is unknown.
The names are catalog data. A catalog’s field can list the names a label prints for it (printed): Carbs answers to “Carbohydrate” and “Glucides”, Calories to “Energy” and “Énergie”. A row matches a field by those names, then by its label and its name, compared without case, accents, punctuation or a plural s; a bilingual row (“Fat / Lipides”) matches on either name, and the first row to name a field wins, so “Fat” is not taken by a later “Saturated fat”. The Food catalog carries English and French names. Nothing in the matching is about food, so any catalog with a printed table reads the same way; the readers themselves are adapters for an outside format.
The serving line is read from what is printed: “Per 2 cookies (34 g)”, “Serving size 2/3 cup (55g)”, “½ cup (125 mL)”, and the other way round, “Per 75 mL (1 bar)”, where the measure comes first and the thing in brackets. A bilingual line is read in its first language.
The barcode reader
The phone’s code scanner returns the code (EAN-13, EAN-8, UPC-A, UPC-E), and the app fetches the product from Open Food Facts: free, open data that answers a request from the app’s own page, so the lookup is a plain fetch and the barcode is the only thing that leaves the phone. The product becomes a printed label:
- per its serving when the product names one with a weight, with the weight put back on the line where Open Food Facts keeps it apart (“1 biscuit”, 32 g);
- per one piece of a multipack with no serving (“12 x 75 ml” is a piece of 75 ml);
- otherwise per 100 g, or per 100 ml when the package is measured in ml;
- named in English first, since a Canadian product’s main name is often its French one, with the brand in front when the English name leaves it off (“Eggo Original”).
A scanned item remembers its barcode (catalog_entity.barcode, stored as one spelling: a UPC-A as the EAN-13 it also is), so the next scan of the same product picks it from the catalog with no lookup. A saved item is preferred over a one-off with the same code. In the log’s food picker, Scan barcode picks a saved item or opens the item form filled from the lookup.
The photo reader
The phone’s document scanner takes one page (from the camera or the gallery), and on-device text recognition returns each line and word with its box. Text recognition returns a table’s names and amounts as separate lines, so the reader rebuilds rows from lines at one height, reads a row as a name then its first amount, ignores the % Daily Value after it, reads an O before a unit as 0, and takes the serving from the first line that starts “Per”, “Serving size” or “Portion”, or their French (“Pour”, “Valeur nutritive pour”).
On the device, at no cost
Both scanners and the text recognition are Google Play services on the phone: no camera permission, no key, no charge. They run through a local Tauri plugin, scan (apps/desktop/plugins/scan), with three commands: barcode, label, and read_file, which reads a photo already on the phone. Elsewhere the buttons do not show. Open Food Facts’ host is on the app’s content security policy.
The barcode lookup is offered in any catalog whose basis is a measured unit, since nothing in a catalog says which outside source describes its items.
Code
packages/core/src/printed-label.ts—PrintedLabel,readServing,matchPrinted;packages/core/src/barcode.ts—normalBarcode.apps/renderer/src/lib/open-food-facts.ts—lookUpBarcode,labelOfProduct;apps/renderer/src/lib/read-printed.ts—readPrinted;apps/renderer/src/lib/scan.ts.apps/renderer/src/components/catalog/label-fill.ts—fillFromLabel;ScanButtons.tsx.apps/desktop/plugins/scan— the Android plugin.
Related
Diet and Nutrition · Catalog Entities · Frictionless Capture