C

Qt Quick Ultralite imagedecoder Example

# Copyright (C) 2026 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial
cmake_minimum_required(VERSION 3.21.1)

if (QUL_PLATFORM MATCHES "autosar")
    return()
endif()

project(imagedecoder VERSION 0.0.1 LANGUAGES C CXX ASM)

find_package(QulApp)

# The "no filesystem support" platforms don't load basse-terre-guadeloupe.jpg /
# yosemite-national-park.jpg from an SD card / posix filesystem at all; instead
# all four images are embedded resources, and the root QML file is a dedicated
# variant that only references embedded (non file://) image paths.
set(IMAGEDECODER_ROOT_QML "rootqml/imagedecoder.qml")
set(IMAGEDECODER_RESOURCES grand-canyon-arizona.jpg sequoia-national-park.jpg)
set(IMAGEDECODER_MAX_RESOURCE_CACHE_SIZE 2000000)

if(CMAKE_CROSSCOMPILING)
    if(QUL_PLATFORM MATCHES "^stm32")
        # Custom JPG encoder supported
        if(QUL_PLATFORM MATCHES "^stm32f7")
            set(STM32XX "stm32f7")
        elseif(QUL_PLATFORM MATCHES "^stm32u5")
            if (NOT QUL_PLATFORM_ENABLE_EMMC)
                message(WARNING "For the image decoder to load from a filesystem, "
                                "QUL_PLATFORM_ENABLE_EMMC needs to be enabled. "
                                "Without eMMC, you have to change the QML project to not load "
                                "the images from external storage")
                return()
            endif()
            set(STM32XX "stm32u5")
        elseif(QUL_PLATFORM MATCHES "^stm32h7")
            set(STM32XX "stm32h7")
            set(IMAGEDECODER_ROOT_QML "rootqml/+noFilesystemSupport/imagedecoder.qml")
            list(APPEND IMAGEDECODER_RESOURCES basse-terre-guadeloupe.jpg yosemite-national-park.jpg)
            set(IMAGEDECODER_MAX_RESOURCE_CACHE_SIZE 512000)
        endif()
    elseif(QUL_PLATFORM MATCHES "^tviic2d6m[^-]*-baremetal")
        # In CI we test with the 500-BGA variant with graphics driver TVII_GRAPHICS_DRIVER_DIR_1_1_0_4M6M
        # (infineon-traveo-t2g-cyt4dn-baremetal-500-bga-windows-ghs-arm)
        # and to be able to build the imagedecoder backend an SDL upgrade is required.
        if(QUL_TVIIC2D6M_BOARD_REVISION STREQUAL "500-BGA")
            return()
        endif()
        if(ARMGCC)
            # The JPEG driver does not support ARMGCC at the moment.
            return()
        endif()
        set(IMAGEDECODER_ROOT_QML "rootqml/+noFilesystemSupport/imagedecoder.qml")
        list(APPEND IMAGEDECODER_RESOURCES basse-terre-guadeloupe.jpg yosemite-national-park.jpg)
        set(IMAGEDECODER_MAX_RESOURCE_CACHE_SIZE 1500000)
    elseif(QUL_PLATFORM MATCHES "rh850-d1m1a-baremetal")
        set(IMAGEDECODER_ROOT_QML "rootqml/+noFilesystemSupport/imagedecoder.qml")
        list(APPEND IMAGEDECODER_RESOURCES basse-terre-guadeloupe.jpg yosemite-national-park.jpg)
        set(IMAGEDECODER_MAX_RESOURCE_CACHE_SIZE 524288)
    else()
        return()
    endif()
elseif(QUL_PLATFORM STREQUAL "qt")
    find_package(Qt6 6.2 COMPONENTS Gui QUIET)
    if(NOT Qt6Gui_FOUND)
        set(DEFAULT_QT6_VERSION 6.2.4)
        if(WIN32)
            set(DEFAULT_QT6_PATH C:\\Qt\\${DEFAULT_QT6_VERSION}\\msvc2019_64)
        else()
            set(DEFAULT_QT6_PATH $HOME/Qt/${DEFAULT_QT6_VERSION}/gcc_64)
        endif()
        message(FATAL_ERROR "Qt6 is required to build the image decoder example. "
                            "Use -DCMAKE_PREFIX_PATH=${DEFAULT_QT6_PATH} or similar to specify the location of Qt6, "
                            "depending on which Qt version is used and where it is installed. "
                            "Alternatively, check the documentation for this example for more detailed instructions."
                          )
    endif()
else()
    return()
endif()

qul_add_executable(imagedecoder os/${QUL_OS_LOWERCASE}/main.cpp)

set_source_files_properties(${IMAGEDECODER_RESOURCES} PROPERTIES
    QUL_RESOURCE_KEEP_RAW_DATA ON
)

qul_add_qml_module(imagedecoder
    URI ImagedecoderApp
    QML_FILES ${IMAGEDECODER_ROOT_QML}
    RESOURCES ${IMAGEDECODER_RESOURCES}
)

qul_set_maximum_resource_cache_size(imagedecoder CACHE_SIZE ${IMAGEDECODER_MAX_RESOURCE_CACHE_SIZE})

if(CMAKE_CROSSCOMPILING)
    if(QUL_PLATFORM MATCHES "^stm32")
        if(QUL_PLATFORM MATCHES "^stm32f7")
            target_sources(imagedecoder PRIVATE
                ../fileloading/3rdparty/FatFs/src/diskio.c
                ../fileloading/3rdparty/FatFs/src/ff.c
                ../fileloading/3rdparty/FatFs/src/ff_gen_drv.c
                ../fileloading/3rdparty/FatFs/src/option/unicode.c
                ../fileloading/3rdparty/FatFs/src/sd_diskio.c
                ${QUL_BOARD_SDK_DIR}/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_ll_sdmmc.c
                ${QUL_BOARD_SDK_DIR}/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_sd.c
                ${QUL_BOARD_SDK_DIR}/Drivers/BSP/STM32F769I-Discovery/stm32f769i_discovery_sd.c
                ${QUL_BOARD_SDK_DIR}/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_jpeg.c
                ${CMAKE_CURRENT_SOURCE_DIR}/stm/${STM32XX}/stm32f7xx_hal_msp.c
            )

            target_include_directories(imagedecoder PRIVATE
                ../fileloading/
                ../fileloading/3rdparty/FatFs/src/
            )

            target_compile_definitions(imagedecoder PRIVATE
                SUPPORT_FILESYSTEM
                FF_FS_READONLY
            )
        elseif(QUL_PLATFORM MATCHES "^stm32u5")
            target_sources(imagedecoder PRIVATE
                           ${CMAKE_CURRENT_SOURCE_DIR}/stm/${STM32XX}/board_config.cpp
                           ${CMAKE_CURRENT_SOURCE_DIR}/stm/${STM32XX}/buffer_config.cpp
                           ${CMAKE_CURRENT_SOURCE_DIR}/stm/${STM32XX}/stm32u5xx_hal_msp.c
                           ${CMAKE_CURRENT_SOURCE_DIR}/stm/stmimagedecoder.cpp
                           ${QUL_BOARD_SDK_DIR}/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_dma_ex.c
                           ${QUL_BOARD_SDK_DIR}/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_jpeg.c
                           ../fileloading/3rdparty/FatFs/src/diskio.c
                           ../fileloading/3rdparty/FatFs/src/ff.c
                           ../fileloading/3rdparty/FatFs/src/ff_gen_drv.c
                           ../fileloading/3rdparty/FatFs/src/option/unicode.c
            )

            target_include_directories(imagedecoder PRIVATE
                                       ../fileloading/
                                       ../fileloading/3rdparty/FatFs/src/
                                       ${QUL_PLATFORM_BOARDS_DIR}/st/stm32u5x9-discovery-common
            )
            target_compile_definitions(imagedecoder PRIVATE
                                       USE_JPEG_DECODER=1
                                       #USE_DMA_BASED_JPEG_DECODING
                                       SUPPORT_FILESYSTEM
                                       FF_FS_READONLY
            )
        elseif(QUL_PLATFORM MATCHES "^stm32h7")
            target_sources(imagedecoder PRIVATE
                ${QUL_BOARD_SDK_DIR}/Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_jpeg.c
                ${CMAKE_CURRENT_SOURCE_DIR}/stm/${STM32XX}/stm32h7xx_hal_msp.c
            )
        endif()

        target_sources(imagedecoder PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/stm/${STM32XX}/board_config.cpp
            ${CMAKE_CURRENT_SOURCE_DIR}/stm/${STM32XX}/buffer_config.cpp
            ${CMAKE_CURRENT_SOURCE_DIR}/stm/stmimagedecoder.cpp
            common/jpeg.cpp
            3rdparty/stm/Utilities/JPEG/jpeg_utils.c
        )

        target_include_directories(imagedecoder PRIVATE
            ${QUL_BOARD_SDK_DIR}/Utilities/JPEG
            ${CMAKE_CURRENT_SOURCE_DIR}/stm/${STM32XX}
            ${CMAKE_CURRENT_SOURCE_DIR}/stm
        )

        target_compile_definitions(imagedecoder PRIVATE
            USE_JPEG_DECODER=1
            PLATFORM_OS=${QUL_OS_LOWERCASE}
            USE_DMA_BASED_JPEG_DECODING
        )

        target_link_libraries(imagedecoder PRIVATE Qul::PlatformBSPConfig)

        if(NOT IAR)
            # Required for SDK code to build
            target_compile_options(imagedecoder PRIVATE
                -Wno-unused-parameter
            )
        endif()
    elseif(QUL_PLATFORM MATCHES "^tviic2d6m[^-]*-baremetal")
        set(TRAVEO_T2G_IMAGEDECODER_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/traveo-t2g")
        include("${TRAVEO_T2G_IMAGEDECODER_SOURCE_DIR}/tvii_jpeg_driver_lib.cmake") # will provide `TVII_JPEG_DRIVER_LIB`.

        target_sources(imagedecoder PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/traveo-t2g/board_config.cpp
            ${CMAKE_CURRENT_SOURCE_DIR}/traveo-t2g/traveot2gimagedecoder.cpp
            ${CMAKE_CURRENT_SOURCE_DIR}/traveo-t2g/tvii_jpeg.c
            common/jpeg.cpp
        )

        list(APPEND CMAKE_MODULE_PATH ${QUL_PLATFORM_TARGET_DIR}/../common/cmake/modules)
        # Old path needed for platform compatibility checks after UL-5159 (renamed folder from tvii-shared to common)
        list(APPEND CMAKE_MODULE_PATH ${QUL_PLATFORM_TARGET_DIR}/../tvii-shared/cmake/modules)
        find_package(TVII-SDK REQUIRED COMPONENTS basic_graphics util freetype)

        target_include_directories(imagedecoder PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/traveo-t2g/
            ${TVII_JPEG_DRIVER_DIR}/Source/jpgdec/include
            ${TVII_SDK_INCLUDE_DIRS}
        )

        target_link_libraries(imagedecoder PRIVATE Qul::PlatformBSPConfig ${TVII_JPEG_DRIVER_LIB})
        if(GREENHILLS)
            target_link_libraries(imagedecoder PRIVATE -T ${CMAKE_CURRENT_SOURCE_DIR}/traveo-t2g/JPEGDEC_register_map.ld)
        endif()

        if(IAR)
            target_compile_options(imagedecoder PRIVATE --diag_suppress=Pe940) # Pe940 missing return statement at end of non-void function (graphics driver 1.2.1)
        endif()
    elseif(QUL_PLATFORM MATCHES "rh850-d1m1a-baremetal")
        target_sources(imagedecoder PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/renesas-rh850/board_config.cpp
            ${CMAKE_CURRENT_SOURCE_DIR}/renesas-rh850/rh850imagedecoder.cpp
            ${CMAKE_CURRENT_SOURCE_DIR}/renesas-rh850/rh850_jpeg.cpp
            common/jpeg.cpp
        )

        target_include_directories(imagedecoder PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/renesas-rh850/
        )

        target_compile_definitions(imagedecoder PRIVATE
            USE_OUTPUT_SPLIT_MODE
            DECODE_BUFFER_PIXEL_LINES=16
            CHROMA_SUBSAMPLING=R_JCUA_JPEG_FORMAT_YCBCR420
        )

        target_link_libraries(imagedecoder PRIVATE Qul::PlatformBSPConfig)
    endif()
elseif(QUL_PLATFORM STREQUAL "qt")
    target_link_libraries(imagedecoder PRIVATE Qt6::Gui)
    target_sources(imagedecoder PRIVATE
                          desktop/desktopimagedecoder.cpp
                          desktop/board_config.cpp
                          ../fileloading/posix/posixfilesystem.cpp
                  )
    target_include_directories(imagedecoder PRIVATE ../fileloading/posix/)
    if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
        target_compile_options(imagedecoder PRIVATE -Wno-maybe-uninitialized) # desktopimagedecoder.cpp:129ff read into a byte array.
    endif()

    add_custom_command(TARGET imagedecoder POST_BUILD
      COMMAND ${CMAKE_COMMAND} -E
      copy_if_different "${CMAKE_CURRENT_LIST_DIR}/basse-terre-guadeloupe.jpg" "${CMAKE_CURRENT_LIST_DIR}/yosemite-national-park.jpg" "$<TARGET_FILE_DIR:imagedecoder>")
endif()

app_target_setup_os(imagedecoder)