Use Google Cloud Vision OCR from Zoho Creator with Deluge

Read Text and Label Images with Google Cloud Vision from Zoho Creator

Photograph a receipt, get the text. Upload a product shot, get keywords for search. Cloud Vision does the hard part; Deluge only has to build a small JSON body and read the answer back.

Still current, with one meaningful improvement. The endpoint vision.googleapis.com/v1/images:annotate is unchanged and — contrary to a lot of advice online — API-key authentication still works. Google's documentation now showcases OAuth, but a bogus key returns API_KEY_INVALID, meaning the method is accepted and only the key was wrong. Keys remain the pragmatic choice from Deluge. What has been changed here is the original's use of a third-party PHP relay to base64-encode the image before sending it. That relay is gone: Vision accepts an imageUri and fetches the picture itself.

Before you start

  • A Google Cloud project with the Cloud Vision API enabled and billing attached.
  • An API key, restricted to the Vision API in the console.
  • A publicly reachable image URL, or a Cloud Storage gs:// URI.

Deluge function

// ============================================
// GOOGLE CLOUD VISION — OCR AND LABELLING
// Uses imageUri so nothing has to be base64-encoded.
// ============================================

string Vision.readImage(string imageUrl, string featureType)
{
    API_KEY = "YOUR_GOOGLE_CLOUD_API_KEY";

    source = Map();
    source.put("imageUri",imageUrl);

    image = Map();
    image.put("source",source);

    feature = Map();
    feature.put("type",featureType);        // TEXT_DETECTION or LABEL_DETECTION
    feature.put("maxResults",10);

    features = List();
    features.add(feature);

    request = Map();
    request.put("image",image);
    request.put("features",features);

    requests = List();
    requests.add(request);

    payload = Map();
    payload.put("requests",requests);

    response = invokeurl
    [
        url    : "https://vision.googleapis.com/v1/images:annotate?key=" + API_KEY
        type   : POST
        parameters : payload.toString()
        headers: {"Content-Type":"application/json"}
    ];

    responses = response.getJSON("responses");
    if(responses == null || responses.size() == 0)
    {
        info "Vision error: " + response.toString();
        return "";
    }

    first = responses.get(0);

    // Vision reports per-image failures inside a 200 response
    if(first.getJSON("error") != null)
    {
        info "Vision rejected the image: " + first.getJSON("error").toString();
        return "";
    }

    if(featureType == "TEXT_DETECTION")
    {
        full = first.getJSON("fullTextAnnotation");
        if(full != null)
        {
            return full.getJSON("text");
        }
        return "";
    }
    else
    {
        labels = first.getJSON("labelAnnotations");
        out = "";
        if(labels != null)
        {
            for each l in labels
            {
                if(out != "")
                {
                    out = out + ", ";
                }
                out = out + l.getJSON("description");
            }
        }
        return out;
    }
}

Notes

  • Use imageUri, not content. Base64-encoding a photo in Deluge produces a huge string, risks the script timeout, and was the only reason the original needed an external helper. Let Google fetch the image.
  • Failures hide inside a 200 response. Vision returns HTTP 200 with a per-image error object when it cannot reach or decode the picture. Without the check above, an unreachable image looks exactly like an image containing no text.
  • Each feature per image is one unit. First 1,000 units a month are free, then about $1.50 per 1,000. Asking for TEXT_DETECTION and LABEL_DETECTION on the same photo bills two units. Request only what you will actually use.
  • fullTextAnnotation for documents, textAnnotations for words. The first gives you the whole block with layout preserved, which is what you want for a receipt. The second gives every word with bounding boxes, which is what you want when position matters.
  • The image must be reachable without a login. A Creator file field behind authentication will not work — push the image somewhere public first, which is one reason to pair this with the Cloudinary script in this section.

This script is part of the free Creator Scripts Deluge Library.

All 39 Deluge scripts, the full Zoho Creator course, and every downloadable asset are now free. Get free access →

    • Related Articles

    • Google Distance Matrix API: Calculate Distance and Store the Value in Zoho Creator

      Given two addresses on a Zoho Creator record — a pickup and a drop-off, a technician and a job site, a warehouse and a customer — the Google Distance Matrix API returns the driving distance between them. This function calls it from Deluge and writes ...
    • Search the Getty Images API from Zoho Creator

      If your team licenses stock photography from Getty, searching it from inside the app where the work happens beats alt-tabbing to a browser. The API is a straightforward search endpoint — the awkward part is getting access to it at all. Read this ...
    • Publish Zoho Creator Records to Google Calendar or iCloud

      Your team already lives in a calendar. Rather than asking them to open Creator to see what is booked, publish the report as an iCal feed and let them subscribe — Google Calendar, iCloud, Outlook and anything else that speaks the format will poll it ...
    • Generate QR Codes and Barcodes in Zoho Creator

      Print a QR code on a label, put a Code 128 barcode on a picking slip, let a warehouse scanner read a lot number straight off a Creator record. Generating the image takes one HTTP call and no library. The service the original used no longer exists. ...
    • Cloudinary Image Management from Zoho Creator

      Creator stores images perfectly well, but it will not resize them, crop to a face, convert to WebP or serve them from a CDN. Cloudinary does all of that from the URL. Upload once from Deluge and every variant you ever need is a query string away. ...