Google Cloud Vision PHP — Make Batch Request - google-cloud-vision

I need to perform an OCR analysis on an image for an university project.
I am imposed to use PHP, unfortunately, on the Google Cloud Vision Documentation few are the code sample using PHP...
I succeed to perform OCR on one image at time but 80% of the time I have a lot of images (around 20) to treat at once.
So I tried to use BatchRequest, to minimize the API calls, as specified here but I can't found how to build the $requests array they put at the top.
Btw I tried other APIs like Tesseract but the recognition is not accurate enough to use.

If you only want to perform a batch request you can just use batchAnnotateImages using ImageAnnotatorClient. Below you can find a sample using it as well as a way to create a request variable. Also, I include below a asyncBatchAnnotateImages sample but I recommend the one I mentioned earlier.
Using ImageAnnotatorClient with batchAnnotateImages
<?php
require '../vendor/autoload.php';
use Google\Cloud\Storage\StorageClient;
use Google\Cloud\Vision\V1\Feature;
use Google\Cloud\Vision\V1\Feature_Type;
use Google\Cloud\Vision\V1\ImageAnnotatorClient;
use Google\Cloud\Vision\V1\Image;
use Google\Cloud\Vision\V1\ImageSource;
use Google\Cloud\Vision\V1\AnnotateImageRequest;
use Google\Cloud\Vision\V1\Likelihood;
$client = new ImageAnnotatorClient();
try {
$feature = (new Feature())
->setType(Feature_Type::FACE_DETECTION);
$image = (new Image())
->setContent(file_get_contents("../images/family.jpg","r"));
$request = (new AnnotateImageRequest())
->setImage($image)
->setFeatures([$feature]);
$requests = [$request];
# note: you can add as many requests you want to perform. ie: [$request,$request2,..,..]
$results = $client->batchAnnotateImages($requests);
foreach($results->getResponses() as $result){
foreach ($result->getFaceAnnotations() as $faceAnnotation) {
$likelihood = Likelihood::name($faceAnnotation->getJoyLikelihood());
echo "Likelihood of headwear: $likelihood" . PHP_EOL;
}
}
} finally {
$client->close();
}
Using ImageAnnotatorClient with asyncBatchAnnotateImages
<?php
require '../vendor/autoload.php';
use Google\Cloud\Storage\StorageClient;
use Google\Cloud\Vision\V1\Feature;
use Google\Cloud\Vision\V1\Feature_Type;
use Google\Cloud\Vision\V1\ImageAnnotatorClient;
use Google\Cloud\Vision\V1\Image;
use Google\Cloud\Vision\V1\ImageSource;
use Google\Cloud\Vision\V1\AnnotateImageRequest;
use Google\Cloud\Vision\V1\asyncBatchAnnotateImages;
use Google\Cloud\Vision\V1\OutputConfig;
use Google\Cloud\Vision\V1\GcsDestination;
$client = new ImageAnnotatorClient();
try {
$feature = (new Feature())
->setType(Feature_Type::FACE_DETECTION);
$gcsImageUri = 'gs://<YOUR BUCKET ID>/<YOUR IMAGE FILE>';
$source = new ImageSource();
$source->setImageUri($gcsImageUri);
$image = (new Image())
->setSource($source);
$request = (new AnnotateImageRequest())
->setImage($image)
->setFeatures([$feature]);
$requests = [$request];
$gcsDestination = (new GcsDestination())
->setUri("gs://<YOUR BUCKET>/<OUTPUT FOLDER>/");
$outputConfig = (new OutputConfig())
->setGcsDestination($gcsDestination);
$operationResponse = $client->asyncBatchAnnotateImages($requests, $outputConfig);
$operationResponse->pollUntilComplete();
if ($operationResponse->operationSucceeded()) {
$result = $operationResponse->getResult();
var_dump($result);
#Your Folder output will have your file processing results.
}
} finally {
$client->close();
}
Note: To add on this, you can also check an official implementation of a similar case using vision client on this link but its a sample to detect text on a pdf file.
You can also find additional information on these links:
ImageAnnotatorClient
AnnotateImageRequest
AsyncBatchAnnotateImages
BatchAnnotateImagesResponse
AsyncBatchAnnotateImagesResponse
PHP CLOUD VISION Github Project Page

Related

unable to see header after fpdf creates file

I am working on a wordpress plugin,
I want to create a pdf file, For this I used fpdf
By using this code I am able to generate pdf and save it to server
require('fpdf/html_table.php');
$pdf=new PDF_HTML();
$questions = $_POST['question'];
$count = count($questions);
$quests = "";
$pdf->SetFont('times','',12);
$pdf->SetTextColor(50,60,100);
$pdf->AddPage('P');
$pdf->SetDisplayMode(real,'default');
$pdf->SetFontSize(12);
for($i=1;$i<=$count;$i++)
{
$qus_id = $questions[$i-1];
$get_q = "select * from `SelleXam_question` where `id`='$qus_id'";
$get_q = $wpdb->get_results($get_q);
$questf = "Quest $i : ".$get_q[0]->question;
$pdf->Cell(0, 10, $questf."\n");
$pdf->Ln();
}
$dir='C:/wamp/www/';
$filename= "filename.pdf";
$pdf ->Output($dir.$filename);
echo "Save PDF in folder";
But when it saved and displayed the messge Save PDF in Folder. I am unable to see the header part of the wordpress website.
Or when I use
$pdf->Output($filename,'D');
then is there any way that I can show the file in a link
When you are developing for Wordpress, you can't just echo text at any time. Wordpress has a whole series of actions it goes through to progressively generate the output rendered to the browser. If you generate output at an inappropriate time, you'll mess up Wordpress' ability to generate output at the right time.
If I were developing this, I'd have this function be called as a filter on the_content. Your output code would change to something like this:
function append_pdf_to_content($content) {
//Your existing code
$pdf->Output($filename, 'F');
$pdf_link = "<br><a href='$filename' download>Download PDF</a>"
return $content . $pdf_link;
}
add_filter('the_content', 'append_pdf_to_content');
If you wanted to use the D option, you'll need to link your users to a separate php page using a target='_blank' that calls the download. Otherwise the PDFs headers will override any headers Wordpress is trying to send.
BTW, you also might want to also take a look at mPDF, it's a fork of fpdf and remains in active development.

How to clear all events in Google Calendar using API V3 PHP

I spent a long time to work out how to do the following using Google Calendar using API V3 in PHP
insert a new event
read all existing events
delete each existing event
However I would still like to know how to clear an entire Google Calendar to make my code faster, as the read & delete method is a little slow.
I've been trying to work out how to use the supplied Google function "clear" for this, and the documentation supplied by Google simply shows that I should be able to use the following command to achieve this:
$service->calendars->clear('primary');
Also within the Google Code there is a comment relating to the "calendars" collection of methods (where the clear function exists):
Typical usage is:
<code>
$calendarService = new Google_Service_Calendar(...);
$calendars = $calendarService->calendars;
</code>
So I've put this together with the preceding authentication code. I am sure the authentication is working OK as I've used that elsewhere, but the clear code is obviously wrong as I get error message:
Notice: Undefined variable: service in C:\wamp\www\googleapi\clear\index.php on line 39
I've tried using 'primary' as well as the main owner, and I've tried making the calendar private and public but to no avail.
Anyone who has got the clear method to work, please point me in the right direction.
This is the code I'm running so far:
<?php
session_start();
require_once '../google-api-php-client-master/autoload.php';
//Google credentials
$client_id = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com';
$service_account_name = 'xxxxxxxxxxxxxxxxxxxxxx#developer.gserviceaccount.com';
$key_file_location = '../google-api-php-client-master/API Project-xxxxxxx.p12';
if (!strlen($service_account_name) || !strlen($key_file_location))
echo missingServiceAccountDetailsWarning();
$client = new Google_Client();
$client->setApplicationName("Whatever the name of your app is");
if (isset($_SESSION['service_token'])) {
$client->setAccessToken($_SESSION['service_token']);
}
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
$service_account_name,
array('https://www.googleapis.com/auth/calendar'),
$key
);
$client->setAssertionCredentials($cred);
if($client->getAuth()->isAccessTokenExpired()) {
try {
$client->getAuth()->refreshTokenWithAssertion($cred);
} catch (Exception $e) {
var_dump($e->getMessage());
}
}
$_SESSION['service_token'] = $client->getAccessToken();
/* ------------------------- We are now properly authenticated ------------------- */
$calendarService = new Google_Service_Calendar($client);
$calendars = $calendarService->calendars;
$service->calendars->clear('primary');
?>
Just use your service calendar instance.
$service = new Google_Service_Calendar($client);
$calendar = $service->calendars->clear('primary');

Mocking a GuzzleHttp response

How should I mock a Guzzle response properly. When testing a parser I'm writing, the test html is contained in files. In my PHPUnit tests I'm doing file_read_contents and passing the result into my method. Occasionally the HTML will link to a seperate file. I can mock this response like so:
public function testAlgo()
{
$mock = new MockAdapter(function() {
$mockhtml = file_get_contents($this->dir . '/HTML/authorship-test-cases/h-card_with_u-url_that_is_also_rel-me.html');
$stream = Stream\create($mockhtml);
return new Response(200, array(), $stream);
});
$html = file_get_contents($this->dir . '/HTML/authorship-test-cases/h-entry_with_rel-author_pointing_to_h-card_with_u-url_that_is_also_rel-me.html');
$parser = new Parser();
$parser->parse($html, $adaptor = $mock);
Then in my actual method, when I make the guzzle request this code works:
try {
if($adapter) {
$guzzle = new \GuzzleHttp\Client(['adapter' => $adapter]);
} else {
$guzzle = new \GuzzleHttp\Client();
}
$response = $guzzle->get($authorPage);
So obviously this isn't ideal. Does anyone know of a better way of doing this?
$html = (string) $response->getBody();
EDIT: I'm now using the __construct() methid to set up a default Guzzle Client. Then a using a second function that can be called by tests to replace the Client with a new Client that has the mock adapter. I'm not sure if this is the best way to do things.
You can use the MockPlugin API, like so:
$plugin = new MockPlugin();
$plugin->addResponse(__DIR__.'/twitter_200_response.txt');
The txt file then contains everything from your response, including headers.
There are also good approaches available here: http://www.sitepoint.com/unit-testing-guzzlephp/
Also there are articles found here: http://guzzle3.readthedocs.io/testing/unit-testing.html

Send Gravity Forms data to redirection page

I have a very simple form created with Gravity Forms;
It submits two numbers and then redirects to a different result page.
How do I retrieve those two numbers on the result page?
add_filter("gform_confirmation_4", "custom_confirmation", 3, 4 );
function custom_confirmation($confirmation, $form, $lead, $ajax)
Gives a custom confirmation. Each field value can be retrieved by using $lead[{field ID}]
I have a solution for this based on using a combination of form submission hooks and the GForms API. It's a horrible plugin so I apologise for the messiness of the logic flow. It's important to use the framework methods rather than processing the data yourself since there are a good amount of hacks and shonky things going on in there to correctly match field IDs and so forth.
I will provide a solution to pass a submission from one form to pre-populate another. Changing the destination for POST data is pretty straightforward, they have an example for it on their gform_form_tag hook documentation page. Yes, that really is the only way of doing it.
Without further ado here is the code. I've set it up to work off form configuration to make things simpler for the end user, so it works like this:
Select "allow field to be populated dynamically" in your destination form field's advanced settings and choose a parameter name for each.
Add matching CSS classes on the source fields of the other form(s) to setup the associations.
Add a CSS class to the source forms themselves so that we can quickly check if the redirection is necessary.
.
$class = 'GForms_Redirector';
add_filter('gform_pre_submission', array($class, 'checkForSubmissionRedirection'), 10, 1);
add_filter('gform_confirmation', array($class, 'performSubmissionRedirection'), 10, 4);
abstract class GForms_Redirector
{
const SOURCE_FORMS_CLASS_MATCH = 'submission-redirect';
const DEST_PAGE_SLUG = 'submit-page-slug';
const DEST_FORM_ID = 1;
protected static $submissionRedirectUrl;
// first, read sent data and generate redirection URL
function checkForSubmissionRedirection($form)
{
if (false !== preg_match('#\W' . self::SOURCE_FORMS_CLASS_MATCH . '\W#', $form['cssClass'])) {
// load page for base redirect URL
$destPage = get_page_by_path(self::DEST_PAGE_SLUG);
// load form for reading destination form config
$destForm = RGFormsModel::get_form_meta(self::DEST_FORM_ID, true);
$destForm = RGFormsModel::add_default_properties($destForm);
// generate submission data for this form (there seem to be no hooks before gform_confirmation that allow access to this. DUMB.)
$formData = GFFormsModel::create_lead($form);
// create a querystring for the new form based on mapping dynamic population parameters to CSS class names in source form
$queryVars = array();
foreach ($destForm['fields'] as $destField) {
if (empty($destField['inputName'])) {
continue;
}
foreach ($form['fields'] as $field) {
if (preg_match('#(\s|^)' . preg_quote($destField['inputName'], '#') . '(\s|$)#', $field['cssClass'])) {
$queryVars[$destField['inputName']] = $formData[$field['id']];
break;
}
}
}
// set the redirect URL to be used later
self::$submissionRedirectUrl = get_permalink($destPage) . "?" . http_build_query($queryVars);
}
}
// when we get to the confirmation step we set the redirect URL to forward on to
function performSubmissionRedirection($confirmation, $form, $entry, $is_ajax = false)
{
if (self::$submissionRedirectUrl) {
return array('redirect' => self::$submissionRedirectUrl);
}
return $confirmation;
}
}
If you wanted to pass the form values someplace else via the querystring then you'd merely need to cut out my code from the callback and build your own URL to redirect to.
This is a very old question, now you can send it using a Query String on the confirmation settings.
They have the documentation on this link:
How to send data from a form using confirmations
Just follow the first step and it will be clear to you.

Annotation in pdfclown

I am trying to put a sticky note at some x,y location. For this i am using the pdfclown annotation class in .net.
Below is what is available.
using files = org.pdfclown.files;
public override bool Run()
{
files::File file = new files::File();
Document document = file.Document;
Populate(document);
Serialize(file, false, "Annotations", "inserting annotations");
return true;
}
private void Populate(Document document)
{
Page page = new Page(document);
document.Pages.Add(page);
PrimitiveComposer composer = new PrimitiveComposer(page);
StandardType1Font font = new StandardType1Font(document, StandardType1Font.FamilyEnum.Courier, true, false);
composer.SetFont(font, 12);
annotations::Note note = new annotations::Note(page, new Point(78, 658), "this is my annotation...");
note.IconType = annotations::Note.IconTypeEnum.Help;
note.ModificationDate = new DateTime();
note.IsOpen = true;
composer.Flush();
}
Link for annotation
This is putting a sticky note at 78, 658 cordinates in a blank pdf.
The problem is that i want that sticky note in a particular pdf which has some data. How can i modify it...thanks for the help..
I'm the author of PDF Clown -- this is the right way to insert an annotation like a sticky note into an existing page:
using org.pdfclown.documents;
using annotations = org.pdfclown.documents.interaction.annotations;
using files = org.pdfclown.files;
using System.Drawing;
. . .
// Open the PDF file!
using(files::File file = new files::File(#"C:\mypath\myfile.pdf"))
{
// Get the document (high-level representation of the PDF file)!
Document document = file.Document;
// Get, e.g., the first page of the document!
Page page = document.Pages[0];
// Insert your sticky note into the page!
annotations::Note note = new annotations::Note(page, new Point(78, 658), "this is my annotation...");
note.IconType = annotations::Note.IconTypeEnum.Help;
note.ModificationDate = new DateTime();
note.IsOpen = true;
// Save the PDF file!
file.Save(files::SerializationModeEnum.Incremental);
}
Please consider that there are lots of options about the way you can save your file (to an output (in-memory) stream, to a distinct path, as a compacted file, as an appended file...).
If you look at the 50+ samples accompanying the library's distribution, along with the API documentation, you can discover how expressive and powerful it is. Its architecture strictly adheres to the official Adobe PDF Reference 1.7.
enjoy!

Resources