diff --git a/.gitmodules b/.gitmodules index 7101234a72..f0112dd9cd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -81,3 +81,7 @@ [submodule "third_party/tinyxml2"] path = third_party/tinyxml2 url = https://github.com/aseprite/tinyxml2.git + +[submodule "third_party/tinyexif"] + path = third_party/tinyexif + url = https://github.com/aseprite/tinyexif.git diff --git a/CMakeLists.txt b/CMakeLists.txt index faa234f902..7ae8e3f9e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,8 +43,9 @@ option(USE_SHARED_GIFLIB "Use your installed copy of giflib" off) option(USE_SHARED_JPEGLIB "Use your installed copy of jpeglib" off) option(USE_SHARED_ZLIB "Use your installed copy of zlib" off) option(USE_SHARED_LIBPNG "Use your installed copy of libpng" off) -option(USE_SHARED_TINYXML "Use your installed copy of tinyxml" off) -option(USE_SHARED_PIXMAN "Use your installed copy of pixman" off) +option(USE_SHARED_TINYXML "Use your installed copy of tinyxml" off) +option(USE_SHARED_TINYEXIF "Use your installed copy of TinyEXIF" off) +option(USE_SHARED_PIXMAN "Use your installed copy of pixman" off) option(USE_SHARED_FREETYPE "Use shared FreeType library" off) option(USE_SHARED_HARFBUZZ "Use shared HarfBuzz library" off) option(ENABLE_ASEPRITE_EXE "Compile main Aseprite executable" on) @@ -166,6 +167,7 @@ set(FREETYPE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/freetype2) set(HARFBUZZ_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/harfbuzz) set(SIMPLEINI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/simpleini) set(TINYXML_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/tinyxml2) +set(TINYEXIF_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/TinyEXIF) set(ZLIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/zlib) # Search in the "cmake" directory for additional CMake modules. @@ -237,6 +239,17 @@ else() endif() include_directories(${TINYXML_INCLUDE_DIR}) +# TinyEXIF +if(USE_SHARED_TINYEXIF) + find_library(TINYEXIF_LIBRARY NAMES TinyEXIF) + find_path(TINYEXIF_INCLUDE_DIR NAMES TinyEXIF.h) +else() + set(TINYEXIF_LIBRARY TinyEXIF) + set(TINYEXIF_INCLUDE_DIR ${TINYEXIF_DIR}) +endif() +include_directories(${TINYEXIF_INCLUDE_DIR}) + + # pixman if(USE_SHARED_PIXMAN) find_library(PIXMAN_LIBRARY NAMES pixman pixman-1) diff --git a/cmake/FindTinyxml2.cmake b/cmake/FindTinyxml2.cmake new file mode 100644 index 0000000000..d75faa3db5 --- /dev/null +++ b/cmake/FindTinyxml2.cmake @@ -0,0 +1,24 @@ +# Copyright (C) 2023 Igara Studio S.A. +# Find tinyxml2 + +function(find_tinyxml2 dir dependencies) + file(GLOB tinyxml2 ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/tinyxml2.cpp) + list(REMOVE_AT ARGV 0) + + get_filename_component(tinyxml2name tinyxml2.cpp NAME_WE) + + add_executable(${tinyxml2name} tinyxml2.cpp) + + if(MSVC) + # Fix problem compiling gen from a Visual Studio solution + set_target_properties(${tinyxml2name} + PROPERTIES LINK_FLAGS -ENTRY:"mainCRTStartup") + endif() + + target_link_libraries(${tinyxml2name} tinyxml2 ${ARGV} ${PLATFORM_LIBS}) + + if(extra_definitions) + set_target_properties(${tinyxml2name} + PROPERTIES COMPILE_FLAGS ${extra_definitions}) + endif() +endfunction() diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 0b7413614d..bbdccfd083 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -746,6 +746,7 @@ target_link_libraries(app-lib undo ${CMARK_LIBRARIES} ${TINYXML_LIBRARY} + ${TINYEXIF_LIBRARY} ${JPEG_LIBRARIES} ${GIF_LIBRARIES} ${PNG_LIBRARIES} diff --git a/src/app/file/jpeg_format.cpp b/src/app/file/jpeg_format.cpp index bcd91c7b15..b9d12b99dc 100644 --- a/src/app/file/jpeg_format.cpp +++ b/src/app/file/jpeg_format.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018-2023 Igara Studio S.A. +// Copyright (C) 2018-2024 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -31,6 +31,7 @@ #include "jpeg_options.xml.h" #include "jpeglib.h" +#include "TinyEXIF.h" namespace app { @@ -177,12 +178,38 @@ bool JpegFormat::onLoad(FileOp* fop) // Start decompressor. jpeg_start_decompress(&dinfo); + // Get orientation: + TinyEXIF::EXIFInfo info; + int orientation = 0; +#if LAF_WINDOWS + int tempBufSize = (int)std::ftell(file); + rewind(file); + char *tempBuf = (char *)malloc(sizeof(char) * tempBufSize); + if (!tempBuf) { + std::free(tempBuf); + jpeg_destroy_decompress(&dinfo); + return false; + } + fread(tempBuf, sizeof(char), tempBufSize, file); + info.parseFrom((u_int8_t*)tempBuf, tempBufSize); + orientation = info.Orientation; + std::free(tempBuf); +#elif LAF_MACOS + info.parseFrom(file->_bf._base, file->_bf._size); + orientation = info.Orientation; +#elif LAF_LINUX + int fileSize = std::ftell(file); + info.parseFrom(file->_IO_read_base, fileSize); + orientation = info.Orientation; +#endif + int outputW = (orientation < 5 ? dinfo.output_width : dinfo.output_height); + int outputH = (orientation < 5 ? dinfo.output_height : dinfo.output_width); // Create the image. ImageRef image = fop->sequenceImageToLoad( (dinfo.out_color_space == JCS_RGB ? IMAGE_RGB: IMAGE_GRAYSCALE), - dinfo.output_width, - dinfo.output_height); + outputW, + outputH); if (!image) { jpeg_destroy_decompress(&dinfo); return false; @@ -217,6 +244,61 @@ bool JpegFormat::onLoad(FileOp* fop) while (dinfo.output_scanline < dinfo.output_height) { num_scanlines = jpeg_read_scanlines(&dinfo, buffer, buffer_height); + // Orientation function/variables adjust + std::function start_dst_x; + std::function start_dst_y; + int next_addr_increment = 1; + switch (orientation) { + case 2: + start_dst_x = [image](int y) { return image->width() - 1; }; + start_dst_y = [dinfo](int y) { + return dinfo.output_scanline - 1 + y; }; + next_addr_increment = -1; + break; + case 3: + start_dst_x = [image](int y) { return image->width() - 1; }; + start_dst_y = [image, dinfo](int y) { + return image->height() - dinfo.output_scanline + y; }; + next_addr_increment = -1; + break; + case 4: + start_dst_x = [](int y) { return 0; }; + start_dst_y = [image, dinfo](int y) { + return image->height() - dinfo.output_scanline - y; }; + next_addr_increment = 1; + break; + case 5: + start_dst_x = [dinfo](int y) { + return dinfo.output_scanline - 1 + y; }; + start_dst_y = [](int y) { return 0; }; + next_addr_increment = image->width(); + break; + case 6: + start_dst_x = [image, dinfo](int y) { + return image->width() - dinfo.output_scanline - y; }; + start_dst_y = [](int y) { return 0; }; + next_addr_increment = image->width(); + break; + case 7: + start_dst_x = [image, dinfo](int y) { + return image->width() - dinfo.output_scanline - y; }; + start_dst_y = [image](int y) { return image->height() - 1; }; + next_addr_increment = -image->width(); + break; + case 8: + start_dst_x = [dinfo](int y) { + return dinfo.output_scanline - 1 + y; }; + start_dst_y = [image](int y) { return image->height() - 1; }; + next_addr_increment = -image->width(); + break; + default: + start_dst_x = [](int y) { return 0; }; + start_dst_y = [dinfo](int y) { + return dinfo.output_scanline - 1 + y; }; + next_addr_increment = 1; + break; + } + // RGB if (image->pixelFormat() == IMAGE_RGB) { uint8_t* src_address; @@ -225,13 +307,14 @@ bool JpegFormat::onLoad(FileOp* fop) for (y=0; y<(int)num_scanlines; y++) { src_address = ((uint8_t**)buffer)[y]; - dst_address = (uint32_t*)image->getPixelAddress(0, dinfo.output_scanline-1+y); + dst_address = (uint32_t*)image->getPixelAddress(start_dst_x(y), start_dst_y(y)); - for (x=0; xwidth(); x++) { + for (x=0; xgetPixelAddress(0, dinfo.output_scanline-1+y); + dst_address = (uint16_t*)image->getPixelAddress(start_dst_x(y), start_dst_y(y)); - for (x=0; xwidth(); x++) - *(dst_address++) = graya(*(src_address++), 255); + for (x=0; x