Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for HEIC/HEIF/TIFF #365

Merged
merged 5 commits into from
Oct 12, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions lib/Classifiers/Audio/MusicnnClassifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use OCA\Recognize\Service\TagManager;
use OCP\Files\IRootFolder;
use OCP\IConfig;
use OCP\ITempManager;

class MusicnnClassifier extends Classifier {
public const AUDIO_TIMEOUT = 40; // seconds
Expand All @@ -22,8 +23,8 @@ class MusicnnClassifier extends Classifier {
private TagManager $tagManager;
private IConfig $config;

public function __construct(Logger $logger, IConfig $config, TagManager $tagManager, QueueService $queue, IRootFolder $rootFolder) {
parent::__construct($logger, $config, $rootFolder, $queue);
public function __construct(Logger $logger, IConfig $config, TagManager $tagManager, QueueService $queue, IRootFolder $rootFolder, ITempManager $tempManager) {
parent::__construct($logger, $config, $rootFolder, $queue, $tempManager);
$this->config = $config;
$this->tagManager = $tagManager;
}
Expand Down
52 changes: 50 additions & 2 deletions lib/Classifiers/Classifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@

namespace OCA\Recognize\Classifiers;

use OC\Files\Node\Node;
use OCA\Recognize\Constants;
use OCA\Recognize\Service\Logger;
use OCA\Recognize\Service\QueueService;
use OCP\DB\Exception;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\IConfig;
use OCP\ITempManager;
use Psr\Log\LoggerInterface;
use Symfony\Component\Process\Exception\ProcessTimedOutException;
use Symfony\Component\Process\Exception\RuntimeException;
Expand All @@ -23,12 +26,14 @@ class Classifier {
private IConfig $config;
private IRootFolder $rootFolder;
private QueueService $queue;
private ITempManager $tempManager;

public function __construct(Logger $logger, IConfig $config, IRootFolder $rootFolder, QueueService $queue) {
public function __construct(Logger $logger, IConfig $config, IRootFolder $rootFolder, QueueService $queue, ITempManager $tempManager) {
$this->logger = $logger;
$this->config = $config;
$this->rootFolder = $rootFolder;
$this->queue = $queue;
$this->tempManager = $tempManager;
}

/**
Expand All @@ -46,7 +51,7 @@ public function classifyFiles(string $model, array $queueFiles, int $timeout): \
continue;
}
try {
$paths[] = $files[0]->getStorage()->getLocalFile($files[0]->getInternalPath());
$paths[] = $this->getConvertedFilePath($files[0]);
$processedFiles[] = $queueFile;
} catch (NotFoundException $e) {
$this->logger->warning('Could not find file', ['exception' => $e]);
Expand Down Expand Up @@ -141,4 +146,47 @@ public function classifyFiles(string $model, array $queueFiles, int $timeout): \
throw new \RuntimeException('Classifier process could not be started');
}
}

/**
* Get path of file to process.
* If the file is an image and not JPEG, it will be converted using ImageMagick.
* Images will also be downscaled to a max dimension of 4096px.
*
* @param Node $file
* @return string Path to file to process
*/
private function getConvertedFilePath(Node $file): string {
$path = $file->getStorage()->getLocalFile($file->getInternalPath());

// check if this is an image to convert / downscale
$mime = $file->getMimeType();
if (!in_array($mime, Constants::IMAGE_FORMATS)) {
return $path;
}

// Check if ImageMagick is installed
if (!extension_loaded('imagick')) {
return $path;
}

// Create a temporary file *with the correct extension*
$tmpname = $this->tempManager->getTemporaryFile('.jpg');

try {
// Convert to a temporary JPEG file optionally downscaling
$imagick = new \Imagick($path);
$dimensions = $imagick->getImageGeometry();
if ($dimensions['width'] > 4096 || $dimensions['height'] > 4096) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Imagick before 3.0.0 used to leave the image untouched if it was smaller than the specified scaling; I didn't know the behavior had changed.

// downscale
$imagick->scaleImage(4096, 4096, true);
}
$imagick->setImageFormat('jpeg');
$imagick->writeImage($tmpname);
} catch (\ImagickException $e) {
// If conversion fails, just use the original file
return $path;
}

return $tmpname;
}
}
5 changes: 3 additions & 2 deletions lib/Classifiers/Images/ClusteringFaceClassifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use OCP\Files\Config\IUserMountCache;
use OCP\Files\IRootFolder;
use OCP\IConfig;
use OCP\ITempManager;

class ClusteringFaceClassifier extends Classifier {
public const IMAGE_TIMEOUT = 120; // seconds
Expand All @@ -33,8 +34,8 @@ class ClusteringFaceClassifier extends Classifier {
private IUserMountCache $userMountCache;
private IJobList $jobList;

public function __construct(Logger $logger, IConfig $config, FaceDetectionMapper $faceDetections, QueueService $queue, IRootFolder $rootFolder, IUserMountCache $userMountCache, IJobList $jobList) {
parent::__construct($logger, $config, $rootFolder, $queue);
public function __construct(Logger $logger, IConfig $config, FaceDetectionMapper $faceDetections, QueueService $queue, IRootFolder $rootFolder, IUserMountCache $userMountCache, IJobList $jobList, ITempManager $tempManager) {
parent::__construct($logger, $config, $rootFolder, $queue, $tempManager);
$this->logger = $logger;
$this->config = $config;
$this->faceDetections = $faceDetections;
Expand Down
5 changes: 3 additions & 2 deletions lib/Classifiers/Images/ImagenetClassifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use OCP\DB\Exception;
use OCP\Files\IRootFolder;
use OCP\IConfig;
use OCP\ITempManager;

class ImagenetClassifier extends Classifier {
public const IMAGE_TIMEOUT = 480; // seconds
Expand All @@ -25,8 +26,8 @@ class ImagenetClassifier extends Classifier {
private QueueService $queue;
private Logger $logger;

public function __construct(Logger $logger, IConfig $config, TagManager $tagManager, QueueService $queue, IRootFolder $rootFolder) {
parent::__construct($logger, $config, $rootFolder, $queue);
public function __construct(Logger $logger, IConfig $config, TagManager $tagManager, QueueService $queue, IRootFolder $rootFolder, ITempManager $tempManager) {
parent::__construct($logger, $config, $rootFolder, $queue, $tempManager);
$this->config = $config;
$this->tagManager = $tagManager;
$this->queue = $queue;
Expand Down
5 changes: 3 additions & 2 deletions lib/Classifiers/Images/LandmarksClassifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use OCA\Recognize\Service\TagManager;
use OCP\Files\IRootFolder;
use OCP\IConfig;
use OCP\ITempManager;

class LandmarksClassifier extends Classifier {
public const IMAGE_TIMEOUT = 480; // seconds
Expand All @@ -24,8 +25,8 @@ class LandmarksClassifier extends Classifier {
private TagManager $tagManager;
private IConfig $config;

public function __construct(Logger $logger, IConfig $config, TagManager $tagManager, QueueService $queue, IRootFolder $rootFolder) {
parent::__construct($logger, $config, $rootFolder, $queue);
public function __construct(Logger $logger, IConfig $config, TagManager $tagManager, QueueService $queue, IRootFolder $rootFolder, ITempManager $tempManager) {
parent::__construct($logger, $config, $rootFolder, $queue, $tempManager);
$this->logger = $logger;
$this->config = $config;
$this->tagManager = $tagManager;
Expand Down
5 changes: 3 additions & 2 deletions lib/Classifiers/Video/MovinetClassifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use OCA\Recognize\Service\TagManager;
use OCP\Files\IRootFolder;
use OCP\IConfig;
use OCP\ITempManager;

class MovinetClassifier extends Classifier {
public const VIDEO_TIMEOUT = 480; // seconds
Expand All @@ -22,8 +23,8 @@ class MovinetClassifier extends Classifier {
private TagManager $tagManager;
private IConfig $config;

public function __construct(Logger $logger, IConfig $config, TagManager $tagManager, QueueService $queue, IRootFolder $rootFolder) {
parent::__construct($logger, $config, $rootFolder, $queue);
public function __construct(Logger $logger, IConfig $config, TagManager $tagManager, QueueService $queue, IRootFolder $rootFolder, ITempManager $tempManager) {
parent::__construct($logger, $config, $rootFolder, $queue, $tempManager);
$this->config = $config;
$this->tagManager = $tagManager;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Constants.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace OCA\Recognize;

class Constants {
public const IMAGE_FORMATS = ['image/jpeg', 'image/png', 'image/bmp'];
public const IMAGE_FORMATS = ['image/jpeg', 'image/png', 'image/bmp', 'image/heic', 'image/heif', 'image/tiff'];
public const AUDIO_FORMATS = ['audio/mpeg', 'audio/mp4', 'audio/ogg', 'audio/vnd.wav', 'audio/flac'];
public const VIDEO_FORMATS = ['image/gif', 'video/mp4', 'video/MP2T', 'video/x-msvideo', 'video/x-ms-wmv', 'video/quicktime', 'video/ogg', 'video/mpeg', 'video/webm', 'video/x-matroska'];
public const MAX_FILE_SIZE = 10000000;
Expand Down