Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
481 changes: 481 additions & 0 deletions src/plugins/pictview/PVOverrider.cpp

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions src/plugins/pictview/PVOverrider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-FileCopyrightText: 2023 Open Salamander Authors
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

// overrider for the pict-view library, which adds support for viewing new image formats

void InitializePvOverrider();
void UninitializePvOverrider();
177 changes: 177 additions & 0 deletions src/plugins/pictview/heif.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// SPDX-FileCopyrightText: 2023 Open Salamander Authors
// SPDX-License-Identifier: GPL-2.0-or-later

#include "precomp.h"
#include "heif.h"
#include <fstream>
#include <assert.h>

struct HeifProgressData
{
TProgressProc progressProc;
void* appSpecific;
int cancelFlag{false};
int maxProgress{0};
};

ImageHeif::~ImageHeif()
{
if (m_image)
heif_image_release(m_image);
if (m_handle)
heif_image_handle_release(m_handle);
if (m_ctx)
heif_context_free(m_ctx);
}

PVCODE ImageHeif::Open(const char* filename, PVImageInfo& pvii)
{
pvii = {};

// initialize libheif context
m_ctx = heif_context_alloc();
if (!m_ctx)
return PVC_OUT_OF_MEMORY;
heif_error err = heif_context_read_from_file(m_ctx, filename, nullptr);
if (err.code != heif_error_Ok)
{
switch (err.code)
{
case heif_error_Invalid_input:
return PVC_UNKNOWN_FILE_STRUCT;
case heif_error_Memory_allocation_error:
return PVC_OUT_OF_MEMORY;
default:
return PVC_CANNOT_OPEN_FILE;
}
}

// get the primary image handle
err = heif_context_get_primary_image_handle(m_ctx, &m_handle);
if (err.code != heif_error_Ok)
return PVC_UNKNOWN_FILE_STRUCT;

// fill out the image info
pvii.cbSize = sizeof(pvii);
pvii.Format = PVF_BMP;
pvii.Width = heif_image_handle_get_width(m_handle);
pvii.Height = heif_image_handle_get_height(m_handle);
const int luma_bits = heif_image_handle_get_luma_bits_per_pixel(m_handle);
const int chroma_bits = heif_image_handle_get_chroma_bits_per_pixel(m_handle);
pvii.Colors = (1 << luma_bits) * (1 << chroma_bits);
pvii.NumOfImages = 1;

// compute the number of bytes per line (stride)
const int bytes_per_pixel = (luma_bits + chroma_bits) / 8; // assuming 24-bit RGB format
pvii.BytesPerLine = pvii.Width * bytes_per_pixel;
pvii.Colors = PV_COLOR_TC24;
pvii.ColorModel = PVCM_RGB;
pvii.Compression = PVCS_NO_COMPRESSION;

// get the file size
if (std::ifstream file(filename, std::ios::binary | std::ios::ate);
file.is_open())
{
file.seekg(0, std::ios::end);
pvii.FileSize = static_cast<DWORD>(file.tellg());
}

strcpy_s(pvii.Info1, "HEIF");

return PVC_OK;
}

PVCODE ImageHeif::Read(HBITMAP& bmp, TProgressProc Progress, void* AppSpecific)
{
assert(m_ctx);
assert(m_handle);

// decoding progress and cancellation doesn't work yet!
heif_decoding_options* options = heif_decoding_options_alloc();
if (!options)
return PVC_OUT_OF_MEMORY;

options->version = 6;
options->start_progress = &ImageHeif::StartProgress;
options->on_progress = &ImageHeif::OnProgress;
// options->end_progress = &ImageHeif::EndProgress;
options->cancel_decoding = &ImageHeif::CancelDecoding;

HeifProgressData progress_data{
.progressProc = Progress,
.appSpecific = AppSpecific
};
options->progress_user_data = &progress_data;

// decode the image
heif_error err = heif_decode_image(m_handle, &m_image, heif_colorspace_RGB, heif_chroma_interleaved_RGB, options);
heif_decoding_options_free(options);
if (err.code != heif_error_Ok)
return PVC_READING_ERROR;

// check image bit depth
const int bitDepth = heif_image_get_bits_per_pixel(m_image, heif_channel_interleaved);
if (bitDepth != 24)
return PVC_UNSUP_COLOR_DEPTH;

// get image dimensions
const int width = heif_image_get_width(m_image, heif_channel_interleaved);
const int height = heif_image_get_height(m_image, heif_channel_interleaved);

// get image data
int stride{};
const uint8_t* data = heif_image_get_plane_readonly(m_image, heif_channel_interleaved, &stride);
if (!data)
return PVC_READING_ERROR;

// convert the decoded image to a bitmap
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biHeight = -height; // Negative to indicate top-down DIB
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 24; // 24-bit RGB
bmi.bmiHeader.biCompression = BI_RGB;

HDC hdc = GetDC(nullptr);
void* bits = nullptr;
bmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &bits, nullptr, 0);
ReleaseDC(nullptr, hdc);

// copy image data to the DIB
for (int y = 0; y < height; ++y)
{
memcpy(static_cast<uint8_t*>(bits) + y * width * 3, data + y * stride, width * 3);
}

// image loaded successfully
return PVC_OK;
}

void ImageHeif::StartProgress(heif_progress_step step, int max_progress, void* user)
{
if (step != heif_progress_step_total)
return;
auto* data = static_cast<HeifProgressData*>(user);
data->maxProgress = max_progress;
}

void ImageHeif::OnProgress(heif_progress_step step, int progress, void* user)
{
if (step != heif_progress_step_total)
return;

auto* data = static_cast<HeifProgressData*>(user);
if (data->progressProc && data->maxProgress != 0)
{
const int percent = progress * 100 / data->maxProgress;
if (data->progressProc(percent, data->appSpecific) && data->cancelFlag)
data->cancelFlag = true;
}
}

int ImageHeif::CancelDecoding(void* user)
{
const auto* data = static_cast<HeifProgressData*>(user);
return data->cancelFlag;
}
26 changes: 26 additions & 0 deletions src/plugins/pictview/heif.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-FileCopyrightText: 2023 Open Salamander Authors
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "lib/pvw32dll.h"
#include <libheif/heif.h>

class ImageHeif
{
public:
ImageHeif() = default;
~ImageHeif();

PVCODE Open(const char* filename, PVImageInfo& pvii);
PVCODE Read(HBITMAP& bmp, TProgressProc Progress, void* AppSpecific);

private:
static void StartProgress(enum heif_progress_step step, int max_progress, void* user);
static void OnProgress(enum heif_progress_step step, int progress, void* user);
static int CancelDecoding(void* user);

heif_context* m_ctx{};
heif_image_handle* m_handle{};
heif_image* m_image{};
};
1 change: 0 additions & 1 deletion src/plugins/pictview/histwnd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

#include "precomp.h"

#include "lib\\pvw32dll.h"
#include "pictview.h"
#include "dialogs.h"
#include "histwnd.h"
Expand Down
15 changes: 13 additions & 2 deletions src/plugins/pictview/pictview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "histwnd.h"
#include "PVEXEWrapper.h"
#include "PixelAccess.h"
#include "PVOverrider.h"

// objekt interfacu pluginu, jeho metody se volaji ze Salamandera
CPluginInterface PluginInterface;
Expand Down Expand Up @@ -71,7 +72,7 @@ BOOL SalamanderRegistered = FALSE;
// 22 - Salamander 2.52 B1: Added *.BLP files used by Blizzard Entertainment in World of Wordcraft

int ConfigVersion = 0;
#define CURRENT_CONFIG_VERSION 22
#define CURRENT_CONFIG_VERSION 23

SGlobals G; // inicializovano v InitViewer
TDirectArray<DWORD> ExifHighlights(20, 10);
Expand Down Expand Up @@ -1063,6 +1064,11 @@ void CPluginInterface::Connect(HWND parent, CSalamanderConnectAbstract* salamand
salamander->AddViewer("*.blp", TRUE);
}

if (ConfigVersion < 23) // Added HEIF and WebP formats
{
salamander->AddViewer("*.heic;*.heif;*.webp", TRUE);
}

/* slouzi pro skript export_mnu.py, ktery generuje salmenu.mnu pro Translator
udrzovat synchronizovane s volani salamander->AddMenuItem() dole...
MENU_TEMPLATE_ITEM PluginMenu[] =
Expand Down Expand Up @@ -1113,7 +1119,7 @@ MENU_TEMPLATE_ITEM PluginMenu[] =
"*.flc;*.fli;*.gem;*.gif;*.ham;*.hmr;*.hrz;*.icn;*.ico;*.iff;*.img;"
"*.cdt;*.cel;*.clp;*.cit;*.cmx;*.cot;*.cpt;*.cur;*.cut;*.dcx;*.dib;"
"*.82i;*.83i;*.85i;*.86i;*.89i;*.92i;*.awd;*.bmi;*.bmp;*.cal;*.cdr;"
"*.arw;*.blp;*.cr2;*.dng;*.orf;*.pef");
"*.arw;*.blp;*.cr2;*.dng;*.orf;*.pef;*.heic;*.heif;*.webp");
}

void CPluginInterface::ClearHistory(HWND parent)
Expand Down Expand Up @@ -1411,6 +1417,9 @@ BOOL LoadPictViewDll(HWND hParentWnd)
return FALSE;
}
#endif // PICTVIEW_DLL_IN_SEPARATE_PROCESS

// inject the new image file formats support into the viewer
InitializePvOverrider();
return TRUE;
}

Expand Down Expand Up @@ -1543,6 +1552,8 @@ BOOL InitEXIF(HWND hParent, BOOL bSilent)

void ReleaseViewer()
{
UninitializePvOverrider();

#ifdef PICTVIEW_DLL_IN_SEPARATE_PROCESS
ReleasePVEXEWrapper();
#endif
Expand Down
1 change: 0 additions & 1 deletion src/plugins/pictview/pvtwain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

#ifdef ENABLE_TWAIN32

#include "lib/pvw32dll.h"
#include "renderer.h"
#include "dialogs.h"
#include "pictview.h"
Expand Down
1 change: 0 additions & 1 deletion src/plugins/pictview/statsbar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

#include "precomp.h"

#include "lib\\pvw32dll.h"
#include "renderer.h"
#include "pictview.h"
#include "pictview.rh"
Expand Down
7 changes: 7 additions & 0 deletions src/plugins/pictview/vcpkg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"dependencies": [
"libheif",
"libwebp"
],
"builtin-baseline": "6f29f12e82a8293156836ad81cc9bf5af41fe836"
}
11 changes: 11 additions & 0 deletions src/plugins/pictview/vcxproj/pictview.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@
</ImportGroup>
<PropertyGroup Label="UserMacros">
</PropertyGroup>
<PropertyGroup Label="Vcpkg">
<VcpkgEnabled>true</VcpkgEnabled>
<VcpkgManifestInstall>true</VcpkgManifestInstall>
<VcpkgEnableManifest>true</VcpkgEnableManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<LanguageStandard>stdcpplatest</LanguageStandard>
Expand Down Expand Up @@ -131,6 +136,7 @@
</ClCompile>
<ClCompile Include="..\dialogs.cpp">
</ClCompile>
<ClCompile Include="..\heif.cpp" />
<ClCompile Include="..\histwnd.cpp">
</ClCompile>
<ClCompile Include="..\pictview.cpp">
Expand All @@ -151,6 +157,7 @@
</ClCompile>
<ClCompile Include="..\PVMessageWrapper.cpp">
</ClCompile>
<ClCompile Include="..\PVOverrider.cpp" />
<ClCompile Include="..\pvtwain.cpp">
</ClCompile>
<ClCompile Include="..\render1.cpp">
Expand All @@ -167,6 +174,7 @@
</ClCompile>
<ClCompile Include="..\utils.cpp">
</ClCompile>
<ClCompile Include="..\webp.cpp" />
<ClCompile Include="..\wiawrap.cpp">
</ClCompile>
</ItemGroup>
Expand Down Expand Up @@ -201,6 +209,7 @@
</ClInclude>
<ClInclude Include="..\dialogs.h">
</ClInclude>
<ClInclude Include="..\heif.h" />
<ClInclude Include="..\histwnd.h">
</ClInclude>
<ClInclude Include="..\lib\pvw32dll.h">
Expand All @@ -215,6 +224,7 @@
</ClInclude>
<ClInclude Include="..\PVMessage.h">
</ClInclude>
<ClInclude Include="..\PVOverrider.h" />
<ClInclude Include="..\pvtwain.h">
</ClInclude>
<ClInclude Include="..\renderer.h">
Expand All @@ -225,6 +235,7 @@
</ClInclude>
<ClInclude Include="..\utils.h">
</ClInclude>
<ClInclude Include="..\webp.h" />
<ClInclude Include="..\wiawrap.h">
</ClInclude>
</ItemGroup>
Expand Down
18 changes: 18 additions & 0 deletions src/plugins/pictview/vcxproj/pictview.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@
<ClCompile Include="..\wiawrap.cpp">
<Filter>cpp</Filter>
</ClCompile>
<ClCompile Include="..\PVOverrider.cpp">
<Filter>cpp</Filter>
</ClCompile>
<ClCompile Include="..\heif.cpp">
<Filter>cpp</Filter>
</ClCompile>
<ClCompile Include="..\webp.cpp">
<Filter>cpp</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\dialogs.h">
Expand Down Expand Up @@ -167,6 +176,15 @@
<ClInclude Include="..\wiawrap.h">
<Filter>h</Filter>
</ClInclude>
<ClInclude Include="..\PVOverrider.h">
<Filter>h</Filter>
</ClInclude>
<ClInclude Include="..\heif.h">
<Filter>h</Filter>
</ClInclude>
<ClInclude Include="..\webp.h">
<Filter>h</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\lang\lang.rh">
Expand Down
Loading