Sometimes, you may only need a service to identify one image from another, good news there are entry points for that. And because Images have a meaning only in your context, you can associate metadata and keywords to your images. To access to this service, You only need a login, an OrganizationId (you get it when you log in), and an API Key for searching.
This part is optimized for High Volumes / High Speed image recognition. No image is stored in the platform, and data is indexed in a fast database. Here we will guide you from the authentication on the platform until the search of an image. This API also allows to search an image based on the color of another image. The principle stays the same but if you need more information please do not hesitate to contact us.
If you need to enrich an image with complex actions, languages and styles, you can consult the documentation of the EnrichedImages API
Request AccessTo get access to our services, you will need an account.
To request an account to our development team, please fill in that request form.
Contact UsShould you have any feedback or question please feel free to contact us.
-> To go deeper, the full API reference documentation is available here.
-> JQuery code samples come from the Javascript SDK (GitHub).
To have access to our service you must be logged. It means you need an account. With your API Key - that you get on the platform in the admin tab - and with your login, you get an token. This token must be send with all the add/get requests and is valid for 15 days.
Build a POST request of type application/x-www-form-urlencoded.
POST https://api.onprint.com/token
ApiKey:[your Api Key]
data:
grant_type:
username : your login account
password : your password
The content is form-data, built like this:
grant_type=password&username=toto@ltu.com&password=test
A Json containing the account data and the access token
curl -X POST -H "contentType: application/x-www-form-urlencoded" "https://api.onprint.com/token" -d "grant_type=password&username=toto@ltu.com&password=test" -H "ApiKey:[your API key]"
function login(username, password, apikey, callback) {
if (username == '' || password == '') {
alert('missing username or password');
return;
}
var url = 'https://api.onprint.com/token';
var formData = 'grant_type=password&username=' + encodeURIComponent(username) + '&password=' + encodeURIComponent(password);
$.ajax({
url: url,
type: 'POST',
accept: 'application/json',
headers: {
'ApiKey': apikey
},
contentType: 'application/x-www-form-urlencoded',
data: formData,
success: function (data, status) {
$.ajaxSetup({ beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'bearer ' + data.access_token);
} });
callback(data, status);
},
error: function (xhr, status) {
callback(xhr, status);
}
});
}
The response contains the token in the field access_token. It has an expiration date. It also contains your userId as well as your organizationId
{"access_token":"AQAAANCMnd8BFdERjHoAwE_Cl-sBAAAAET6D6vU6i0Kl63(...)","token_type":"bearer","expires_in":1209599,"userName":"toto@toto.com","userId":"085201a8-98a2-0f5c-3311-aa415563ed05","organizationId":"1a855da8-4510-0f5c-3311-aa415563da95","organizationName":"totorg","roles":"System.Data.Entity.DynamicProxies.UserRole_CDCE067A6D23","apiversion":"2.0.6",".issued":"Thu, 09 Feb 2017 15:51:04 GMT",".expires":"Thu, 23 Feb 2017 15:51:04 GMT"}
Use the OAuth2 authentication for API calls that requires it. Set a header in your get/add requests like this:
Authorization: Bearer AQAAANCMnd8BFdERjHoAwE_Cl-sBAAAAET6D6vU6i0Kl63(...)
When you log in, you get access to your organization (often it's your enterprise name) and all its children, which can be other organizations (your clients or your different applications such as test, prod, preprod...). These are called nodes. To navigate through the node arborescence, you can use the nodes endpoint.
As you may have noticed in part 1, when you log in, you are returned your own userId as well as your organizationId. If you want to see what nodes are children of your organization, try:
GET https://api.onprint.com/api/nodes/[nodeId]/organizations
And if you want to go deeper in the arborescence, call the same thing with any other node Id.
GET https://api.onprint.com/api/nodes/[nodeId]/nodes
"Authorization: bearer ${TOKEN}"
A JSON object with the nodes children's data.
curl -H "Authorization: bearer ${TOKEN}" 'https://api.onprint.com/api/nodes/[nodeId]/nodes'
For typename in organizations:
function getChildren(nodeId, typename, callback) {
$.ajax({
method: "GET",
url: getUrl("/api/nodes/" + nodeId + "/" + typename),
success: function (data, status, xhr) {
callback(data, status, xhr);
},
error: function (xhr, status) {
callback(null, status, xhr);
}
});
}
When you want to create a new organization, you can POST it (Content-Type:application/json). Organizations could help you to organise your pictures by applications (test, preprod, prod...).
POST https://api.onprint.com/api/[organizations]
curl -X POST --header 'Content-Type: application/json' --header 'Accept: text/plain' --header "Authorization: Bearer ${TOKEN}" -d '{"Name": "test","LanguageCode": "fr-FR","ParentId":"[Id]"}' 'https://api.onprint.com/api/Organizations'
For typename in nodes, organizations:
function postOne(object, typename, callback) {
$.ajax({
method: "POST",
url: "https://api.onprint.com/api/" + typename,
data: JSON.stringify(object),
contentType: "application/json",
dataType: "json",
success: function (data, status, xhr) {
callback(data, status, xhr);
},
error: function (xhr, status) {
callback(null, status, xhr);
}
});
}
The node details are given as a JSON object in the body.
A Picture is a simple, single Image.
Property | Mandatory? | Type | Description | Comment |
---|---|---|---|---|
Id | String | Picture Id in the platform. | Read-Only, generated | |
_objectId | String | Internal Id, useful for pagination (see ) | Read-Only, generated | |
Name | * | String | Picture name. Can be your own identifier | |
Data | String | Picture metadata. You can put whatever you want, in any format. | ||
OrganizationId | * | String | Organization"s Id. Pictures will be listed under it. | |
BigThumbnailUrl | String | URL of the Picture"s Thumbnail. (only for display) | Read-Only, generated | |
SessionId | String | Session identifier that you can use to link events to the IR. | Read-Only, generated | |
RecognitionScore | String | Score of the image recognition, regarding the query image. | Read-Only, generated | |
Keywords | String[] | Keywords attached to the picture, to filter searches. |
The POST method is used to add a picture by sending the image file and its properties.
POST https://api.onprint.com/api/pictures
The request body content type must be Multipart (multipart/form-data). The content is made of a File data (named file) and a Form data (named picture). If you don't know how to make a Multipart request, see the RFC 1341 part 7.2, or Java, NodeJS, .NET tools.
The response is a JSON object representing the new picture. HTTP status is 201 - Created.
curl -s -i -F 'picture={"Name":"veggies","ContentType":"image/jpeg","OrganizationId":"[id]"};type=application/json' -F 'file=@/Users/Downloads/veggies.jpeg;type=image/jpeg;filename=veggies.jpg' -X POST -H 'Content-type: multipart/form-data' -H 'Accept: application/json' -H "Authorization: bearer ${TOKEN}" 'https://api.onprint.com/api/Pictures/'
File parameter of function postPicture must be a binary file. We partially reuse what was done for a Node before:
function getBoundary() {
return "XXX" + (new Date).getTime() + "XXX";
}
function createFileContent(filename, attachmentname, filetype, boundary) {
var contentFile = "--" + boundary + "\r\n";
contentFile += "Content-Disposition: attachment; name=" + attachmentname + "; filename="" + filename + ""\r\n";
contentFile += "Content-Type: " + filetype + "\r\n";
contentFile += "\r\n";
return contentFile;
}
function createFormContent(object, objectname, boundary) {
var contentForm = "--" + boundary + "\r\n";
contentForm += "Content-Type: application/json; charset=utf-8\r\n";
contentForm += "Content-Disposition: form-data; name=" + objectname + "\r\n";
contentForm += "\r\n";
contentForm += JSON.stringify(object) + "\r\n";
return contentForm;
}
function postPicture(file, picture, callback) {
var boundary = getBoundary();
var contentForm = createFormContent(picture, "picture", boundary);
var contentFile = createFileContent(file.name, "file", file.type, boundary);
var blob = new Blob([contentForm, contentFile, file, createEndContent(boundary)]);
$.ajax({
method: "POST",
url: "https://api.onprint.com/api/pictures),
data: blob,
contentType: "multipart/form-data; boundary="" + boundary + """,
dataType: "json",
processData: false,
success: function (data, status, xhr) {
callback(data, status, xhr)
},
error: function (xhr, status) {
callback(null, status, xhr)
}
});
}
Internal identifiers are filled:
{
"_objectId": "507f1f77bcf86cd799439011",
"Id": "31140da6-b422-44fd-82c1-847820f954e7",
"OrganizationId": "37e2cc76-8fcb-4864-9557-866d4bd47316",
"Name": "Veggies",
"Data": "1234568799|Test|784845122|###",
"BigThumbnailUrl": "https://static.ltu-engine.com/thumb-200x200/image/0ILHbFNqj3QwB8yH/8dd90fa85898fb14cc904dfd52925f3e"
}
The picture itself. It can be a JPEG, PNG, GIF image. The MIME type has to be given in the file content type. There is no special requirement regarding file size or quality. However, you must keep in mind that to be recognized, the image must contain enough details or points. And if you send us very high quality images, it will be slow and worth nothing because the platform resizes the images for recognition.
Contains a Picture object. The mandatory fields are:
Example:
{
"OrganizationId": "5215adae-e451-44c8-a930-9e4afe88bba9",
"Name": "Veggies",
"Data": "1234568799|Test|784845122|###" //anything you need, String or Json or Binary or whatever you like...
}
For an image search, it will be a multipart (multipart/formdata) POST:
POST https://api.onprint.com/api/Pictures/Search
LTU will require some information from the device to store useful clickstream information, and to authenticate using the API key. This call does not need a oAuth authentication. This is why you will have to set several headers to the call. Here is the full list. You can also find it in the reference documentation.
Header | Type | Example | Mandatory? |
---|---|---|---|
SessionId | Unique Identifier | 2252dda8-ce26-49d8-98e0-3fbe76181435 | |
ApplicationInstanceId | Unique Identifier | CCE20149-0F83-43FE-A167-C4E1A3335FC9 | |
ApplicationName | String | My Super App | * |
ApplicationVersion | String | 1.7.4.121 | * |
ApiKey | Unique Identifier | 3ad17b48a8a4f08f8949a | * |
DeviceName | String | iPhone de Thomas | * |
DeviceSystemVersion | String | 10.2.1 | * |
DeviceSystemVersionName | String | iPhone OS | |
SdkName | String | My Super App SDK | |
SdkVersion | String | 1.7.4 | * |
DeviceConnectivity | String | WiFi | |
DeviceScreenDiagonal | String | 0 | |
DeviceScreenHeight | String | 568 | |
DeviceScreenWidth | String | 320 | |
Longitude | Floating point | 44.946709 | |
Latitude | Floating point | -93.175379 | |
Language | String | fr-FR |
The mandatory headers are Application Name and version, Sdk version (if you are developing a single application, Sdk version = Application version), Device name and system version, and APIkey.
Once you are able to get all this information from the device, you are ready to do the request.
If the image is found, you will get a 200 OK and a list of matching Picture objects: images and their metadata, with a recognition score, the highest being 1.
curl -s -i -F 'query={"Keywords":["legumes"]};type=application/json' -F 'file=@/Users/Documents/onprint/veggies.jpg;type=image/jpeg;filename=veggies.jpg' -X POST -H 'Content-type: multipart/form-data' -H 'Accept: application/json' -H 'ApiKey: [ApiKey]' -H 'ApplicationInstanceId: ApiTester' -H 'ApplicationName: ApiTester' -H 'ApplicationVersion: 0.0' -H ‘DeviceName: Po -H 'DeviceSystemVersion: 0.0' -H 'DeviceSystemVersionName: Script' -H 'SdkName: Script' -H 'SdkVersion: 1.0' 'https://api.onprint.com/api/Pictures/Search'
function getBoundary() {
return "XXX" + (new Date).getTime() + "XXX";
}
function createFileContent(filename, attachmentname, filetype, boundary) {
var contentFile = "--" + boundary + "\r\n";
contentFile += "Content-Disposition: attachment; name=" + attachmentname + "; filename="" + filename + ""\r\n";
contentFile += "Content-Type: " + filetype + "\r\n";
contentFile += "\r\n";
return contentFile;
}
function createFormContent(object, objectname, boundary) {
var contentForm = "--" + boundary + "\r\n";
contentForm += "Content-Type: application/json; charset=utf-8\r\n";
contentForm += "Content-Disposition: form-data; name=" + objectname + "\r\n";
contentForm += "\r\n";
contentForm += JSON.stringify(object) + "\r\n";
return contentForm;
}
function searchPicture(file, searchQuery, callback) {
var query = {
Keywords:["painting"]
};
var boundary = getBoundary();
var contentForm = createFormContent(query, "query", boundary);
var contentFile = createFileContent(file.name, "file", file.type, boundary);
var blob = new Blob([contentForm, contentFile, file, createEndContent(boundary)]);
$.ajax({
method: "POST",
url: "http://api.onprint.com/api/Pictures/Search",
data: blob,
contentType: "multipart/form-data; boundary="" + boundary + """,
dataType: "json",
processData: false,
headers: {
"ApplicationInstanceId": searchQuery.ApplicationInstanceId,
"ApplicationName": searchQuery.ApplicationName,
"ApplicationVersion": searchQuery.ApplicationVersion,
"ApiKey": searchQuery.ApiKey,
"DeviceName": searchQuery.DeviceName,
"DeviceSystemVersion": searchQuery.DeviceSystemVersion,
"DeviceSystemVersionName": searchQuery.DeviceSystemVersionName,
"SdkName": searchQuery.SdkName,
"SdkVersion": searchQuery.SdkVersion,
"Latitude": searchQuery.Latitude,
"Longitude": searchQuery.Longitude
},
success: function (data, status, xhr) {
if (xhr.status == 200) {
}
if (xhr.status == 204) {
}
callback(data, status, xhr);
},
error: function (xhr, status) {
callback(null, status, xhr);
}
});
}
Here is an example of what you should get:
[
{
"_objectId": "507f1f77bcf86cd799439011",
"Id": "31140da6-b422-44fd-82c1-847820f954e7",
"OrganizationId": "37e2cc76-8fcb-4864-9557-866d4bd47316",
"Name": "La Joconde",
"Data": "123548481512000",
"BigThumbnailUrl": "https://static.ltu-engine.com/thumb-200x200/image/0ILHbFNqj3QwB8yH/8dd90fa85898fb14cc904dfd52925f3e",
"SessionId": "ff4d6e93-bddf-4584-bfb6-de5259ae6c2c",
"RecognitionScore": 0.99822000,
"Keywords":["painting"]
},
{
"_objectId": "90876f77bca86cd799439871
"Id": "ab889076-b422-44fd-82c1-847820f954e7",
"OrganizationId": "37e2cc76-8fcb-4864-9557-866d4bd47316",
"Name": "Joconde Bottero",
"Data": "{\"internalid\":\"2\", \"info\":\"personal info\"}",
"BigThumbnailUrl": "https://static.ltu-engine.com/thumb-200x200/image/0ILHbFNqqzf87KHi/5a6fc5812f9e68122082951b68c18060",
"SessionId": "ff4d6e93-bddf-4584-bfb6-de5259ae6c2c",
"RecognitionScore": 0.75643000,
"Keywords":["painting"]
}
]
The query JPEG image itself. No need to make it big: our recommandation is to pre-treat it before sending to the server:
The MIME type must be image/jpeg.
Contains the Json query object that goes with the content. If you have no special query and only want to do a simple match, leave it empty and send a blank JSON. If you work with keywords and want to filter the results with this keyword, add keywords as a string array in the query object:
{
"Keywords":["cat", "animal"]
}
There is also a compatibility between EnrichedImages and Pictures. You can use the EnrichedImages API to scan a Picture (the opposite is not true). The result will be a single (best recognition score) Enriched Image, with no language, no styles, only a "Data" field containing the picture data.
To get the same result by providing the image Id only (no image search), you can call a GET:
GET https://api.onprint.com/api/Pictures/[Id]"
The only difference is that the RecognitionScore will be null or 0.
curl -H "Authorization: bearer ${TOKEN}" 'https://api.onprint.com/api/Pictures/[id]'
The LTU platform stores every flash, so that you can get clickstream information.
∴
That's it! You went through all our quickstart. We hope you liked it. We would love to hear from your feedback, so for anything please contact us! You can now start ahead, and if you need more, don't forget the reference documentation.
We also have a Swagger page, useful to test a little but not fully configured (missing headers for EnrichedImages and Clicks, so it won't work, multipart stuff a little handmade...). You can find it here: https://api.onprint.com/Swagger
Thank you for your interest in the LTU API. Any question let us know.