You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Previewer/ImagePreviewer.cpp

373 lines
12 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <ImageProcessing_precompiled.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <Source/Previewer/ImagePreviewer.h>
#include <Source/Previewer/ui_ImagePreviewer.h>
#include <Editor/EditorCommon.h>
#include <AzCore/Asset/AssetTypeInfoBus.h>
#include <AzCore/IO/FileIO.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
#include <AzToolsFramework/AssetBrowser/EBusFindAssetTypeByName.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <ImageLoader/ImageLoaders.h>
#include <Processing/ImageConvert.h>
#include <Processing/ImagePreview.h>
#include <Processing/ImageToProcess.h>
#include <Processing/Utils.h>
#include <Processing/ImageFlags.h>
#include <QString>
#include <QStringList>
AZ_POP_DISABLE_WARNING
namespace ImageProcessingAtom
{
static constexpr const int IMAGE_PREVIEWER_CHAR_WIDTH = 6;
ImagePreviewer::ImagePreviewer(QWidget* parent)
: Previewer(parent)
, m_ui(new Ui::ImagePreviewerClass())
{
m_ui->setupUi(this);
Clear();
}
ImagePreviewer::~ImagePreviewer()
{
AZ::SystemTickBus::Handler::BusDisconnect();
if (m_createDisplayTextureResult.isRunning())
{
m_createDisplayTextureResult.waitForFinished();
}
}
void ImagePreviewer::Clear() const
{
m_ui->m_texturePreviewWidget->hide();
m_ui->m_fileInfoCtrl->hide();
}
void ImagePreviewer::Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry)
{
using namespace AzToolsFramework::AssetBrowser;
m_previewImageObject = nullptr;
Clear();
switch (entry->GetEntryType())
{
case AssetBrowserEntry::AssetEntryType::Source:
DisplaySource(static_cast<const SourceAssetBrowserEntry*>(entry));
break;
case AssetBrowserEntry::AssetEntryType::Product:
DisplayProduct(static_cast<const ProductAssetBrowserEntry*>(entry));
break;
}
}
const QString& ImagePreviewer::GetName() const
{
return m_name;
}
void ImagePreviewer::resizeEvent(QResizeEvent* event)
{
AZ_UNUSED(event);
m_ui->m_fileInfoCtrl->setText(WordWrap(m_fileinfo, m_ui->m_fileInfoCtrl->width() / IMAGE_PREVIEWER_CHAR_WIDTH));
}
// Get the preview of a sub-image specified by mip
QImage GetSubImagePreview(IImageObjectPtr image, uint32_t mip)
{
AZ::u8* imageBuf;
AZ::u32 pitch;
image->GetImagePointer(mip, imageBuf, pitch);
const AZ::u32 width = image->GetWidth(mip);
const AZ::u32 height = image->GetHeight(mip);
return QImage(imageBuf, width, height, pitch, QImage::Format_RGBA8888);
}
// From image info string from ImageObject
void GetImageInfoString(IImageObjectPtr image, AZStd::string& output)
{
if (!image)
{
return;
}
output += AZStd::string::format("Dimensions: %dx%d\r\n", image->GetWidth(0), image->GetHeight(0));
AZ::u32 mipCount = image->GetMipCount();
output += AZStd::string::format("Mips: %d\r\n", mipCount);
AZ::u32 memSize = image->GetTextureMemory();
AZStd::string memSizeString = ImageProcessingAtomEditor::EditorHelper::GetFileSizeString(memSize);
output += AZStd::string::format("Size: %s\r\n", memSizeString.c_str());
CPixelFormats& pixelFormats = CPixelFormats::GetInstance();
EPixelFormat format = image->GetPixelFormat();
const PixelFormatInfo* info = pixelFormats.GetPixelFormatInfo(format);
if (info)
{
output += AZStd::string::format("Format: %s\r\n", info->szName);
}
AZStd::string colorSpaceString;
if (image->HasImageFlags(EIF_SRGBRead))
{
colorSpaceString = "sRGB";
}
else
{
// If the flag isn't set, then we don't know whether it's linear, or it's sRGB and the file format doesn't support a color space flag.
colorSpaceString = "Unknown";
}
output += AZStd::string::format("Color Space: %s\r\n", colorSpaceString.c_str());
if (image->HasImageFlags(EIF_Cubemap))
{
output += AZStd::string::format("Cubemap\r\n");
}
}
// From image info string from StreamingImageAsset
void GetImageInfoString(const AZ::Data::Asset<AZ::RPI::StreamingImageAsset>& imageAsset, AZStd::string& output)
{
if (!imageAsset.IsReady())
{
return;
}
AZ::RHI::ImageDescriptor descriptor = imageAsset->GetImageDescriptor();
output += AZStd::string("\r\nOverall image data...\r\n");
output += AZStd::string::format("Dimensions: %dx%d\r\n", descriptor.m_size.m_width, descriptor.m_size.m_height);
AZStd::string memSizeString;
if (imageAsset->GetTotalImageDataSize() > 0)
{
memSizeString = ImageProcessingAtomEditor::EditorHelper::GetFileSizeString(imageAsset->GetTotalImageDataSize());
}
else
{
memSizeString = "Unknown";
}
output += AZStd::string::format("Size: %s\r\n", memSizeString.c_str());
uint32_t totalMipCount = descriptor.m_mipLevels;
output += AZStd::string::format("Mips: %d\r\n", totalMipCount);
output += AZStd::string::format("Format: %s\r\n", AZ::RHI::ToString(descriptor.m_format));
//[GFX TODO] Put this back in, pending in my other CL
//output += AZStd::string::format("Color Space: %s\r\n", AZ::RHI::ToString(descriptor.m_colorSpace));
if (descriptor.m_isCubemap)
{
output += AZStd::string::format("Cubemap: true\r\n");
}
output += AZStd::string("\r\nBuilt-in mip chain...\r\n");
uint32_t builtInMipCount = imageAsset->GetTailMipChain().GetMipLevelCount();
output += AZStd::string::format("Mips: %d\r\n", builtInMipCount);
memSizeString = ImageProcessingAtomEditor::EditorHelper::GetFileSizeString(imageAsset->GetTailMipChain().GetImageDataSize());
output += AZStd::string::format("Size: %s\r\n", memSizeString.c_str());
AZ::RHI::Size builtInMipSizeA = imageAsset->GetTailMipChain().GetSubImageLayout(0).m_size;
AZStd::string mipChainDimensionString;
if (builtInMipCount == 1)
{
mipChainDimensionString = AZStd::string::format("%dx%d", builtInMipSizeA.m_width, builtInMipSizeA.m_height);
}
else
{
AZ::RHI::Size builtInMipSizeB = imageAsset->GetTailMipChain().GetSubImageLayout(builtInMipCount - 1).m_size;
mipChainDimensionString = AZStd::string::format("%dx%d .. %dx%d", builtInMipSizeA.m_width, builtInMipSizeA.m_height, builtInMipSizeB.m_width, builtInMipSizeB.m_height);
}
output += AZStd::string::format("Dimensions: %s\r\n", mipChainDimensionString.c_str());
output += AZStd::string("\r\n");
size_t additionalMipChainCount = imageAsset->GetMipChainCount() - 1;
output += AZStd::string::format("Additional Mip Chains: %zu\r\n", additionalMipChainCount);
}
void ImagePreviewer::DisplayProduct(const AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry* product)
{
m_ui->m_fileInfoCtrl->show();
m_fileinfo = QString::fromUtf8(product->GetName().c_str());
m_fileinfo += GetFileSize(product->GetRelativePath().c_str());
CreateAndDisplayTextureItemAsync(
[assetId = product->GetAssetId()]
() -> CreateDisplayTextureResult
{
AZ::Data::Asset<AZ::RPI::StreamingImageAsset> imageAsset = Utils::LoadImageAsset(assetId);
IImageObjectPtr image = Utils::LoadImageFromImageAsset(imageAsset);
if (image)
{
// Add product image info
AZStd::string productInfo;
GetImageInfoString(imageAsset, productInfo);
QString fileInfo = QStringLiteral("\r\n");
fileInfo += productInfo.c_str();
return { ConvertImageForPreview(image), fileInfo };
}
else
{
return { nullptr, "" };
}
});
DisplayTextureItem();
}
void ImagePreviewer::DisplaySource(const AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry* source)
{
m_ui->m_fileInfoCtrl->show();
m_fileinfo = QString::fromUtf8(source->GetName().c_str());
m_fileinfo += GetFileSize(source->GetFullPath().c_str());
CreateAndDisplayTextureItemAsync(
[fullPath = source->GetFullPath()]
() -> CreateDisplayTextureResult
{
IImageObjectPtr image = IImageObjectPtr(LoadImageFromFile(fullPath));
if (image)
{
// Add source image info
AZStd::string sourceInfo;
GetImageInfoString(image, sourceInfo);
QString fileInfo = QStringLiteral("\r\n");
fileInfo += sourceInfo.c_str();
return { ConvertImageForPreview(image), fileInfo };
}
else
{
return { nullptr, "" };
}
});
DisplayTextureItem();
}
QString ImagePreviewer::GetFileSize(const char* path)
{
QString fileSizeStr;
AZ::u64 fileSizeResult = 0;
if (AZ::IO::FileIOBase::GetInstance()->Size(path, fileSizeResult))
{
AZStd::string fileSizeString = ImageProcessingAtomEditor::EditorHelper::GetFileSizeString(fileSizeResult);
fileSizeStr += tr("\r\nFile Size: ");
fileSizeStr += fileSizeString.c_str();
}
return fileSizeStr;
}
void ImagePreviewer::DisplayTextureItem()
{
m_ui->m_texturePreviewWidget->show();
if (m_previewImageObject)
{
// Display mip 0 by default
PreviewSubImage(0);
}
else
{
m_ui->m_previewImageCtrl->setPixmap(QPixmap());
}
m_ui->m_fileInfoCtrl->setText(WordWrap(m_fileinfo, m_ui->m_fileInfoCtrl->width() / IMAGE_PREVIEWER_CHAR_WIDTH));
updateGeometry();
}
template<class CreateFn>
void ImagePreviewer::CreateAndDisplayTextureItemAsync(CreateFn create)
{
AZ::SystemTickBus::Handler::BusConnect();
m_createDisplayTextureResult = QtConcurrent::run(AZStd::move(create));
}
void ImagePreviewer::OnSystemTick()
{
if (m_createDisplayTextureResult.isFinished())
{
CreateDisplayTextureResult result = m_createDisplayTextureResult.result();
m_previewImageObject = AZStd::move(result.first);
m_fileinfo += result.second;
AZ::SystemTickBus::Handler::BusDisconnect();
DisplayTextureItem();
}
}
void ImagePreviewer::PreviewSubImage(uint32_t mip)
{
QImage previewImage = GetSubImagePreview(m_previewImageObject, mip);
QPixmap pix = QPixmap::fromImage(previewImage);
m_ui->m_previewImageCtrl->setPixmap(pix);
m_ui->m_previewImageCtrl->updateGeometry();
}
QString ImagePreviewer::WordWrap(const QString& string, int maxLength)
{
QString result;
int length = 0;
for (auto c : string)
{
if (c == '\n')
{
length = 0;
}
else if (length > maxLength)
{
result.append('\n');
length = 0;
}
else
{
length++;
}
result.append(c);
}
return result;
}
}//namespace ImageProcessingAtom
#include <Source/Previewer/moc_ImagePreviewer.cpp>