diff --git a/.gitignore b/.gitignore index 1f2db4f..92fd865 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,5 @@ images/ ?.php sess.php + +vendor/ diff --git a/ajax/savecard.php b/ajax/savecard.php index 136e806..38877c8 100644 --- a/ajax/savecard.php +++ b/ajax/savecard.php @@ -43,6 +43,8 @@ if ( $filename != $image->getFileName() ) { } } +$image->setOCR($_REQUEST["cardtext"]); + $image->setEnabled(($_REQUEST["enabled"] == "1") ? true : false); $image->save(); $data["image"] = $image; diff --git a/ajax/uploadimages.php b/ajax/uploadimages.php index 557f1f8..a3c558f 100644 --- a/ajax/uploadimages.php +++ b/ajax/uploadimages.php @@ -40,6 +40,7 @@ foreach ( $_FILES['images']['name'] as $key => $name ) { $image->setFileName($filename); $image->setWidth($width); $image->setHeight($height); + $image->updateOCR(); $image->save(); } } diff --git a/class_image.php b/class_image.php index 7e891a7..c1fe56d 100644 --- a/class_image.php +++ b/class_image.php @@ -1,5 +1,7 @@ ocr; + } + public function getWidth() { return $this->width; } @@ -117,6 +124,12 @@ class MTGImage implements JsonSerializable { return true; } + public function setOCR($value = null) { + if ( is_null($value) || !is_string($value) ) return false; + $this->ocr = $value; + return true; + } + public function setWidth($value = null) { if ( is_null($value) ) return false; if ( !is_int($value) || ($value < 0) ) return false; @@ -131,6 +144,18 @@ class MTGImage implements JsonSerializable { return true; } + public function updateOCR() { + try { + $text = (new TesseractOCR(IMAGEPATH . $this->getFileName())) + ->lang('eng') + ->run(); + $text = str_replace("\n", " ", $text); + return $this->setOCR($text); + } catch ( Exception $e ) { + return $e->getMessage(); + } + } + public function renameImage($value = "") { $oldname = $this->getFileName(); $conflictImage = MTGImage::getImageByFileName($value); @@ -207,7 +232,7 @@ class MTGImage implements JsonSerializable { $query = "SELECT id FROM images "; if ( !is_null($filter) ) { - $query .= "WHERE filename LIKE :filter "; + $query .= "WHERE filename LIKE :filter OR ocr LIKE :filter "; } $query .= "ORDER BY LOWER(filename)"; $sth = $globaldbh->prepare($query); @@ -236,6 +261,7 @@ class MTGImage implements JsonSerializable { 'title' => pathinfo($this->getFileName(), PATHINFO_FILENAME), 'enabled' => $this->getEnabled(), 'played' => $this->getPlayed(), + 'cardtext' => $this->getOCR(), 'width' => $this->getWidth(), 'height' => $this->getHeight(), 'dimensions' => $this->getDimensions(), @@ -263,12 +289,13 @@ class MTGImage implements JsonSerializable { public function save() { global $globaldbh; - $query = "INSERT INTO images (id, filename, width, height) VALUES(:id, :filename, :width, :height) ON DUPLICATE KEY UPDATE filename=:filename, enabled=:enabled, played=:played, width=:width, height=:height"; + $query = "INSERT INTO images (id, filename, ocr, width, height) VALUES(:id, :filename, :ocr, :width, :height) ON DUPLICATE KEY UPDATE filename=:filename, enabled=:enabled, played=:played, ocr=:ocr, width=:width, height=:height"; $sth = $globaldbh->prepare($query); $sth->bindValue(":id", (int) $this->getId(), PDO::PARAM_INT); $sth->bindValue(":filename", $this->getFileName(), PDO::PARAM_STR); $sth->bindValue(":enabled", (int) $this->getEnabled(MTGImage::MTGI_BOOLEANDB), PDO::PARAM_INT); $sth->bindValue(":played", (int) $this->getPlayed(MTGImage::MTGI_BOOLEANDB), PDO::PARAM_INT); + $sth->bindValue(":ocr", $this->getOCR(), PDO::PARAM_STR); $sth->bindValue(":width", (int) $this->getWidth(), PDO::PARAM_INT); $sth->bindValue(":height", (int) $this->getHeight(), PDO::PARAM_INT); $sth->execute(); @@ -280,7 +307,7 @@ class MTGImage implements JsonSerializable { global $globaldbh; if ( !is_int($imgid) || $imgid == 0 ) return; - $query = "SELECT id, filename, enabled, played, width, height, created FROM images where id=:id"; + $query = "SELECT id, filename, enabled, played, ocr, width, height, created FROM images where id=:id"; $sth = $globaldbh->prepare($query); $sth->bindValue(":id", (int) $imgid, PDO::PARAM_INT); $sth->execute(); @@ -289,6 +316,7 @@ class MTGImage implements JsonSerializable { $this->setFileName($row["filename"]); $this->setEnabled($row["enabled"]); $this->setPlayed($row["played"]); + $this->setOCR($row["ocr"]); $this->setWidth($row["width"]); $this->setHeight($row["height"]); $this->created = $row["created"]; diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..acee0dc --- /dev/null +++ b/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "thiagoalessio/tesseract_ocr": "2.*" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..d18a1fe --- /dev/null +++ b/composer.lock @@ -0,0 +1,68 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "2fcc4ad110dab2a1eb87ee31f83940b4", + "packages": [ + { + "name": "thiagoalessio/tesseract_ocr", + "version": "2.13.0", + "source": { + "type": "git", + "url": "https://github.com/thiagoalessio/tesseract-ocr-for-php.git", + "reference": "232a8cb9d571992f9bd1e263f2f6909cf6c173a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thiagoalessio/tesseract-ocr-for-php/zipball/232a8cb9d571992f9bd1e263f2f6909cf6c173a1", + "reference": "232a8cb9d571992f9bd1e263f2f6909cf6c173a1", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/php-code-coverage": "^2.2.4 || ^9.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "thiagoalessio\\TesseractOCR\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "thiagoalessio", + "email": "thiagoalessio@me.com" + } + ], + "description": "A wrapper to work with Tesseract OCR inside PHP.", + "keywords": [ + "OCR", + "Tesseract", + "text recognition" + ], + "support": { + "irc": "irc://irc.freenode.net/tesseract-ocr-for-php", + "issues": "https://github.com/thiagoalessio/tesseract-ocr-for-php/issues", + "source": "https://github.com/thiagoalessio/tesseract-ocr-for-php" + }, + "time": "2023-10-05T21:14:48+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/header.php b/header.php index 8682399..8707deb 100644 --- a/header.php +++ b/header.php @@ -2,6 +2,7 @@ require_once "config.php"; require_once "functions.php"; +require_once 'vendor/autoload.php'; require_once "class_image.php"; diff --git a/install/initial_db_mysql.sql b/install/initial_db_mysql.sql index b685495..f7fcf7f 100644 --- a/install/initial_db_mysql.sql +++ b/install/initial_db_mysql.sql @@ -28,10 +28,12 @@ CREATE TABLE `images` ( `filename` varchar(255) NOT NULL, `enabled` tinyint(1) DEFAULT 1, `played` tinyint(1) DEFAULT 0, + `ocr` text DEFAULT '', `width` mediumint(8) unsigned NOT NULL DEFAULT 0, `height` mediumint(8) unsigned NOT NULL DEFAULT 0, `created` datetime NOT NULL DEFAULT current_timestamp(), - PRIMARY KEY (`id`) + PRIMARY KEY (`id`), + FULLTEXT KEY `idx_ocr` (`ocr`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; diff --git a/install/refreshocr.php b/install/refreshocr.php new file mode 100644 index 0000000..37ae419 --- /dev/null +++ b/install/refreshocr.php @@ -0,0 +1,19 @@ +updateOCR(); + if ( $updated === true ) { + $image->save(); + echo " Success on: {$image->getFileName()}\n"; + } else { + echo "Error: " . $updated; + } +} + +// vim: ts=4 sw=4: diff --git a/install/testocr.php b/install/testocr.php new file mode 100644 index 0000000..0322c55 --- /dev/null +++ b/install/testocr.php @@ -0,0 +1,32 @@ +lang('eng') // Set languages + ->run(); + + echo $text; +} catch (Exception $e) { + echo 'Error: ' . $e->getMessage(), "\n"; +} + +// vim: ts=4 sw=4: diff --git a/js/manage.js b/js/manage.js index 197d3b0..2437f7b 100644 --- a/js/manage.js +++ b/js/manage.js @@ -26,6 +26,7 @@ $(document).ready(function() { $(this).dialog("close"); $("#edit-props-id").val("0"); $("#edit-props-filename").val(""); + $("#edit-props-cardtext").val(""); $("#edit-props-enabled").prop("checked", false); }, "Save": saveCardProperties @@ -33,16 +34,13 @@ $(document).ready(function() { }); $("#searchfilter").on("keyup", function(event) { clearTimeout(typingTimer); - typingTimer = setTimeout(performSearch, 750); + typingTimer = setTimeout(showGallery, 750); }); showGallery(); }); -function performSearch() { - showGallery($("#searchfilter").val()); -} - -function showGallery(filter = "") { +function showGallery() { + filter = $("#searchfilter").val(); $.ajax({ url: 'ajax/getimages.php', data: {filter: filter}, @@ -183,6 +181,7 @@ function openEditDialog(imageId) { $("#edit-image").attr("src", "thumb.php?id="+imageId); $("#edit-props-id").val(imageId); $("#edit-props-filename").val(data.image.title); + $("#edit-props-cardtext").val(data.image.cardtext); $("#edit-props-enabled").prop("checked", data.image.enabled); $("#edit-props-dimensions").html(data.image.dimensions); $("#edit-props-size").html(data.image.size); @@ -196,6 +195,7 @@ function clearEditDialog() { $("#edit-image").attr("src", "img/error.png"); $("#edit-props-id").val("0"); $("#edit-props-filename").val(""); + $("#edit-props-cardtext").val(""); $("#edit-props-enabled").prop("checked", false); $("#edit-props-dimensions").html(""); $("#edit-props-size").html(""); @@ -230,8 +230,10 @@ function saveCardProperties() { data: { id: $("#edit-props-id").val(), filename: $("#edit-props-filename").val(), + cardtext: $("#edit-props-cardtext").val(), enabled: ($("#edit-props-enabled").prop("checked")) ? 1 : 0 }, + type: 'POST', success: function(data, stat, jqo) { if ( !data.error ) { clearEditDialog(); diff --git a/manage.php b/manage.php index f3a1fc7..2e0dc08 100644 --- a/manage.php +++ b/manage.php @@ -27,6 +27,10 @@ $files = MTGImage::getList(); File Name:
++ Card Text: + +
Enabled: