diff --git a/Meta/CMake/common_options.cmake b/Meta/CMake/common_options.cmake index 9ca99bd8113..6d61cc186ab 100644 --- a/Meta/CMake/common_options.cmake +++ b/Meta/CMake/common_options.cmake @@ -13,6 +13,7 @@ serenity_option(UNDEFINED_BEHAVIOR_IS_FATAL OFF CACHE BOOL "Make undefined behav serenity_option(ENABLE_ALL_THE_DEBUG_MACROS OFF CACHE BOOL "Enable all debug macros to validate they still compile") serenity_option(ENABLE_ALL_DEBUG_FACILITIES OFF CACHE BOOL "Enable all noisy debug symbols and options. Not recommended for normal developer use") +serenity_option(ENABLE_ADOBE_ICC_PROFILES_DOWNLOAD ON CACHE BOOL "Enable download of Adobe's ICC profiles") serenity_option(ENABLE_COMPILETIME_HEADER_CHECK OFF CACHE BOOL "Enable compiletime check that each library header compiles stand-alone") serenity_option(ENABLE_TIME_ZONE_DATABASE_DOWNLOAD ON CACHE BOOL "Enable download of the IANA Time Zone Database at build time") diff --git a/Meta/CMake/download_icc_profiles.cmake b/Meta/CMake/download_icc_profiles.cmake new file mode 100644 index 00000000000..39c2182a5a3 --- /dev/null +++ b/Meta/CMake/download_icc_profiles.cmake @@ -0,0 +1,25 @@ +include(${CMAKE_CURRENT_LIST_DIR}/utils.cmake) + +if (ENABLE_ADOBE_ICC_PROFILES_DOWNLOAD) + set(ADOBE_ICC_PROFILES_PATH "${SERENITY_CACHE_DIR}/AdobeICCProfiles" CACHE PATH "Download location for Adobe ICC profiles") + set(ADOBE_ICC_PROFILES_DATA_URL "https://download.adobe.com/pub/adobe/iccprofiles/win/AdobeICCProfilesCS4Win_end-user.zip") + set(ADOBE_ICC_PROFILES_ZIP_PATH "${ADOBE_ICC_PROFILES_PATH}/adobe-icc-profiles.zip") + if (ENABLE_NETWORK_DOWNLOADS) + download_file("${ADOBE_ICC_PROFILES_DATA_URL}" "${ADOBE_ICC_PROFILES_ZIP_PATH}") + else() + message(STATUS "Skipping download of ${ADOBE_ICC_PROFILES_DATA_URL}, expecting the archive to have been donwloaded to ${ADOBE_ICC_PROFILES_ZIP_PATH}") + endif() + + function(extract_adobe_icc_profiles source path) + if(EXISTS "${ADOBE_ICC_PROFILES_ZIP_PATH}" AND NOT EXISTS "${path}") + file(ARCHIVE_EXTRACT INPUT "${ADOBE_ICC_PROFILES_ZIP_PATH}" DESTINATION "${ADOBE_ICC_PROFILES_PATH}" PATTERNS "${source}") + endif() + endfunction() + + set(ADOBE_ICC_CMYK_SWOP "CMYK/USWebCoatedSWOP.icc") + set(ADOBE_ICC_CMYK_SWOP_PATH "${ADOBE_ICC_PROFILES_PATH}/Adobe ICC Profiles (end-user)/${ADOBE_ICC_CMYK_SWOP}") + extract_adobe_icc_profiles("Adobe ICC Profiles (end-user)/${ADOBE_ICC_CMYK_SWOP}" "${ADOBE_ICC_CMYK_SWOP_PATH}") + + set(ADOBE_ICC_CMYK_SWOP_INSTALL_PATH "${CMAKE_BINARY_DIR}/Root/res/icc/Adobe/${ADOBE_ICC_CMYK_SWOP}") + configure_file("${ADOBE_ICC_CMYK_SWOP_PATH}" "${ADOBE_ICC_CMYK_SWOP_INSTALL_PATH}" COPYONLY) +endif() diff --git a/Meta/Lagom/Contrib/MacPDF/AppDelegate.mm b/Meta/Lagom/Contrib/MacPDF/AppDelegate.mm index d6430208957..fe3ded39614 100644 --- a/Meta/Lagom/Contrib/MacPDF/AppDelegate.mm +++ b/Meta/Lagom/Contrib/MacPDF/AppDelegate.mm @@ -16,7 +16,7 @@ - (void)applicationDidFinishLaunching:(NSNotification*)aNotification { - // FIXME: Copy the fonts to the bundle or something + // FIXME: Copy fonts and icc file to the bundle or something // Get from `Build/lagom/bin/MacPDF.app/Contents/MacOS/MacPDF` to `Build/lagom/Root/res`. NSString* source_root = [[NSBundle mainBundle] executablePath]; diff --git a/Tests/LibPDF/TestPDF.cpp b/Tests/LibPDF/TestPDF.cpp index 14c643d1124..0e019ed255e 100644 --- a/Tests/LibPDF/TestPDF.cpp +++ b/Tests/LibPDF/TestPDF.cpp @@ -6,7 +6,10 @@ #include #include +#include #include +#include +#include #include #include #include @@ -293,6 +296,12 @@ TEST_CASE(postscript) TEST_CASE(render) { +#if !defined(AK_OS_SERENITY) + // Get from Build/lagom/bin/TestPDF to Build/lagom/Root/res. + auto source_root = LexicalPath(MUST(Core::System::current_executable_path())).parent().parent().string(); + Core::ResourceImplementation::install(make(MUST(String::formatted("{}/Root/res", source_root)))); +#endif + auto file = MUST(Core::MappedFile::map("colorspaces.pdf"sv)); auto document = MUST(PDF::Document::create(file->bytes())); MUST(document->initialize()); diff --git a/Userland/Libraries/LibPDF/CMakeLists.txt b/Userland/Libraries/LibPDF/CMakeLists.txt index 2e1b456c8cd..7f00a9d469f 100644 --- a/Userland/Libraries/LibPDF/CMakeLists.txt +++ b/Userland/Libraries/LibPDF/CMakeLists.txt @@ -26,4 +26,6 @@ set(SOURCES ) serenity_lib(LibPDF pdf) -target_link_libraries(LibPDF PRIVATE LibCompress LibIPC LibGfx LibTextCodec LibCrypto) +target_link_libraries(LibPDF PRIVATE LibCompress LibCore LibIPC LibGfx LibTextCodec LibCrypto) + +include(${SerenityOS_SOURCE_DIR}/Meta/CMake/download_icc_profiles.cmake) diff --git a/Userland/Libraries/LibPDF/ColorSpace.cpp b/Userland/Libraries/LibPDF/ColorSpace.cpp index b0dc5598d59..dde21737f98 100644 --- a/Userland/Libraries/LibPDF/ColorSpace.cpp +++ b/Userland/Libraries/LibPDF/ColorSpace.cpp @@ -134,8 +134,23 @@ Vector DeviceRGBColorSpace::default_decode() const return { 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f }; } +static RefPtr s_default_cmyk_profile; +static RefPtr s_default_cmyk_resource; + +static ErrorOr load_default_cmyk_profile() +{ + auto resource = TRY(Core::Resource::load_from_uri("resource://icc/Adobe/CMYK/USWebCoatedSWOP.icc"sv)); + auto profile = TRY(Gfx::ICC::Profile::try_load_from_externally_owned_memory(resource->data())); + s_default_cmyk_resource = move(resource); + s_default_cmyk_profile = move(profile); + return {}; +} + ErrorOr> DeviceCMYKColorSpace::the() { + if (s_default_cmyk_profile.is_null()) + TRY(load_default_cmyk_profile()); + static auto instance = adopt_ref(*new DeviceCMYKColorSpace()); return instance; } @@ -143,11 +158,17 @@ ErrorOr> DeviceCMYKColorSpace::the() PDFErrorOr DeviceCMYKColorSpace::style(ReadonlySpan arguments) const { VERIFY(arguments.size() == 4); - auto c = arguments[0]; - auto m = arguments[1]; - auto y = arguments[2]; - auto k = arguments[3]; - return Color::from_cmyk(c, m, y, k); + + u8 bytes[4]; + bytes[0] = static_cast(arguments[0] * 255.0f); + bytes[1] = static_cast(arguments[1] * 255.0f); + bytes[2] = static_cast(arguments[2] * 255.0f); + bytes[3] = static_cast(arguments[3] * 255.0f); + auto pcs = TRY(s_default_cmyk_profile->to_pcs(bytes)); + + Array output; + TRY(ICCBasedColorSpace::sRGB()->from_pcs(*s_default_cmyk_profile, pcs, output.span())); + return Color(output[0], output[1], output[2]); } Vector DeviceCMYKColorSpace::default_decode() const