diff options
author | Ryan Rector <rmrector@gmail.com> | 2023-08-02 18:53:32 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-02 18:53:32 -0600 |
commit | 89cc33615d0c755daa69adb4ae4b583d80bb6eac (patch) | |
tree | 2e3f73b742ea45a3def2f26d4bcc6a1b6c49e92f | |
parent | e9718f7ef9e663f7bc5bf97a6369697cad74e69b (diff) | |
parent | 5ae6b0fa1302894f30913634242ca6510a62fd13 (diff) |
Merge pull request #23517 from rmrector/picturefolder-thumbnails
[guilib][vfs][imagecache] Load picture folder images into texture cache when viewed, like standard images
-rw-r--r-- | xbmc/TextureCache.cpp | 3 | ||||
-rw-r--r-- | xbmc/TextureCacheJob.cpp | 3 | ||||
-rw-r--r-- | xbmc/imagefiles/SpecialImageFileLoader.h | 6 | ||||
-rw-r--r-- | xbmc/imagefiles/SpecialImageLoaderFactory.cpp | 2 | ||||
-rw-r--r-- | xbmc/imagefiles/SpecialImageLoaderFactory.h | 2 | ||||
-rw-r--r-- | xbmc/music/MusicEmbeddedImageFileLoader.cpp | 6 | ||||
-rw-r--r-- | xbmc/music/MusicEmbeddedImageFileLoader.h | 6 | ||||
-rw-r--r-- | xbmc/pictures/CMakeLists.txt | 2 | ||||
-rw-r--r-- | xbmc/pictures/Picture.cpp | 85 | ||||
-rw-r--r-- | xbmc/pictures/Picture.h | 3 | ||||
-rw-r--r-- | xbmc/pictures/PictureFolderImageFileLoader.cpp | 63 | ||||
-rw-r--r-- | xbmc/pictures/PictureFolderImageFileLoader.h | 27 | ||||
-rw-r--r-- | xbmc/pictures/PictureThumbLoader.cpp | 24 | ||||
-rw-r--r-- | xbmc/video/VideoEmbeddedImageFileLoader.cpp | 6 | ||||
-rw-r--r-- | xbmc/video/VideoEmbeddedImageFileLoader.h | 6 | ||||
-rw-r--r-- | xbmc/video/VideoGeneratedImageFileLoader.cpp | 8 | ||||
-rw-r--r-- | xbmc/video/VideoGeneratedImageFileLoader.h | 6 |
17 files changed, 207 insertions, 51 deletions
diff --git a/xbmc/TextureCache.cpp b/xbmc/TextureCache.cpp index 0ddccb727d..e0a5e2d906 100644 --- a/xbmc/TextureCache.cpp +++ b/xbmc/TextureCache.cpp @@ -97,7 +97,8 @@ std::string CTextureCache::GetCachedImage(const std::string &image, CTextureDeta bool CTextureCache::CanCacheImageURL(const CURL &url) { return url.GetUserName().empty() || url.GetUserName() == "music" || - url.GetUserName() == "video" || StringUtils::StartsWith(url.GetUserName(), "video_") || + url.GetUserName() == "video" || url.GetUserName() == "picturefolder" || + StringUtils::StartsWith(url.GetUserName(), "video_") || StringUtils::StartsWith(url.GetUserName(), "pvr") || StringUtils::StartsWith(url.GetUserName(), "epg"); } diff --git a/xbmc/TextureCacheJob.cpp b/xbmc/TextureCacheJob.cpp index 7a7c555532..cc9eb4e34d 100644 --- a/xbmc/TextureCacheJob.cpp +++ b/xbmc/TextureCacheJob.cpp @@ -149,7 +149,8 @@ std::string CTextureCacheJob::DecodeImageURL(const std::string &url, unsigned in if (!CTextureCache::CanCacheImageURL(thumbURL)) return ""; - if (thumbURL.GetUserName() == "music" || thumbURL.GetUserName() == "video") + if (thumbURL.GetUserName() == "music" || thumbURL.GetUserName() == "video" || + thumbURL.GetUserName() == "picturefolder") additional_info = thumbURL.GetUserName(); if (StringUtils::StartsWith(thumbURL.GetUserName(), "video_") || StringUtils::StartsWith(thumbURL.GetUserName(), "pvr") || diff --git a/xbmc/imagefiles/SpecialImageFileLoader.h b/xbmc/imagefiles/SpecialImageFileLoader.h index 18b3b03655..b409c9fbd6 100644 --- a/xbmc/imagefiles/SpecialImageFileLoader.h +++ b/xbmc/imagefiles/SpecialImageFileLoader.h @@ -25,9 +25,9 @@ namespace IMAGE_FILES class ISpecialImageFileLoader { public: - virtual bool CanLoad(std::string specialType) const = 0; - virtual std::unique_ptr<CTexture> Load(std::string specialType, - std::string filePath, + virtual bool CanLoad(const std::string& specialType) const = 0; + virtual std::unique_ptr<CTexture> Load(const std::string& specialType, + const std::string& filePath, unsigned int preferredWidth, unsigned int preferredHeight) const = 0; virtual ~ISpecialImageFileLoader() = default; diff --git a/xbmc/imagefiles/SpecialImageLoaderFactory.cpp b/xbmc/imagefiles/SpecialImageLoaderFactory.cpp index 639a4c1cd4..0fae961884 100644 --- a/xbmc/imagefiles/SpecialImageLoaderFactory.cpp +++ b/xbmc/imagefiles/SpecialImageLoaderFactory.cpp @@ -10,6 +10,7 @@ #include "guilib/Texture.h" #include "music/MusicEmbeddedImageFileLoader.h" +#include "pictures/PictureFolderImageFileLoader.h" #include "video/VideoEmbeddedImageFileLoader.h" #include "video/VideoGeneratedImageFileLoader.h" @@ -20,6 +21,7 @@ CSpecialImageLoaderFactory::CSpecialImageLoaderFactory() m_specialImageLoaders[0] = std::make_unique<VIDEO::CVideoEmbeddedImageFileLoader>(); m_specialImageLoaders[1] = std::make_unique<MUSIC_INFO::CMusicEmbeddedImageFileLoader>(); m_specialImageLoaders[2] = std::make_unique<VIDEO::CVideoGeneratedImageFileLoader>(); + m_specialImageLoaders[3] = std::make_unique<CPictureFolderImageFileLoader>(); } std::unique_ptr<CTexture> CSpecialImageLoaderFactory::Load(const std::string& specialType, diff --git a/xbmc/imagefiles/SpecialImageLoaderFactory.h b/xbmc/imagefiles/SpecialImageLoaderFactory.h index 3bf8f3ed5b..d633c617f1 100644 --- a/xbmc/imagefiles/SpecialImageLoaderFactory.h +++ b/xbmc/imagefiles/SpecialImageLoaderFactory.h @@ -29,6 +29,6 @@ public: unsigned int preferredHeight) const; private: - std::array<std::unique_ptr<ISpecialImageFileLoader>, 3> m_specialImageLoaders{}; + std::array<std::unique_ptr<ISpecialImageFileLoader>, 4> m_specialImageLoaders{}; }; } // namespace IMAGE_FILES diff --git a/xbmc/music/MusicEmbeddedImageFileLoader.cpp b/xbmc/music/MusicEmbeddedImageFileLoader.cpp index c93ee2bc46..212f51823f 100644 --- a/xbmc/music/MusicEmbeddedImageFileLoader.cpp +++ b/xbmc/music/MusicEmbeddedImageFileLoader.cpp @@ -17,7 +17,7 @@ using namespace MUSIC_INFO; -bool CMusicEmbeddedImageFileLoader::CanLoad(std::string specialType) const +bool CMusicEmbeddedImageFileLoader::CanLoad(const std::string& specialType) const { return specialType == "music"; } @@ -36,8 +36,8 @@ bool GetEmbeddedThumb(const std::string& path, EmbeddedArt& art) } } // namespace -std::unique_ptr<CTexture> CMusicEmbeddedImageFileLoader::Load(std::string specialType, - std::string filePath, +std::unique_ptr<CTexture> CMusicEmbeddedImageFileLoader::Load(const std::string& specialType, + const std::string& filePath, unsigned int preferredWidth, unsigned int preferredHeight) const { diff --git a/xbmc/music/MusicEmbeddedImageFileLoader.h b/xbmc/music/MusicEmbeddedImageFileLoader.h index 95a2db7e12..45381edde8 100644 --- a/xbmc/music/MusicEmbeddedImageFileLoader.h +++ b/xbmc/music/MusicEmbeddedImageFileLoader.h @@ -19,9 +19,9 @@ public: CMusicEmbeddedImageFileLoader() = default; ~CMusicEmbeddedImageFileLoader() override = default; - bool CanLoad(std::string specialType) const override; - std::unique_ptr<CTexture> Load(std::string specialType, - std::string filePath, + bool CanLoad(const std::string& specialType) const override; + std::unique_ptr<CTexture> Load(const std::string& specialType, + const std::string& filePath, unsigned int preferredWidth, unsigned int preferredHeight) const override; }; diff --git a/xbmc/pictures/CMakeLists.txt b/xbmc/pictures/CMakeLists.txt index a6895a075a..fe4601aa07 100644 --- a/xbmc/pictures/CMakeLists.txt +++ b/xbmc/pictures/CMakeLists.txt @@ -7,6 +7,7 @@ set(SOURCES ExifParse.cpp JpegParse.cpp libexif.cpp Picture.cpp + PictureFolderImageFileLoader.cpp PictureInfoLoader.cpp PictureInfoTag.cpp PictureScalingAlgorithm.cpp @@ -18,6 +19,7 @@ set(HEADERS GUIDialogPictureInfo.h GUIWindowPictures.h GUIWindowSlideShow.h Picture.h + PictureFolderImageFileLoader.h PictureInfoLoader.h PictureInfoTag.h PictureScalingAlgorithm.h diff --git a/xbmc/pictures/Picture.cpp b/xbmc/pictures/Picture.cpp index 9c7ec1e377..ceeb515a9d 100644 --- a/xbmc/pictures/Picture.cpp +++ b/xbmc/pictures/Picture.cpp @@ -6,20 +6,22 @@ * See LICENSES/README.md for more information. */ -#include <algorithm> - #include "Picture.h" -#include "URL.h" + +#include "FileItem.h" #include "ServiceBroker.h" +#include "URL.h" +#include "filesystem/File.h" +#include "guilib/Texture.h" +#include "guilib/imagefactory.h" #include "settings/AdvancedSettings.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" -#include "FileItem.h" -#include "filesystem/File.h" -#include "utils/log.h" +#include "utils/MemUtils.h" #include "utils/URIUtils.h" -#include "guilib/Texture.h" -#include "guilib/imagefactory.h" +#include "utils/log.h" + +#include <algorithm> extern "C" { #include <libswscale/swscale.h> @@ -277,6 +279,73 @@ bool CPicture::CacheTexture(uint8_t *pixels, uint32_t width, uint32_t height, ui return false; } +std::unique_ptr<CTexture> CPicture::CreateTiledThumb(const std::vector<std::string>& files) +{ + if (!files.size()) + return {}; + + unsigned int num_across = + static_cast<unsigned int>(std::ceil(std::sqrt(static_cast<float>(files.size())))); + unsigned int num_down = (files.size() + num_across - 1) / num_across; + + unsigned int imageRes = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_imageRes; + + unsigned int tile_width = imageRes / num_across; + unsigned int tile_height = imageRes / num_down; + unsigned int tile_gap = 1; + bool success = false; // Flag that we at least had one successful image processed + + // create a buffer for the resulting thumb + std::unique_ptr<uint32_t[]> buffer = std::make_unique<uint32_t[]>(imageRes * imageRes); + if (!buffer) + return {}; + for (unsigned int i = 0; i < files.size(); ++i) + { + int x = i % num_across; + int y = i / num_across; + // load in the image + unsigned int width = tile_width - 2 * tile_gap, height = tile_height - 2 * tile_gap; + std::unique_ptr<CTexture> texture = CTexture::LoadFromFile(files[i], width, height, true); + if (texture && texture->GetWidth() && texture->GetHeight()) + { + GetScale(texture->GetWidth(), texture->GetHeight(), width, height); + + // scale appropriately + std::unique_ptr<uint32_t[]> scaled = std::make_unique<uint32_t[]>(width * height); + if (ScaleImage(texture->GetPixels(), texture->GetWidth(), texture->GetHeight(), + texture->GetPitch(), AV_PIX_FMT_BGRA, reinterpret_cast<uint8_t*>(scaled.get()), + width, height, width * 4, AV_PIX_FMT_BGRA)) + { + unsigned int stridePixels{width}; + uint32_t* scaledL = scaled.get(); + if (!texture->GetOrientation() || + OrientateImage(scaledL, width, height, texture->GetOrientation(), stridePixels)) + { + success = true; + // drop into the texture + unsigned int posX = x * tile_width + (tile_width - width) / 2; + unsigned int posY = y * tile_height + (tile_height - height) / 2; + uint32_t* dest = buffer.get() + posX + posY * imageRes; + const uint32_t* src = scaled.get(); + for (unsigned int y = 0; y < height; ++y) + { + memcpy(dest, src, width * 4); + dest += imageRes; + src += stridePixels; + } + } + } + } + } + + std::unique_ptr<CTexture> result = CTexture::CreateTexture(); + if (success) + result->LoadFromMemory(imageRes, imageRes, imageRes * 4, XB_FMT_A8R8G8B8, true, + reinterpret_cast<unsigned char*>(buffer.get())); + + return result; +} + bool CPicture::CreateTiledThumb(const std::vector<std::string> &files, const std::string &thumb) { if (!files.size()) diff --git a/xbmc/pictures/Picture.h b/xbmc/pictures/Picture.h index 192982aa1a..e3d02011b5 100644 --- a/xbmc/pictures/Picture.h +++ b/xbmc/pictures/Picture.h @@ -13,6 +13,7 @@ #include <cstddef> #include <cstdint> +#include <memory> #include <string> #include <vector> @@ -35,6 +36,8 @@ public: */ static bool CreateTiledThumb(const std::vector<std::string> &files, const std::string &thumb); + static std::unique_ptr<CTexture> CreateTiledThumb(const std::vector<std::string>& files); + static bool ResizeTexture( const std::string& image, CTexture* texture, diff --git a/xbmc/pictures/PictureFolderImageFileLoader.cpp b/xbmc/pictures/PictureFolderImageFileLoader.cpp new file mode 100644 index 0000000000..1eb58f21b0 --- /dev/null +++ b/xbmc/pictures/PictureFolderImageFileLoader.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2023 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PictureFolderImageFileLoader.h" + +#include "FileItem.h" +#include "Picture.h" +#include "ServiceBroker.h" +#include "TextureCache.h" +#include "filesystem/Directory.h" +#include "guilib/Texture.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/FileExtensionProvider.h" + +using namespace XFILE; + +bool CPictureFolderImageFileLoader::CanLoad(const std::string& specialType) const +{ + return specialType == "picturefolder"; +} + +std::unique_ptr<CTexture> CPictureFolderImageFileLoader::Load(const std::string& specialType, + const std::string& filePath, + unsigned int preferredWidth, + unsigned int preferredHeight) const +{ + CFileItemList imagesInFolder; + CDirectory::GetDirectory(filePath, imagesInFolder, + CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), + DIR_FLAG_NO_FILE_DIRS); + + for (int i = 0; i < imagesInFolder.Size();) + { + if (!imagesInFolder[i]->IsPicture() || imagesInFolder[i]->IsZIP() || + imagesInFolder[i]->IsRAR() || imagesInFolder[i]->IsPlayList()) + { + imagesInFolder.Remove(i); + } + else + i++; + } + if (imagesInFolder.IsEmpty()) + { + return {}; + } + + imagesInFolder.Randomize(); + std::vector<std::string> imagesToTile; + int size = std::min(4, imagesInFolder.Size()); + imagesToTile.reserve(size); + for (int thumb = 0; thumb < size; thumb++) + { + imagesToTile.push_back(imagesInFolder[thumb]->GetPath()); + } + + return CPicture::CreateTiledThumb(imagesToTile); +} diff --git a/xbmc/pictures/PictureFolderImageFileLoader.h b/xbmc/pictures/PictureFolderImageFileLoader.h new file mode 100644 index 0000000000..aa5fb52678 --- /dev/null +++ b/xbmc/pictures/PictureFolderImageFileLoader.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2023 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "imagefiles/SpecialImageFileLoader.h" + +/*! + * @brief Generates a thumbnail for a folder in the picture browser, tile 4 images inside the folder. +*/ +class CPictureFolderImageFileLoader : public IMAGE_FILES::ISpecialImageFileLoader +{ +public: + CPictureFolderImageFileLoader() = default; + ~CPictureFolderImageFileLoader() override = default; + + bool CanLoad(const std::string& specialType) const override; + std::unique_ptr<CTexture> Load(const std::string& specialType, + const std::string& filePath, + unsigned int preferredWidth, + unsigned int preferredHeight) const override; +}; diff --git a/xbmc/pictures/PictureThumbLoader.cpp b/xbmc/pictures/PictureThumbLoader.cpp index 755c7df0c2..97114e304e 100644 --- a/xbmc/pictures/PictureThumbLoader.cpp +++ b/xbmc/pictures/PictureThumbLoader.cpp @@ -39,6 +39,11 @@ CPictureThumbLoader::~CPictureThumbLoader() void CPictureThumbLoader::OnLoaderFinish() { + if (m_regenerateThumbs) + { + CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS); + CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg); + } m_regenerateThumbs = false; CThumbLoader::OnLoaderFinish(); } @@ -195,24 +200,9 @@ void CPictureThumbLoader::ProcessFoldersAndArchives(CFileItem *pItem) } else { - // ok, now we've got the files to get the thumbs from, lets create it... - // we basically load the 4 images and combine them - std::vector<std::string> files; - files.reserve(4); - for (int thumb = 0; thumb < 4; thumb++) - files.push_back(items[thumb]->GetPath()); std::string thumb = CTextureUtils::GetWrappedImageURL(pItem->GetPath(), "picturefolder"); - std::string relativeCacheFile = CTextureCache::GetCacheFile(thumb) + ".png"; - if (CPicture::CreateTiledThumb(files, CTextureCache::GetCachedPath(relativeCacheFile))) - { - CTextureDetails details; - details.file = relativeCacheFile; - details.width = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_imageRes; - details.height = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_imageRes; - CServiceBroker::GetTextureCache()->AddCachedTexture(thumb, details); - db.SetTextureForPath(pItem->GetPath(), "thumb", thumb); - pItem->SetArt("thumb", CTextureCache::GetCachedPath(relativeCacheFile)); - } + db.SetTextureForPath(pItem->GetPath(), "thumb", thumb); + pItem->SetArt("thumb", thumb); } } // refill in the icon to get it to update diff --git a/xbmc/video/VideoEmbeddedImageFileLoader.cpp b/xbmc/video/VideoEmbeddedImageFileLoader.cpp index 3fe3d04650..f5f9c813b2 100644 --- a/xbmc/video/VideoEmbeddedImageFileLoader.cpp +++ b/xbmc/video/VideoEmbeddedImageFileLoader.cpp @@ -18,7 +18,7 @@ using namespace VIDEO; -bool CVideoEmbeddedImageFileLoader::CanLoad(std::string specialType) const +bool CVideoEmbeddedImageFileLoader::CanLoad(const std::string& specialType) const { return StringUtils::StartsWith(specialType, "video_"); } @@ -47,8 +47,8 @@ bool GetEmbeddedThumb(const std::string& path, const std::string& type, Embedded } } // namespace -std::unique_ptr<CTexture> CVideoEmbeddedImageFileLoader::Load(std::string specialType, - std::string filePath, +std::unique_ptr<CTexture> CVideoEmbeddedImageFileLoader::Load(const std::string& specialType, + const std::string& filePath, unsigned int preferredWidth, unsigned int preferredHeight) const { diff --git a/xbmc/video/VideoEmbeddedImageFileLoader.h b/xbmc/video/VideoEmbeddedImageFileLoader.h index c73ba5964a..2467adf9db 100644 --- a/xbmc/video/VideoEmbeddedImageFileLoader.h +++ b/xbmc/video/VideoEmbeddedImageFileLoader.h @@ -19,9 +19,9 @@ public: CVideoEmbeddedImageFileLoader() = default; ~CVideoEmbeddedImageFileLoader() override = default; - bool CanLoad(std::string specialType) const override; - std::unique_ptr<CTexture> Load(std::string specialType, - std::string filePath, + bool CanLoad(const std::string& specialType) const override; + std::unique_ptr<CTexture> Load(const std::string& specialType, + const std::string& filePath, unsigned int preferredWidth, unsigned int preferredHeight) const override; }; diff --git a/xbmc/video/VideoGeneratedImageFileLoader.cpp b/xbmc/video/VideoGeneratedImageFileLoader.cpp index 3cc6be8d3c..72ec950e16 100644 --- a/xbmc/video/VideoGeneratedImageFileLoader.cpp +++ b/xbmc/video/VideoGeneratedImageFileLoader.cpp @@ -16,7 +16,7 @@ #include "utils/URIUtils.h" #include "video/VideoInfoTag.h" -bool VIDEO::CVideoGeneratedImageFileLoader::CanLoad(std::string specialType) const +bool VIDEO::CVideoGeneratedImageFileLoader::CanLoad(const std::string& specialType) const { return specialType == "video"; } @@ -45,10 +45,8 @@ void SetupRarOptions(CFileItem& item, const std::string& path) } } // namespace -std::unique_ptr<CTexture> VIDEO::CVideoGeneratedImageFileLoader::Load(std::string specialType, - std::string filePath, - unsigned int, - unsigned int) const +std::unique_ptr<CTexture> VIDEO::CVideoGeneratedImageFileLoader::Load( + const std::string& specialType, const std::string& filePath, unsigned int, unsigned int) const { CFileItem item{filePath, false}; diff --git a/xbmc/video/VideoGeneratedImageFileLoader.h b/xbmc/video/VideoGeneratedImageFileLoader.h index 6ddc7ff67f..d25dfe6f27 100644 --- a/xbmc/video/VideoGeneratedImageFileLoader.h +++ b/xbmc/video/VideoGeneratedImageFileLoader.h @@ -18,9 +18,9 @@ namespace VIDEO class CVideoGeneratedImageFileLoader : public IMAGE_FILES::ISpecialImageFileLoader { public: - bool CanLoad(std::string specialType) const override; - std::unique_ptr<CTexture> Load(std::string specialType, - std::string filePath, + bool CanLoad(const std::string& specialType) const override; + std::unique_ptr<CTexture> Load(const std::string& specialType, + const std::string& filePath, unsigned int preferredWidth, unsigned int preferredHeight) const override; }; |