API/Write/Photos

From Open Food Facts wiki

<Back to API/Write(Required reading) The new version of the documentation is available here:

Manipulating photos for a product

Understanding products and photos

  • Photos are the primary source of Open Food Facts.
  • We need good photos of the product, of its ingredients and nutrition table. (and for each language present on the packaging)
  • Good photos means a minimal allowed size: 640 x 160.
  • Please encourage your users to add as many photos as possible, even if the product is already complete (in that case, don't set them as default photos for front, ingredients, and nutrition)

Upload behaviour

If you upload an image (eg for front), the first one will be shown, the others will be saved but not displayed. Useful if you want to let your users take additional images that are neither front, ingredients or nutrition (eg: recycling instructions, labels…)

Understanding photos for multilingual products

Multilingual products have several photos based on languages present on the packaging. Just suffix the lang code to our examples to get or add the relevant language(s).

Adding photos for a product

  • Use the POST method on:
Test server: https://world.openfoodfacts.net/cgi/product_image_upload.pl
Live server: https://world.openfoodfacts.org/cgi/product_image_upload.pl

(remember to do tests on world.openfoodfacts.net - login and password: off )

Parameters
  • code: the barcode of the product
  • imagefield: (can be either: front | ingredients | nutrition)
  • imgupload_front : your image file if imagefield=front
  • imgupload_ingredients: your image file if imagefield=ngredients
  • imgupload_nutrition: your image file if imagefield=nutrition
Example
curl --user off:off --form "imgupload_front=@Tacitus.jpg" --form code=1212121212 --form imagefield=front --form user_id=tacite  --form password=mypassword https://fr.openfoodfacts.net/cgi/product_image_upload.pl
Important
  • Content-Disposition: form-data; name=“imgupload_front”; filename=“front.png”
  • There must be a HTTP header "Content-Type: multipart/form-data" in the HTTP POST request.
  • The imageupload_(front|ingredients|nutrition) name, size and data needs to be encoded in the multipart/form-data format, usually your HTTP request library will do that for you.
  • All parameters need to be passed as POST parameters, do not put some in the URL.
  • 0048151623426 is a random barcode used only for demonstration purposes.

Getting a list of all available photos

You get a list of all available photos in the product JSON (both selected photos for all languages, and Raw photos (source images for the selected images and images that are not used)

Properties of a photo
  • id = 5
  • uploaded_t = 1474912158 (UNIX timestamp format)
  • uploader = tacinte (contributor slug)
  • sizes

100 "h":100, "w":75

  • 400

"h":400, "w":300

  • full

"w":3120, "h":4160

Properties of a selected photo
  • nutrition_fr
  • y1 = 151.8125
  • normalize":"true",
  • x2":"169.75",
  • rev":"13",
  • geometry":"1238x1238-527-1578"
  • sizes
  • 100

"h":100, "w":75

  • 200
  • 400

"h":400, "w":300

  • full

"w":3120, "h":4160

  • y2 = 270.8125
  • x1 = 50.75
  • angle = 0
  • white_magic = false
  • imgid = 4
      "images":{  
         "front_fr":{  
            "y2":"340.8125",
            "x1":"67.75",
            "angle":"0",
            "imgid":"5",
            "white_magic":"false",
            "x2":"245.75",
            "normalize":"true",
            "y1":"13.8125",
            "rev":"10",
            "geometry":"1851x3401-704-143",
            "sizes":{  
               "400":{  
                  "w":218,
                  "h":400
               },
               "full":{  
                  "h":3401,
                  "w":1851
               },
               "100":{  
                  "w":54,
                  "h":100
               },
               "200":{  
                  "h":200,
                  "w":109
               }
            }
         },
         "2":{  
            "sizes":{  
               "400":{  
                  "h":400,
                  "w":300
               },
               "full":{  
                  "h":4160,
                  "w":3120
               },
               "100":{  
                  "w":75,
                  "h":100
               }
            },
            "uploaded_t":"1474912149",
            "uploader":"tacinte"
         },
         "5":{  
            "uploaded_t":"1474912158",
            "uploader":"tacinte",
            "sizes":{  
               "100":{  
                  "h":100,
                  "w":75
               },
               "400":{  
                  "h":400,
                  "w":300
               },
               "full":{  
                  "w":3120,
                  "h":4160
               }
            }
         },
         "3":{  
            "uploaded_t":"1474912152",
            "uploader":"tacinte",
            "sizes":{  
               "full":{  
                  "w":3120,
                  "h":4160
               },
               "400":{  
                  "h":400,
                  "w":300
               },
               "100":{  
                  "h":100,
                  "w":75
               }
            }
         },
         "nutrition_fr":{  
            "y1":"151.8125",
            "normalize":"true",
            "x2":"169.75",
            "rev":"13",
            "geometry":"1238x1238-527-1578",
            "sizes":{  
               "full":{  
                  "w":1238,
                  "h":1238
               },
               "400":{  
                  "h":400,
                  "w":400
               },
               "100":{  
                  "w":100,
                  "h":100
               },
               "200":{  
                  "w":200,
                  "h":200
               }
            },
            "y2":"270.8125",
            "x1":"50.75",
            "angle":"0",
            "white_magic":"false",
            "imgid":"4"
         },
         "4":{  
            "sizes":{  
               "400":{  
                  "w":300,
                  "h":400
               },
               "full":{  
                  "h":4160,
                  "w":3120
               },
               "100":{  
                  "h":100,
                  "w":75
               }
            },
            "uploader":"tacinte",
            "uploaded_t":"1474912154"
         },
         "ingredients_fr":{  
            "y2":"248.8125",
            "x1":"82.75",
            "angle":"0",
            "white_magic":"false",
            "imgid":"3",
            "normalize":"true",
            "y1":"158.8125",
            "x2":"257.75",
            "rev":"12",
            "sizes":{  
               "full":{  
                  "w":1820,
                  "h":936
               },
               "400":{  
                  "h":206,
                  "w":400
               },
               "100":{  
                  "h":51,
                  "w":100
               },
               "200":{  
                  "h":103,
                  "w":200
               }
            },
            "geometry":"1820x936-860-1651"
         },
         "1":{  
            "sizes":{  
               "full":{  
                  "w":3120,
                  "h":4160
               },
               "400":{  
                  "h":400,
                  "w":300
               },
               "100":{  
                  "w":75,
                  "h":100
               }
            },
            "uploaded_t":"1474912148",
            "uploader":"tacinte"
         }
      },

Adding a photo to the list of all available photos

Getting the current global photo

Setting a new current global photo

Getting the current ingredients photo

Setting a new current ingredients photo

Getting the current nutrition photo

Setting a new current nutrition photo

Choosing the product by barcode

code=

Values:

Selecting a photo

product_image_crop.pl?code=3266110700910&id=nutrition_fr&imgid=1
id: the field you want to attribute the image to
code: the barcode of the product
imgid: the image id you want to select into the field
id can be:
front_fr
nutrition_fr
ingredients_fr

front_nl
nutrition_nl
ingredients_nl

…
You retrieve the photo id when you upload it

Rotating a photo

Test server: https://world.openfoodfacts.net/cgi/product_image_rotate.pl
Parameters:
Getting the preview

Parameters:

imgid =
code = BARCODE
angle = Angle of the rotation - 90° increments
normalize = whether the source image should be normalized
white_magic = whether the source image should be "white magic"'d ( background removal)
function update_image(imagefield) {

	$('#crop_' + imagefield).attr("src","/cgi/product_image_rotate.pl?code=" + code + "&imgid=" + imagefield_imgid[imagefield]
		+ "&angle=" + angles[imagefield] + "&normalize=" + $("#normalize_" + imagefield).prop('checked')
		+ "&white_magic=" + $("#white_magic_" + imagefield).prop('checked')		);
	$('div[id="cropbuttonmsg_' + imagefield +'"]').hide();
}
Actually rotating the photo

https://world.openfoodfacts.org/cgi/product_image_crop.pl?code=3266110700910&id=nutrition_fr&imgid=1&angle=90

Removing background on a photo

This will work best on photos with a white background. Best use case is to let user try it and give up if the result is not satisfying.

white_magic=

Values:

Perform color correction on a photo

normalize=

Values:

Cropping a photo

This implies applying operations to a source image (not only cropping, but all the others if applicable). We start from a source image (defined by a barcode and incremental id), apply cropping parameters (x1, y1, x2, y2), additional operations (white_magic, normalize)

Test server: https://world.openfoodfacts.net/cgi/product_image_crop.pl
https://world.openfoodfacts.org/cgi/product_image_crop.pl?code=1&imgid=2&id=front_en&x1=0&y1=0&x2=145&y2=145
Values
code=BARCODE
id=
angle= Angle of the rotation
normalize = whether the source image should be normalized
white_magic = whether the source image should be white magiced (background removal)
type = add
action = display
imgid = the id of the source image
x1 = the X origin of the crop
y1 = the Y origin of the crop
x2 = the X end of the crop
y2 = the Y end of the crop
Ignore me
$.post('/cgi/product_image_crop.pl',
{code: code, 
id: imagefield , 
imgid: imgid,				
x1:selection.x, 
y1:selection.y, 
x2:selection.x + selection.width, 
y2:selection.y + selection.height,
angle:angles[imagefield], 
normalize:$("#normalize_" + imagefield).prop('checked'), 
white_magic:$("#white_magic_" + imagefield).prop('checked') }, function(data) {
imagefield_url[imagefield] = data.image.display_url;
update_display(imagefield, false);
$('div[id="cropbutton_' + imagefield +'"]').show();
$('div[id="cropbuttonmsg_' + imagefield +'"]').html(Lang.image_saved);
$(document).foundation('equalizer', 'reflow');
}, 'json');
});		

Performing OCR on a photo

We start from a source image (defined by barcode and id) as selected for ingredients. We ask Product Opener to process it (process_image=1). Product Opener returns a JSON. Processing is done using Tesseract or Google Cloud Vision. The result is often cripped with errors with Tesseract, less with Google Cloud Vision. Take steps to ensure your users correct the output. Do send the corrected output using the ingredients WRITE API. If possible, please use your own OCR, this costs us money, and we're a non-profit with no budget.

Test server: https://world.openfoodfacts.net/cgi/ingredients.pl
Values and output
code=code
id=imagefield
process_image=1

Example:

ingredients.pl?code=13333560&id=ingredients_en&process_image=1&ocr_engine=tesseract

This will return JSON