136 changes: 0 additions & 136 deletions Externals/libpng/arm/arm_init.c

This file was deleted.

253 changes: 0 additions & 253 deletions Externals/libpng/arm/filter_neon.S

This file was deleted.

402 changes: 0 additions & 402 deletions Externals/libpng/arm/filter_neon_intrinsics.c

This file was deleted.

149 changes: 0 additions & 149 deletions Externals/libpng/arm/palette_neon_intrinsics.c

This file was deleted.

391 changes: 0 additions & 391 deletions Externals/libpng/intel/filter_sse2_intrinsics.c

This file was deleted.

52 changes: 0 additions & 52 deletions Externals/libpng/intel/intel_init.c

This file was deleted.

808 changes: 0 additions & 808 deletions Externals/libpng/mips/filter_msa_intrinsics.c

This file was deleted.

130 changes: 0 additions & 130 deletions Externals/libpng/mips/mips_init.c

This file was deleted.

4,607 changes: 0 additions & 4,607 deletions Externals/libpng/png.c

This file was deleted.

3,247 changes: 0 additions & 3,247 deletions Externals/libpng/png.h

This file was deleted.

50 changes: 0 additions & 50 deletions Externals/libpng/png/png.vcxproj

This file was deleted.

623 changes: 0 additions & 623 deletions Externals/libpng/pngconf.h

This file was deleted.

153 changes: 0 additions & 153 deletions Externals/libpng/pngdebug.h

This file was deleted.

963 changes: 0 additions & 963 deletions Externals/libpng/pngerror.c

This file was deleted.

1,249 changes: 0 additions & 1,249 deletions Externals/libpng/pngget.c

This file was deleted.

267 changes: 0 additions & 267 deletions Externals/libpng/pnginfo.h

This file was deleted.

219 changes: 0 additions & 219 deletions Externals/libpng/pnglibconf.h

This file was deleted.

284 changes: 0 additions & 284 deletions Externals/libpng/pngmem.c

This file was deleted.

1,096 changes: 0 additions & 1,096 deletions Externals/libpng/pngpread.c

This file was deleted.

2,152 changes: 0 additions & 2,152 deletions Externals/libpng/pngpriv.h

This file was deleted.

4,225 changes: 0 additions & 4,225 deletions Externals/libpng/pngread.c

This file was deleted.

120 changes: 0 additions & 120 deletions Externals/libpng/pngrio.c

This file was deleted.

5,044 changes: 0 additions & 5,044 deletions Externals/libpng/pngrtran.c

This file was deleted.

4,681 changes: 0 additions & 4,681 deletions Externals/libpng/pngrutil.c

This file was deleted.

1,802 changes: 0 additions & 1,802 deletions Externals/libpng/pngset.c

This file was deleted.

489 changes: 0 additions & 489 deletions Externals/libpng/pngstruct.h

This file was deleted.

2,158 changes: 0 additions & 2,158 deletions Externals/libpng/pngtest.c

This file was deleted.

864 changes: 0 additions & 864 deletions Externals/libpng/pngtrans.c

This file was deleted.

168 changes: 0 additions & 168 deletions Externals/libpng/pngwio.c

This file was deleted.

2,395 changes: 0 additions & 2,395 deletions Externals/libpng/pngwrite.c

This file was deleted.

575 changes: 0 additions & 575 deletions Externals/libpng/pngwtran.c

This file was deleted.

2,781 changes: 0 additions & 2,781 deletions Externals/libpng/pngwutil.c

This file was deleted.

768 changes: 0 additions & 768 deletions Externals/libpng/powerpc/filter_vsx_intrinsics.c

This file was deleted.

126 changes: 0 additions & 126 deletions Externals/libpng/powerpc/powerpc_init.c

This file was deleted.

9 changes: 9 additions & 0 deletions Externals/libspng/CMakeLists.txt
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.0)

project(spng C)

add_library(spng STATIC ${CMAKE_CURRENT_LIST_DIR}/libspng/spng/spng.c)
target_compile_definitions(spng PUBLIC SPNG_STATIC)
target_link_libraries(spng PUBLIC ZLIB::ZLIB)
target_include_directories(spng PUBLIC ${CMAKE_CURRENT_LIST_DIR}/libspng/spng/)
dolphin_disable_warnings_msvc(spng)
1 change: 1 addition & 0 deletions Externals/libspng/libspng
Submodule libspng added at dc5b10
35 changes: 35 additions & 0 deletions Externals/libspng/spng.vcxproj
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<Import Project="..\..\Source\VSProps\Base.Macros.props" />
<Import Project="$(VSPropsDir)Base.Targets.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{447B7B1E-1D74-4AEF-B2B9-6EB41C5D5313}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(VSPropsDir)Configuration.StaticLibrary.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VSPropsDir)Base.props" />
<Import Project="$(VSPropsDir)ClDisableAllWarnings.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>libspng\spng;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="libspng\spng\spng.c" />
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="libspng\spng\spng.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
14 changes: 7 additions & 7 deletions Externals/licenses.md
Expand Up @@ -15,13 +15,13 @@ Dolphin includes or links code of the following third-party software projects:
- [ENet](http://enet.bespin.org/):
[MIT](http://enet.bespin.org/License.html)
- [FatFs](http://elm-chan.org/fsw/ff/00index_e.html):
[BSD-1-Clause](http://elm-chan.org/fsw/ff/doc/appnote.html#license)
[BSD 1-Clause](http://elm-chan.org/fsw/ff/doc/appnote.html#license)
- [GCEmu](http://sourceforge.net/projects/gcemu-project/):
GPLv2+
- [gettext](https://www.gnu.org/software/gettext/):
[GPLv3+](http://git.savannah.gnu.org/cgit/gettext.git/tree/COPYING)
- [googletest](https://github.com/google/googletest):
[3-clause BSD](https://github.com/google/googletest/blob/master/LICENSE)
[BSD 3-Clause](https://github.com/google/googletest/blob/master/LICENSE)
- [libao](https://www.xiph.org/ao/):
[GPLv2+](https://trac.xiph.org/browser/trunk/ao/README)
- [libav](https://libav.org/):
Expand All @@ -32,8 +32,8 @@ Dolphin includes or links code of the following third-party software projects:
[LGPLv2+](http://git.savannah.gnu.org/cgit/libiconv.git/tree/COPYING.LIB)
- [liblzma](https://tukaani.org/xz/):
[Public domain](https://git.tukaani.org/?p=xz.git;a=blob_plain;f=COPYING;hb=HEAD)
- [libpng](http://www.libpng.org/pub/png/libpng.html):
[libpng license](http://www.libpng.org/pub/png/src/libpng-LICENSE.txt)
- [libspng](https://github.com/randy408/libspng):
[BSD 2-Clause](https://github.com/randy408/libspng/blob/master/LICENSE)
- [libusb](http://libusb.info/):
[LGPLv2.1+](https://github.com/libusb/libusb/blob/master/COPYING)
- [LLVM](http://llvm.org/):
Expand All @@ -43,7 +43,7 @@ Dolphin includes or links code of the following third-party software projects:
- [mGBA](http://mgba.io)
[MPL 2.0](https://github.com/mgba-emu/mgba/blob/master/LICENSE)
- [MiniUPnPc](http://miniupnp.free.fr/):
[3-clause BSD](https://github.com/miniupnp/miniupnp/blob/master/miniupnpc/LICENSE)
[BSD 3-Clause](https://github.com/miniupnp/miniupnp/blob/master/miniupnpc/LICENSE)
- [Microsoft Visual C++ Runtime Library](http://www.microsoft.com/en-us/download/details.aspx?id=40784):
[System Library if not distributed](https://www.gnu.org/licenses/gpl-faq.html#WindowsRuntimeAndGPL)
- [OpenAL Soft](http://kcat.strangesoft.net/openal.html):
Expand Down Expand Up @@ -73,8 +73,8 @@ Dolphin includes or links code of the following third-party software projects:
- [Windows Implementation Libraries](https://github.com/microsoft/wil):
[MIT](https://github.com/microsoft/wil/blob/master/LICENSE)
- [xxHash](https://github.com/Cyan4973/xxHash):
[2-clause BSD](https://github.com/Cyan4973/xxHash/blob/master/LICENSE)
[BSD 2-Clause](https://github.com/Cyan4973/xxHash/blob/master/LICENSE)
- [zlib-ng](https://github.com/zlib-ng/zlib-ng):
[zlib license](https://github.com/zlib-ng/zlib-ng/blob/develop/LICENSE.md)
- [Zstandard](https://facebook.github.io/zstd/):
[3-clause BSD](https://github.com/facebook/zstd/blob/dev/LICENSE) or [GPLv2](https://github.com/facebook/zstd/blob/dev/COPYING)
[BSD 3-Clause](https://github.com/facebook/zstd/blob/dev/LICENSE) or [GPLv2](https://github.com/facebook/zstd/blob/dev/COPYING)
9 changes: 1 addition & 8 deletions Source/Core/Common/CMakeLists.txt
Expand Up @@ -64,8 +64,6 @@ add_library(common
HttpRequest.h
Image.cpp
Image.h
ImageC.c
ImageC.h
IniFile.cpp
IniFile.h
Inline.h
Expand Down Expand Up @@ -148,7 +146,7 @@ PRIVATE
${CURL_LIBRARIES}
FatFs
${ICONV_LIBRARIES}
png
spng
${VTUNE_LIBRARIES}
)

Expand Down Expand Up @@ -315,9 +313,4 @@ endif()
if(MSVC)
# Add precompiled header
target_link_libraries(common PRIVATE use_pch)

# We need to disable PCH for this one file, because it's C and our PCH is C++
set_source_files_properties(
${CMAKE_CURRENT_SOURCE_DIR}/ImageC.c
PROPERTIES COMPILE_FLAGS "/Y- /I${CMAKE_SOURCE_DIR}/Source/PCH/nopch")
endif()
173 changes: 71 additions & 102 deletions Source/Core/Common/Image.cpp
Expand Up @@ -3,159 +3,121 @@

#include "Common/Image.h"

#include <memory>
#include <string>
#include <vector>

#include <png.h>
#include <spng.h>

#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/IOFile.h"
#include "Common/ImageC.h"
#include "Common/Logging/Log.h"
#include "Common/Timer.h"

namespace Common
{
static void spng_free(spng_ctx* ctx)
{
if (ctx)
spng_ctx_free(ctx);
}

static auto make_spng_ctx(int flags)
{
return std::unique_ptr<spng_ctx, decltype(&spng_free)>(spng_ctx_new(flags), spng_free);
}

bool LoadPNG(const std::vector<u8>& input, std::vector<u8>* data_out, u32* width_out,
u32* height_out)
{
// Using the 'Simplified API' of libpng; see section V in the libpng manual.
auto ctx = make_spng_ctx(0);
if (!ctx)
return false;

// Read header
png_image png = {};
png.version = PNG_IMAGE_VERSION;
if (!png_image_begin_read_from_memory(&png, input.data(), input.size()))
if (spng_set_png_buffer(ctx.get(), input.data(), input.size()))
return false;

// Prepare output vector
png.format = PNG_FORMAT_RGBA;
size_t png_size = PNG_IMAGE_SIZE(png);
data_out->resize(png_size);
spng_ihdr ihdr{};
if (spng_get_ihdr(ctx.get(), &ihdr))
return false;

// Convert to RGBA and write into output vector
if (!png_image_finish_read(&png, nullptr, data_out->data(), 0, nullptr))
const int format = SPNG_FMT_RGBA8;
size_t decoded_len = 0;
if (spng_decoded_image_size(ctx.get(), format, &decoded_len))
return false;

*width_out = png.width;
*height_out = png.height;
data_out->resize(decoded_len);
if (spng_decode_image(ctx.get(), data_out->data(), decoded_len, format, SPNG_DECODE_TRNS))
return false;

*width_out = ihdr.width;
*height_out = ihdr.height;
return true;
}

static void WriteCallback(png_structp png_ptr, png_bytep data, size_t length)
{
std::vector<u8>* buffer = static_cast<std::vector<u8>*>(png_get_io_ptr(png_ptr));
buffer->insert(buffer->end(), data, data + length);
}

static void ErrorCallback(ErrorHandler* self, const char* msg)
{
std::vector<std::string>* errors = static_cast<std::vector<std::string>*>(self->error_list);
errors->emplace_back(msg);
}

static void WarningCallback(ErrorHandler* self, const char* msg)
{
std::vector<std::string>* warnings = static_cast<std::vector<std::string>*>(self->warning_list);
warnings->emplace_back(msg);
}

bool SavePNG(const std::string& path, const u8* input, ImageByteFormat format, u32 width,
u32 height, int stride, int level)
u32 height, u32 stride, int level)
{
Common::Timer timer;
timer.Start();

size_t byte_per_pixel;
int color_type;
spng_color_type color_type;
switch (format)
{
case ImageByteFormat::RGB:
color_type = PNG_COLOR_TYPE_RGB;
byte_per_pixel = 3;
color_type = SPNG_COLOR_TYPE_TRUECOLOR;
break;
case ImageByteFormat::RGBA:
color_type = PNG_COLOR_TYPE_RGBA;
byte_per_pixel = 4;
color_type = SPNG_COLOR_TYPE_TRUECOLOR_ALPHA;
break;
default:
ASSERT_MSG(FRAMEDUMP, false, "Invalid format {}", static_cast<int>(format));
return false;
}

// libpng doesn't handle non-ASCII characters in path, so write in two steps:
// first to memory, then to file
std::vector<u8> buffer;
buffer.reserve(byte_per_pixel * width * height);

std::vector<std::string> warnings;
std::vector<std::string> errors;
ErrorHandler error_handler;
error_handler.error_list = &errors;
error_handler.warning_list = &warnings;
error_handler.StoreError = ErrorCallback;
error_handler.StoreWarning = WarningCallback;

std::vector<const u8*> rows;
rows.reserve(height);
for (u32 row = 0; row < height; row++)
{
rows.push_back(&input[row * stride]);
}
auto ctx = make_spng_ctx(SPNG_CTX_ENCODER);
if (!ctx)
return false;

png_structp png_ptr =
png_create_write_struct(PNG_LIBPNG_VER_STRING, &error_handler, PngError, PngWarning);
png_infop info_ptr = png_create_info_struct(png_ptr);
auto outfile = File::IOFile(path, "wb");
if (spng_set_png_file(ctx.get(), outfile.GetHandle()))
return false;

bool success = false;
if (png_ptr != nullptr && info_ptr != nullptr)
{
success = SavePNG0(png_ptr, info_ptr, color_type, width, height, level, &buffer, WriteCallback,
const_cast<u8**>(rows.data()));
}
png_destroy_write_struct(&png_ptr, &info_ptr);
if (spng_set_option(ctx.get(), SPNG_IMG_COMPRESSION_LEVEL, level))
return false;

if (success)
{
File::IOFile outfile(path, "wb");
if (!outfile)
return false;
success = outfile.WriteBytes(buffer.data(), buffer.size());
spng_ihdr ihdr{};
ihdr.width = width;
ihdr.height = height;
ihdr.color_type = color_type;
ihdr.bit_depth = 8;
if (spng_set_ihdr(ctx.get(), &ihdr))
return false;

timer.Stop();
INFO_LOG_FMT(FRAMEDUMP, "{} byte {} by {} image saved to {} at level {} in {}", buffer.size(),
width, height, path, level, timer.GetTimeElapsedFormatted());
ASSERT(errors.size() == 0);
if (warnings.size() != 0)
if (spng_encode_image(ctx.get(), nullptr, 0, SPNG_FMT_PNG, SPNG_ENCODE_PROGRESSIVE))
return false;
for (u32 row = 0; row < height; row++)
{
const int err = spng_encode_row(ctx.get(), &input[row * stride], stride);
if (err == SPNG_EOI)
break;
if (err)
{
WARN_LOG_FMT(FRAMEDUMP, "Saved with {} warnings:", warnings.size());
for (auto& warning : warnings)
WARN_LOG_FMT(FRAMEDUMP, "libpng warning: {}", warning);
ERROR_LOG_FMT(FRAMEDUMP, "Failed to save {} by {} image to {} at level {}: error {}", width,
height, path, level, err);
return false;
}
}
else
{
ERROR_LOG_FMT(FRAMEDUMP,
"Failed to save {} by {} image to {} at level {}: {} warnings, {} errors", width,
height, path, level, warnings.size(), errors.size());
for (auto& error : errors)
ERROR_LOG_FMT(FRAMEDUMP, "libpng error: {}", error);
for (auto& warning : warnings)
WARN_LOG_FMT(FRAMEDUMP, "libpng warning: {}", warning);
}

return success;
}

bool ConvertRGBAToRGBAndSavePNG(const std::string& path, const u8* input, u32 width, u32 height,
int stride, int level)
{
const std::vector<u8> data = RGBAToRGB(input, width, height, stride);
return SavePNG(path, data.data(), ImageByteFormat::RGB, width, height, width * 3, level);
size_t image_len = 0;
spng_decoded_image_size(ctx.get(), SPNG_FMT_PNG, &image_len);
INFO_LOG_FMT(FRAMEDUMP, "{} byte {} by {} image saved to {} at level {} in {}", image_len, width,
height, path, level, timer.GetTimeElapsedFormatted());
return true;
}

std::vector<u8> RGBAToRGB(const u8* input, u32 width, u32 height, int row_stride)
static std::vector<u8> RGBAToRGB(const u8* input, u32 width, u32 height, u32 row_stride)
{
std::vector<u8> buffer;
buffer.reserve(width * height * 3);
Expand All @@ -172,4 +134,11 @@ std::vector<u8> RGBAToRGB(const u8* input, u32 width, u32 height, int row_stride
}
return buffer;
}

bool ConvertRGBAToRGBAndSavePNG(const std::string& path, const u8* input, u32 width, u32 height,
u32 stride, int level)
{
const std::vector<u8> data = RGBAToRGB(input, width, height, stride);
return SavePNG(path, data.data(), ImageByteFormat::RGB, width, height, width * 3, level);
}
} // namespace Common
7 changes: 2 additions & 5 deletions Source/Core/Common/Image.h
Expand Up @@ -20,10 +20,7 @@ enum class ImageByteFormat
};

bool SavePNG(const std::string& path, const u8* input, ImageByteFormat format, u32 width,
u32 height, int stride, int level = 6);
u32 height, u32 stride, int level = 6);
bool ConvertRGBAToRGBAndSavePNG(const std::string& path, const u8* input, u32 width, u32 height,
int stride, int level);

std::vector<u8> RGBAToRGB(const u8* input, u32 width, u32 height, int row_stride = 0);

u32 stride, int level);
} // namespace Common