Introduced lmscore lib to centralize services, migrated cover service

This commit is contained in:
emeric
2021-10-16 15:22:59 +02:00
parent 0dcef2e94c
commit 32a944e3d4
26 changed files with 149 additions and 106 deletions
@@ -0,0 +1,55 @@
/*
* 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/>.
*/
#include "JPEGImage.hpp"
#include "Exception.hpp"
#include "RawImage.hpp"
#include "utils/Logger.hpp"
namespace CoverArt::GraphicsMagick
{
JPEGImage::JPEGImage(const RawImage& rawImage, unsigned quality)
{
try
{
Magick::Image image {rawImage.getMagickImage()};
image.magick("JPEG");
image.quality(quality);
image.write(&_blob);
}
catch (Magick::Exception& e)
{
LMS_LOG(COVER, ERROR) << "Caught Magick exception: " << e.what();
throw ImageException {std::string {"Magick read error: "} + e.what()};
}
}
const std::byte*
JPEGImage::getData() const
{
return reinterpret_cast<const std::byte*>(_blob.data());
}
std::size_t
JPEGImage::getDataSize() const
{
return _blob.length();
}
}
@@ -0,0 +1,45 @@
/*
* 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
#ifndef LMS_SUPPORT_IMAGE_GM
#error "Bad configuration"
#endif
#include <Magick++.h>
#include "cover/IEncodedImage.hpp"
namespace CoverArt::GraphicsMagick
{
class RawImage;
class JPEGImage : public IEncodedImage
{
public:
JPEGImage(const RawImage& rawImage, unsigned quality);
private:
const std::byte* getData() const override;
std::size_t getDataSize() const override;
std::string_view getMimeType() const override { return "image/jpeg"; }
Magick::Blob _blob;
};
}
@@ -0,0 +1,129 @@
/*
* Copyright (C) 2015 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/>.
*/
#include "RawImage.hpp"
#include <magick/resource.h>
#include "utils/Logger.hpp"
#include "JPEGImage.hpp"
#include "Exception.hpp"
namespace Image::GraphicsMagick
{
std::unique_ptr<IRawImage> decodeImage(const std::byte* encodedData, std::size_t encodedDataSize)
{
return std::make_unique<RawImage>(encodedData, encodedDataSize);
}
std::unique_ptr<IRawImage> decodeImage(const std::filesystem::path& path)
{
void
init(const std::filesystem::path& path)
{
Magick::InitializeMagick(path.string().c_str());
if (auto nbThreads {MagickLib::GetMagickResourceLimit(MagickLib::ThreadsResource)}; nbThreads != 1)
LMS_LOG(COVER, WARNING) << "Consider setting env var OMP_NUM_THREADS=1 to save resources";
if (!MagickLib::SetMagickResourceLimit(MagickLib::ThreadsResource, 1))
LMS_LOG(COVER, ERROR) << "Cannot set Magick thread resource limit to 1!";
if (!MagickLib::SetMagickResourceLimit(MagickLib::DiskResource, 0))
LMS_LOG(COVER, ERROR) << "Cannot set Magick disk resource limit to 0!";
LMS_LOG(COVER, INFO) << "Magick threads resource limit = " << GetMagickResourceLimit(MagickLib::ThreadsResource);
LMS_LOG(COVER, INFO) << "Magick Disk resource limit = " << GetMagickResourceLimit(MagickLib::DiskResource);
}
RawImage::RawImage(const std::byte* encodedData, std::size_t encodedDataSize)
{
try
{
Magick::Blob blob {encodedData, encodedDataSize};
_image.read(blob);
}
catch (Magick::WarningCoder& e)
{
LMS_LOG(COVER, WARNING) << "Caught Magick WarningCoder: " << e.what();
}
catch (Magick::Warning& e)
{
LMS_LOG(COVER, WARNING) << "Caught Magick warning: " << e.what();
throw ImageException {std::string {"Magick read warning: "} + e.what()};
}
catch (Magick::Exception& e)
{
LMS_LOG(COVER, ERROR) << "Caught Magick exception: " << e.what();
throw ImageException {std::string {"Magick read error: "} + e.what()};
}
}
RawImage::RawImage(const std::filesystem::path& p)
{
try
{
_image.read(p.string().c_str());
}
catch (Magick::WarningCoder& e)
{
LMS_LOG(COVER, WARNING) << "Caught Magick WarningCoder: " << e.what();
}
catch (Magick::Warning& e)
{
LMS_LOG(COVER, WARNING) << "Caught Magick warning: " << e.what();
throw ImageException {std::string {"Magick read warning: "} + e.what()};
}
catch (Magick::Exception& e)
{
LMS_LOG(COVER, ERROR) << "Caught Magick exception: " << e.what();
throw ImageException {std::string {"Magick read error: "} + e.what()};
}
}
void
RawImage::resize(ImageSize width)
{
try
{
_image.resize(Magick::Geometry {static_cast<unsigned int>(width), static_cast<unsigned int>(width)});
}
catch (Magick::Exception& e)
{
LMS_LOG(COVER, ERROR) << "Caught Magick exception while resizing: " << e.what();
throw ImageException {std::string {"Magick resize error: "} + e.what()};
}
}
std::unique_ptr<IEncodedImage>
RawImage::encodeToJPEG(unsigned quality) const
{
return std::make_unique<JPEGImage>(*this, quality);
}
Magick::Image
RawImage::getMagickImage() const
{
return _image;
}
} // namespace Image::GraphicsMagick
@@ -0,0 +1,54 @@
/*
* 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
#ifndef LMS_SUPPORT_IMAGE_GM
#error "Bad configuration"
#endif
#include <Magick++.h>
#include <cstddef>
#include <filesystem>
#include "cover/IEncodedImage.hpp"
#include "IRawImage.hpp"
namespace CoverArt::GraphicsMagick
{
void init(const std::filesystem::path& path);
class RawImage : IRawImage
{
public:
RawImage(const std::byte* encodedData, std::size_t encodedDataSize);
RawImage(const std::filesystem::path& path);
void resize(ImageSize width) override;
std::unique_ptr<IEncodedImage> encodeToJPEG(unsigned quality) const override;
private:
friend class JPEGImage;
Magick::Image getMagickImage() const;
Magick::Image _image;
};
}
+61
View File
@@ -0,0 +1,61 @@
/*
* 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/>.
*/
#include "JPEGImage.hpp"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb/stb_image_write.h>
#include "image/Exception.hpp"
#include "RawImage.hpp"
namespace Image::STB
{
JPEGImage::JPEGImage(const RawImage& rawImage, unsigned quality)
{
auto writeCb {[](void* ctx, void* writeData, int writeSize)
{
auto& output {*reinterpret_cast<std::vector<std::byte>*>(ctx)};
const std::size_t currentOutputSize {output.size()};
output.resize(currentOutputSize + writeSize);
std::copy(reinterpret_cast<const std::byte*>(writeData), reinterpret_cast<const std::byte*>(writeData) + writeSize, output.data() + currentOutputSize);
}};
if (stbi_write_jpg_to_func(writeCb, &_data, rawImage.getWidth(), rawImage.getHeight(), 3, rawImage.getData(), quality) == 0)
{
_data.clear();
throw ImageException {"Failed to export in jpeg format!"};
}
}
const std::byte*
JPEGImage::getData() const
{
if (_data.empty())
return nullptr;
return &_data.front();
}
std::size_t
JPEGImage::getDataSize() const
{
return _data.size();
}
}
+41
View File
@@ -0,0 +1,41 @@
/*
* 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 <vector>
#include "image/IEncodedImage.hpp"
namespace Image::STB
{
class RawImage;
class JPEGImage : public IEncodedImage
{
public:
JPEGImage(const RawImage& rawImage, unsigned quality);
private:
const std::byte* getData() const override;
std::size_t getDataSize() const override;
std::string_view getMimeType() const override { return "image/jpeg"; }
std::vector<std::byte> _data;
};
}
+127
View File
@@ -0,0 +1,127 @@
/*
* 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/>.
*/
#include "RawImage.hpp"
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL
#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
#include <stb/stb_image.h>
#include <stb/stb_image_resize.h>
#include "JPEGImage.hpp"
#include "image/Exception.hpp"
namespace Image
{
std::unique_ptr<IRawImage> decodeImage(const std::byte* encodedData, std::size_t encodedDataSize)
{
return std::make_unique<STB::RawImage>(encodedData, encodedDataSize);
}
std::unique_ptr<IRawImage> decodeImage(const std::filesystem::path& path)
{
return std::make_unique<STB::RawImage>(path);
}
}
namespace Image::STB
{
RawImage::RawImage(const std::byte* encodedData, std::size_t encodedDataSize)
{
int n;
_data = UniquePtrFree {stbi_load_from_memory(reinterpret_cast<const stbi_uc*>(encodedData), encodedDataSize, &_width, &_height, &n, 3), std::free};
if (!_data)
throw ImageException {"Cannot load image from memory"};
}
RawImage::RawImage(const std::filesystem::path& p)
{
int n;
_data = UniquePtrFree {stbi_load(p.string().c_str(), &_width, &_height, &n, 3), std::free};
if (!_data)
throw ImageException {"Cannot load image from memory"};
}
void
RawImage::resize(ImageSize width)
{
size_t height;
if (_width == _height)
{
height = width;
}
else if (_width > _height)
{
height = (size_t)((float)width/_width*_height);
}
else
{
height = width;
width = (size_t)((float)height/_height*_width);
}
UniquePtrFree resizedData {reinterpret_cast<unsigned char*>(malloc(width*height*3)), std::free};
if (!resizedData)
throw ImageException {"Cannot allocate memory for resized image!"};
if (stbir_resize_uint8_srgb(reinterpret_cast<const unsigned char*>(_data.get()), _width, _height, 0,
reinterpret_cast<unsigned char*>(resizedData.get()), width, height, 0,
3, STBIR_ALPHA_CHANNEL_NONE, 0) == 0)
{
throw ImageException {"Failed to resize image!"};
}
_data = std::move(resizedData);
_height = height;
_width = width;
}
std::unique_ptr<IEncodedImage>
RawImage::encodeToJPEG(unsigned quality) const
{
return std::make_unique<JPEGImage>(*this, quality);
}
ImageSize
RawImage::getWidth() const
{
return _width;
}
ImageSize
RawImage::getHeight() const
{
return _height;
}
const std::byte*
RawImage::getData() const
{
if (!_data)
return nullptr;
return reinterpret_cast<const std::byte*>(_data.get());
}
}
+54
View File
@@ -0,0 +1,54 @@
/*
* 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
#ifndef LMS_SUPPORT_IMAGE_STB
#error "Bad configuration"
#endif
#include <cstddef>
#include <filesystem>
#include "image/IEncodedImage.hpp"
#include "image/IRawImage.hpp"
namespace Image::STB
{
class RawImage : public IRawImage
{
public:
RawImage(const std::byte* encodedData, std::size_t encodedDataSize);
RawImage(const std::filesystem::path& path);
void resize(ImageSize width) override;
std::unique_ptr<IEncodedImage> encodeToJPEG(unsigned quality) const override;
ImageSize getWidth() const;
ImageSize getHeight() const;
const std::byte* getData() const;
private:
int _width;
int _height;
using UniquePtrFree = std::unique_ptr<unsigned char, decltype(&std::free)>;
UniquePtrFree _data {nullptr, std::free};
};
}