Scanner: do not decode whole images, just probe, ref #561
This commit is contained in:
@@ -27,6 +27,9 @@ if (${LMS_IMAGE_BACKEND} STREQUAL "stb")
|
|||||||
target_sources(lmsimage PRIVATE
|
target_sources(lmsimage PRIVATE
|
||||||
impl/stb/Image.cpp
|
impl/stb/Image.cpp
|
||||||
impl/stb/RawImage.cpp
|
impl/stb/RawImage.cpp
|
||||||
|
impl/stb/StbImage.cpp
|
||||||
|
impl/stb/StbImageResize.cpp
|
||||||
|
impl/stb/StbImageWrite.cpp
|
||||||
)
|
)
|
||||||
target_compile_options(lmsimage PRIVATE "-DSTB_IMAGE_RESIZE_VERSION=${STB_IMAGE_RESIZE_VERSION}")
|
target_compile_options(lmsimage PRIVATE "-DSTB_IMAGE_RESIZE_VERSION=${STB_IMAGE_RESIZE_VERSION}")
|
||||||
target_include_directories(lmsimage PRIVATE ${STB_IMAGE_INCLUDE_DIR})
|
target_include_directories(lmsimage PRIVATE ${STB_IMAGE_INCLUDE_DIR})
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include <Magick++/Image.h>
|
||||||
|
|
||||||
#include "core/ILogger.hpp"
|
#include "core/ILogger.hpp"
|
||||||
#include "core/ITraceLogger.hpp"
|
#include "core/ITraceLogger.hpp"
|
||||||
#include "image/Exception.hpp"
|
#include "image/Exception.hpp"
|
||||||
@@ -53,6 +55,28 @@ namespace lms::image
|
|||||||
return fileExtensions;
|
return fileExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImageProperties probeImage(const std::filesystem::path& path)
|
||||||
|
{
|
||||||
|
LMS_SCOPED_TRACE_DETAILED("Image", "ProbeFile");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Magick::Image image;
|
||||||
|
image.ping(path.c_str());
|
||||||
|
|
||||||
|
ImageProperties properties;
|
||||||
|
properties.width = image.size().width();
|
||||||
|
properties.height = image.size().height();
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
catch (Magick::Exception& e)
|
||||||
|
{
|
||||||
|
LMS_LOG(COVER, ERROR, "Caught Magick exception: " << e.what());
|
||||||
|
throw Exception{ std::string{ "Magick probe error: " } + e.what() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<IRawImage> decodeImage(std::span<const std::byte> encodedData)
|
std::unique_ptr<IRawImage> decodeImage(std::span<const std::byte> encodedData)
|
||||||
{
|
{
|
||||||
LMS_SCOPED_TRACE_DETAILED("Image", "DecodeBuffer");
|
LMS_SCOPED_TRACE_DETAILED("Image", "DecodeBuffer");
|
||||||
|
|||||||
@@ -21,14 +21,14 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
#include "StbImage.hpp"
|
||||||
#include <stb_image_write.h>
|
#include "StbImageWrite.hpp"
|
||||||
|
|
||||||
#include "core/ITraceLogger.hpp"
|
#include "core/ITraceLogger.hpp"
|
||||||
|
#include "image/Exception.hpp"
|
||||||
|
|
||||||
#include "EncodedImage.hpp"
|
#include "EncodedImage.hpp"
|
||||||
#include "RawImage.hpp"
|
#include "RawImage.hpp"
|
||||||
#include "image/Exception.hpp"
|
|
||||||
|
|
||||||
namespace lms::image
|
namespace lms::image
|
||||||
{
|
{
|
||||||
@@ -42,6 +42,24 @@ namespace lms::image
|
|||||||
return fileExtensions;
|
return fileExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImageProperties probeImage(const std::filesystem::path& path)
|
||||||
|
{
|
||||||
|
LMS_SCOPED_TRACE_DETAILED("Image", "ProbeFile");
|
||||||
|
|
||||||
|
int x{};
|
||||||
|
int y{};
|
||||||
|
int comp{};
|
||||||
|
|
||||||
|
if (::stbi_info(path.c_str(), &x, &y, &comp) == 0)
|
||||||
|
throw StbiException{ "Probe failed" };
|
||||||
|
|
||||||
|
ImageProperties properties;
|
||||||
|
properties.width = x;
|
||||||
|
properties.height = y;
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<IRawImage> decodeImage(std::span<const std::byte> encodedData)
|
std::unique_ptr<IRawImage> decodeImage(std::span<const std::byte> encodedData)
|
||||||
{
|
{
|
||||||
LMS_SCOPED_TRACE_DETAILED("Image", "DecodeBuffer");
|
LMS_SCOPED_TRACE_DETAILED("Image", "DecodeBuffer");
|
||||||
|
|||||||
@@ -19,22 +19,8 @@
|
|||||||
|
|
||||||
#include "RawImage.hpp"
|
#include "RawImage.hpp"
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#include "StbImage.hpp"
|
||||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
#include "StbImageResize.hpp"
|
||||||
|
|
||||||
#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL
|
|
||||||
#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
|
|
||||||
|
|
||||||
#define STBI_FAILURE_USERMSG
|
|
||||||
|
|
||||||
#include <stb_image.h>
|
|
||||||
#if STB_IMAGE_RESIZE_VERSION == 1
|
|
||||||
#include <stb_image_resize.h>
|
|
||||||
#elif STB_IMAGE_RESIZE_VERSION == 2
|
|
||||||
#include <stb_image_resize2.h>
|
|
||||||
#else
|
|
||||||
#error "Unhandled STB image resize version"!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "core/ITraceLogger.hpp"
|
#include "core/ITraceLogger.hpp"
|
||||||
#include "image/Exception.hpp"
|
#include "image/Exception.hpp"
|
||||||
@@ -43,21 +29,7 @@ namespace lms::image::STB
|
|||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
class StbiException : public Exception
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
StbiException(std::string_view desc)
|
|
||||||
: Exception{ std::string{ desc } + ": " + getLastFailureReason() }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static std::string getLastFailureReason()
|
|
||||||
{
|
|
||||||
const char* failureReason{ ::stbi_failure_reason() };
|
|
||||||
return failureReason ? failureReason : "unknown reason";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
RawImage::RawImage(std::span<const std::byte> encodedData)
|
RawImage::RawImage(std::span<const std::byte> encodedData)
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Emeric Poupon
|
||||||
|
*
|
||||||
|
* This file is part of LMS.
|
||||||
|
*
|
||||||
|
* LMS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LMS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "StbImage.hpp"
|
||||||
|
|
||||||
|
namespace lms::image
|
||||||
|
{
|
||||||
|
StbiException::StbiException(std::string_view desc)
|
||||||
|
: Exception{ std::string{ desc } + ": " + getLastFailureReason() }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StbiException::getLastFailureReason()
|
||||||
|
{
|
||||||
|
const char* failureReason{ ::stbi_failure_reason() };
|
||||||
|
return failureReason ? failureReason : "unknown reason";
|
||||||
|
}
|
||||||
|
} // namespace lms::image
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Emeric Poupon
|
||||||
|
*
|
||||||
|
* This file is part of LMS.
|
||||||
|
*
|
||||||
|
* LMS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LMS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define STBI_ONLY_JPEG
|
||||||
|
#define STBI_ONLY_PNG
|
||||||
|
#define STBI_ONLY_BMP
|
||||||
|
#define STBI_FAILURE_USERMSG
|
||||||
|
|
||||||
|
#include <stb_image.h>
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include "image/Exception.hpp"
|
||||||
|
|
||||||
|
namespace lms::image
|
||||||
|
{
|
||||||
|
class StbiException : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StbiException(std::string_view desc);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::string getLastFailureReason();
|
||||||
|
};
|
||||||
|
} // namespace lms::image
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Emeric Poupon
|
||||||
|
*
|
||||||
|
* This file is part of LMS.
|
||||||
|
*
|
||||||
|
* LMS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LMS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||||
|
#include "StbImageResize.hpp"
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Emeric Poupon
|
||||||
|
*
|
||||||
|
* This file is part of LMS.
|
||||||
|
*
|
||||||
|
* LMS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LMS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL
|
||||||
|
#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
|
||||||
|
|
||||||
|
#if STB_IMAGE_RESIZE_VERSION == 1
|
||||||
|
#include <stb_image_resize.h>
|
||||||
|
#elif STB_IMAGE_RESIZE_VERSION == 2
|
||||||
|
#include <stb_image_resize2.h>
|
||||||
|
#else
|
||||||
|
#error "Unhandled STB image resize version"!
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Emeric Poupon
|
||||||
|
*
|
||||||
|
* This file is part of LMS.
|
||||||
|
*
|
||||||
|
* LMS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LMS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
#include "StbImageWrite.hpp"
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Emeric Poupon
|
||||||
|
*
|
||||||
|
* This file is part of LMS.
|
||||||
|
*
|
||||||
|
* LMS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LMS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stb_image_write.h>
|
||||||
@@ -31,6 +31,9 @@ namespace lms::image
|
|||||||
void init(const std::filesystem::path& path);
|
void init(const std::filesystem::path& path);
|
||||||
std::span<const std::filesystem::path> getSupportedFileExtensions();
|
std::span<const std::filesystem::path> getSupportedFileExtensions();
|
||||||
|
|
||||||
|
// All these methods may throw Exception
|
||||||
|
ImageProperties probeImage(const std::filesystem::path& path);
|
||||||
|
|
||||||
std::unique_ptr<IRawImage> decodeImage(std::span<const std::byte> encodedData);
|
std::unique_ptr<IRawImage> decodeImage(std::span<const std::byte> encodedData);
|
||||||
std::unique_ptr<IRawImage> decodeImage(const std::filesystem::path& path);
|
std::unique_ptr<IRawImage> decodeImage(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
|||||||
@@ -22,4 +22,10 @@
|
|||||||
namespace lms::image
|
namespace lms::image
|
||||||
{
|
{
|
||||||
using ImageSize = std::size_t;
|
using ImageSize = std::size_t;
|
||||||
}
|
|
||||||
|
struct ImageProperties
|
||||||
|
{
|
||||||
|
ImageSize width{};
|
||||||
|
ImageSize height{};
|
||||||
|
};
|
||||||
|
} // namespace lms::image
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
#include "database/MediaLibrary.hpp"
|
#include "database/MediaLibrary.hpp"
|
||||||
#include "database/Session.hpp"
|
#include "database/Session.hpp"
|
||||||
#include "image/Exception.hpp"
|
#include "image/Exception.hpp"
|
||||||
|
#include "image/IRawImage.hpp"
|
||||||
#include "image/Image.hpp"
|
#include "image/Image.hpp"
|
||||||
|
|
||||||
#include "IFileScanOperation.hpp"
|
#include "IFileScanOperation.hpp"
|
||||||
@@ -55,29 +56,18 @@ namespace lms::scanner
|
|||||||
const MediaLibraryInfo _mediaLibrary;
|
const MediaLibraryInfo _mediaLibrary;
|
||||||
db::Db& _db;
|
db::Db& _db;
|
||||||
|
|
||||||
struct ImageInfo
|
std::optional<image::ImageProperties> _parsedImageProperties;
|
||||||
{
|
|
||||||
std::size_t height{};
|
|
||||||
std::size_t width{};
|
|
||||||
};
|
|
||||||
std::optional<ImageInfo> _parsedImageInfo;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void ImageFileScanOperation::scan()
|
void ImageFileScanOperation::scan()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::unique_ptr<image::IRawImage> rawImage{ image::decodeImage(_file) };
|
_parsedImageProperties = image::probeImage(_file);
|
||||||
|
|
||||||
ImageInfo imageInfo;
|
|
||||||
imageInfo.width = rawImage->getWidth();
|
|
||||||
imageInfo.height = rawImage->getHeight();
|
|
||||||
|
|
||||||
_parsedImageInfo = imageInfo;
|
|
||||||
}
|
}
|
||||||
catch (const image::Exception& e)
|
catch (const image::Exception& e)
|
||||||
{
|
{
|
||||||
_parsedImageInfo.reset();
|
_parsedImageProperties.reset();
|
||||||
LMS_LOG(DBUPDATER, ERROR, "Cannot read image in file " << _file << ": " << e.what());
|
LMS_LOG(DBUPDATER, ERROR, "Cannot read image in file " << _file << ": " << e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,7 +86,7 @@ namespace lms::scanner
|
|||||||
db::Session& dbSession{ _db.getTLSSession() };
|
db::Session& dbSession{ _db.getTLSSession() };
|
||||||
db::Image::pointer image{ db::Image::find(dbSession, _file) };
|
db::Image::pointer image{ db::Image::find(dbSession, _file) };
|
||||||
|
|
||||||
if (!_parsedImageInfo)
|
if (!_parsedImageProperties)
|
||||||
{
|
{
|
||||||
if (image)
|
if (image)
|
||||||
{
|
{
|
||||||
@@ -114,8 +104,8 @@ namespace lms::scanner
|
|||||||
|
|
||||||
image.modify()->setLastWriteTime(fileInfo->lastWriteTime);
|
image.modify()->setLastWriteTime(fileInfo->lastWriteTime);
|
||||||
image.modify()->setFileSize(fileInfo->fileSize);
|
image.modify()->setFileSize(fileInfo->fileSize);
|
||||||
image.modify()->setHeight(_parsedImageInfo->height);
|
image.modify()->setHeight(_parsedImageProperties->height);
|
||||||
image.modify()->setWidth(_parsedImageInfo->width);
|
image.modify()->setWidth(_parsedImageProperties->width);
|
||||||
db::MediaLibrary::pointer mediaLibrary{ db::MediaLibrary::find(dbSession, _mediaLibrary.id) }; // may be null if settings are updated in // => next scan will correct this
|
db::MediaLibrary::pointer mediaLibrary{ db::MediaLibrary::find(dbSession, _mediaLibrary.id) }; // may be null if settings are updated in // => next scan will correct this
|
||||||
image.modify()->setDirectory(utils::getOrCreateDirectory(dbSession, _file.parent_path(), mediaLibrary));
|
image.modify()->setDirectory(utils::getOrCreateDirectory(dbSession, _file.parent_path(), mediaLibrary));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user