Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jonasva committed May 14, 2019
0 parents commit c620890
Show file tree
Hide file tree
Showing 12 changed files with 635 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.idea
.DS_Store
vendor
composer.lock
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) Jonas Van Assche

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
70 changes: 70 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Analyze images with Google Cloud Vision

Easy way to analyze images with Laravel and Google Cloud Vision. Check their [demo](https://cloud.google.com/vision/docs/drag-and-drop) to see what it can do.

## Features

### Optical Character Recognition

Convert an image or PDF document to text

```php
$path = $request->file('file')->getRealPath();

$text = Vision::getFullText($path);
```

### Annotate image

Get annotations of your image for one or more Vision [features](https://cloud.google.com/vision/docs/features).

Make sure you extract the same type of annotations from the response as the feature you requested. (eg: `Type::FACE_DETECTION` -> `$response->getFaceAnnotations()`)

```php
use Google\Cloud\Vision\V1\Feature\Type;

$path = $request->file('file')->getRealPath();

$features = [Type::FACE_DETECTION];

$response = Vision::annotateImage($path, $features);

$faces = $response->getFaceAnnotations();
```

## Installation

### Laravel

This package can be installed through Composer.

```bash
composer require jonasva/laravel-vision
```

Publish config
```bash
php artisan vendor:publish --provider="Jonasva\Vision\VisionServiceProvider"
```

### Google Cloud Console

In order to use the Google Cloud Vision API, you'll need to setup a couple of things in Google Cloud Console.

1. Go to [Cloud Console](https://console.cloud.google.com) and select a project (or create a new one).

2. Add your project ID to your env file under `GOOGLE_CLOUD_PROJECT`

3. Go to the API library and find "Cloud Vision API". Click "Enable"

4. Create a service account + credentials file for Cloud Vision API. Place the credentials file in your project, and add the path (relative to your project root) to it in your env file under `GOOGLE_APPLICATION_CREDENTIALS`. (see `config/vision.php` file for more details.)

5. Setup a Google Cloud Storage bucket and make sure your newly created Cloud Vision service account user has read/write permissions to it. This bucket will be used to process PDF and TIFF type files.

6. Add the bucket name in your env under `GOOGLE_CLOUD_BUCKET`

7. I suggest setting up a lifecycle rule for your bucket to automatically remove files older than 1 day.

## Pricing

Make sure you take a look at Cloud Vision API's [pricing](https://cloud.google.com/vision/pricing), as it's not an entirely free service.
45 changes: 45 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "jonasva/laravel-vision",
"description": "A Laravel 5 package to interact with Google Cloud Vision.",
"keywords": [
"laravel",
"ocr",
"vision",
"google",
"gcloud"
],
"homepage": "https://github.com/jonasva/laravel-vision",
"license": "MIT",
"authors": [
{
"name": "Jonas Van Assche",
"email": "[email protected]"
}
],
"require": {
"php" : "^7.2",
"illuminate/support": "^5.4",
"google/cloud-storage": "^1.3",
"google/cloud-vision": "^0.22.0"
},
"autoload": {
"psr-4": {
"Jonasva\\Vision\\": "src"
}
},
"extra": {
"laravel": {
"providers": [
"Jonasva\\Vision\\VisionServiceProvider"
],
"aliases": {
"Vision": "Jonasva\\Vision\\VisionFacade"
}
}
},
"config": {
"sort-packages": true
},
"minimum-stability": "stable",
"prefer-stable": true
}
68 changes: 68 additions & 0 deletions config/vision.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

return [

/*
|--------------------------------------------------------------------------
| Google Cloud project ID
|--------------------------------------------------------------------------
|
| Your API project's ID from Google Cloud Console
| https://console.cloud.google.com
|
*/

'google_cloud_project_id' => env('GOOGLE_CLOUD_PROJECT'),

/*
|--------------------------------------------------------------------------
| Google application credentials path
|--------------------------------------------------------------------------
|
| Path of your the credentials file used to access the API
| (path is relative to your project root eg: credentials/vision/demo.json)
|
*/

'google_app_credentials_path' => env('GOOGLE_APPLICATION_CREDENTIALS'),

/*
|--------------------------------------------------------------------------
| Google Cloud Storage bucket
|--------------------------------------------------------------------------
|
| Storage bucket used to upload and batch process document type files.
| Make sure your API user has read and write access to this bucket
|
| Tip: setup a lifecycle rule for this bucket to automatically delete files older
| than one day. That way you'll save on storage costs of useless files.
|
*/

'google_cloud_storage' => [
'bucket' => env('GOOGLE_CLOUD_BUCKET'),
'raw_prefix' => 'raw/',
'processed_prefix' => 'processed/',
],

/*
|--------------------------------------------------------------------------
| Document batch size
|--------------------------------------------------------------------------
|
| Amount of pages per batch for text detection on documents
|
*/
'document_batch_size' => 3,

/*
|--------------------------------------------------------------------------
| Maximum file size
|--------------------------------------------------------------------------
|
| Maximum file size in Bytes of a single image or document
|
*/
'max_file_size' => 10 * 1000 * 1000, // 10 MB

];
10 changes: 10 additions & 0 deletions src/Exceptions/NotSupportedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Jonasva\Vision\Exceptions;

use Exception;

class NotSupportedException extends Exception
{

}
130 changes: 130 additions & 0 deletions src/Vision.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<?php

namespace Jonasva\Vision;

use Google\Cloud\Vision\V1\AnnotateImageResponse;
use Illuminate\Support\Facades\File;
use Jonasva\Vision\Exceptions\NotSupportedException;

class Vision
{
protected $config;

protected $visionImageClient;

protected $visionDocumentClient;

/**
* Vision constructor.
* @param array $config
*/
public function __construct(array $config)
{
$this->config = $config;
}

/**
* @param string $filePath
* @param array $languageHints
* @return string
* @throws NotSupportedException
*/
public function getFullText(string $filePath, array $languageHints = []): string
{
$this->checkFileSize($filePath);

$mimeType = File::mimeType($filePath);
$fileType = $this->detectFileType($mimeType);

if ($fileType == 'image') {
return $this->getVisionImageClient()->getFullText($filePath, $languageHints);
}
elseif ($fileType == 'document') {
return $this->getVisionDocumentClient()->getFullText($filePath, $mimeType, $languageHints);
}
}

/**
* @param string $filePath
* @param array $features
* @param array $options
* @return AnnotateImageResponse
* @throws NotSupportedException
*/
public function annotateImage(string $filePath, array $features, array $options = []): AnnotateImageResponse
{
$this->checkFileSize($filePath);
$this->checkIsImage($filePath);

return $this->getVisionImageClient()->annotateImage($filePath, $features, $options);
}

/**
* @param string $filePath
* @throws NotSupportedException
*/
protected function checkIsImage(string $filePath): void
{
$mimeType = File::mimeType($filePath);
$fileType = $this->detectFileType($mimeType);

if ($fileType !== 'image') {
throw new NotSupportedException($mimeType . ' file type not supported.');
}
}

/**
* @param string $filePath
* @throws NotSupportedException
*/
protected function checkFileSize(string $filePath): void
{
$size = File::size($filePath);

if ($size > $this->config['max_file_size']) {
throw new NotSupportedException('Maximum file size of ' . $this->config['max_file_size'] . ' Bytes exceeded');
}
}

/**
* @param string $mimeType
* @return string
* @throws NotSupportedException
*/
protected function detectFileType(string $mimeType): string
{
if (in_array($mimeType, ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/webp', 'image/vnd.microsoft.icon'])) {
return 'image';
}
elseif (in_array($mimeType, ['application/pdf', 'image/tiff'])) {
return 'document';
}
else {
throw new NotSupportedException($mimeType . ' file type not supported.');
}
}

/**
* @return VisionImageClient
*/
protected function getVisionImageClient(): VisionImageClient
{
if (!$this->visionImageClient) {
$this->visionImageClient = new VisionImageClient($this->config);
}

return $this->visionImageClient;
}

/**
* @return VisionDocumentClient
*/
protected function getVisionDocumentClient(): VisionDocumentClient
{
if (!$this->visionDocumentClient) {
$this->visionDocumentClient = new VisionDocumentClient($this->config);
}

return $this->visionDocumentClient;
}
}
36 changes: 36 additions & 0 deletions src/VisionClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Jonasva\Vision;

use Google\Cloud\Vision\V1\ImageAnnotatorClient;
use Illuminate\Support\Facades\File;

class VisionClient
{
protected $imageAnnotatorClient;

protected $config;

/**
* VisionClient constructor.
* @param array $config
* @throws \Google\ApiCore\ValidationException
*/
public function __construct(array $config)
{
$this->config = $config;

$this->imageAnnotatorClient = new ImageAnnotatorClient([
'credentials' => base_path($this->config['google_app_credentials_path']),
]);
}

/**
* @param string $filePath
* @return string
*/
protected function getFile(string $filePath): string
{
return File::get($filePath);
}
}
Loading

0 comments on commit c620890

Please sign in to comment.