mirror of
				https://github.com/slint-ui/slint.git
				synced 2025-11-03 21:24:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			267 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			267 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright © SixtyFPS GmbH <info@slint.dev>
 | 
						||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
 | 
						||
 | 
						||
#pragma once
 | 
						||
#include <string_view>
 | 
						||
#include <span>
 | 
						||
#include "slint_generated_public.h"
 | 
						||
#include "slint_size.h"
 | 
						||
#include "slint_image_internal.h"
 | 
						||
#include "slint_string.h"
 | 
						||
#include "slint_sharedvector.h"
 | 
						||
 | 
						||
namespace slint {
 | 
						||
 | 
						||
/// SharedPixelBuffer is a container for storing image data as pixels. It is
 | 
						||
/// internally reference counted and cheap to copy.
 | 
						||
///
 | 
						||
/// You can construct a new empty shared pixel buffer with its default constructor,
 | 
						||
/// or you can copy it from an existing contiguous buffer that you might already have, using the
 | 
						||
/// range constructor.
 | 
						||
///
 | 
						||
/// See the documentation for Image for examples how to use this type to integrate
 | 
						||
/// Slint with external rendering functions.
 | 
						||
template<typename Pixel>
 | 
						||
struct SharedPixelBuffer
 | 
						||
{
 | 
						||
    /// Construct an empty SharedPixelBuffer.
 | 
						||
    SharedPixelBuffer() = default;
 | 
						||
 | 
						||
    /// Construct a SharedPixelBuffer with the given \a width and \a height. The pixels are default
 | 
						||
    /// initialized.
 | 
						||
    SharedPixelBuffer(uint32_t width, uint32_t height)
 | 
						||
        : m_width(width), m_height(height), m_data(width * height)
 | 
						||
    {
 | 
						||
    }
 | 
						||
 | 
						||
    /// Construct a SharedPixelBuffer by copying the data from the \a data array.
 | 
						||
    /// The array must be of size \a width * \a height .
 | 
						||
    SharedPixelBuffer(uint32_t width, uint32_t height, const Pixel *data)
 | 
						||
        : m_width(width), m_height(height), m_data(data, data + (width * height))
 | 
						||
    {
 | 
						||
    }
 | 
						||
 | 
						||
    /// Returns the width of the buffer in pixels.
 | 
						||
    uint32_t width() const { return m_width; }
 | 
						||
    /// Returns the height of the buffer in pixels.
 | 
						||
    uint32_t height() const { return m_height; }
 | 
						||
 | 
						||
    /// Returns a const pointer to the first pixel of this buffer.
 | 
						||
    const Pixel *begin() const { return m_data.begin(); }
 | 
						||
    /// Returns a const pointer past this buffer.
 | 
						||
    const Pixel *end() const { return m_data.end(); }
 | 
						||
    /// Returns a pointer to the first pixel of this buffer.
 | 
						||
    Pixel *begin() { return m_data.begin(); }
 | 
						||
    /// Returns a pointer past this buffer.
 | 
						||
    Pixel *end() { return m_data.end(); }
 | 
						||
    /// Returns a const pointer to the first pixel of this buffer.
 | 
						||
    const Pixel *cbegin() const { return m_data.begin(); }
 | 
						||
    /// Returns a const pointer past this buffer.
 | 
						||
    const Pixel *cend() const { return m_data.end(); }
 | 
						||
 | 
						||
    /// Compare two SharedPixelBuffers. They are considered equal if all their pixels are equal.
 | 
						||
    bool operator==(const SharedPixelBuffer &other) const = default;
 | 
						||
 | 
						||
private:
 | 
						||
    friend struct Image;
 | 
						||
    uint32_t m_width;
 | 
						||
    uint32_t m_height;
 | 
						||
    SharedVector<Pixel> m_data;
 | 
						||
};
 | 
						||
 | 
						||
/// An image type that can be displayed by the Image element
 | 
						||
///
 | 
						||
/// You can construct Image objects from a path to an image file on disk, using
 | 
						||
/// Image::load_from_path().
 | 
						||
///
 | 
						||
/// Another typical use-case is to render the image content with C++ code.
 | 
						||
/// For this it’s most efficient to create a new SharedPixelBuffer with the known dimensions and
 | 
						||
/// pass the pixel pointer returned by begin() to your rendering function. Afterwards you can create
 | 
						||
/// an Image using the constructor taking a SharedPixelBuffer.
 | 
						||
///
 | 
						||
/// The following example creates a 320x200 RGB pixel buffer and calls a function to draw a shape
 | 
						||
/// into it:
 | 
						||
/// ```cpp
 | 
						||
/// slint::SharedPixelBuffer::<slint::Rgb8Pixel> pixel_buffer(320, 200);
 | 
						||
/// low_level_render(pixel_buffer.width(), pixel_buffer.height(),
 | 
						||
///                  static_cast<unsigned char *>(pixel_buffer.begin()));
 | 
						||
/// slint::Image image(pixel_buffer);
 | 
						||
/// ```
 | 
						||
///
 | 
						||
/// Another use-case is to import existing image data into Slint, by
 | 
						||
/// creating a new Image through copying of the buffer:
 | 
						||
///
 | 
						||
/// ```cpp
 | 
						||
/// slint::Image image(slint::SharedPixelBuffer<slint::Rgb8Pixel>(the_width, the_height,
 | 
						||
///     static_cast<slint::Rgb8Pixel*>(the_data));
 | 
						||
/// ```
 | 
						||
///
 | 
						||
/// This only works if the static_cast is valid and the underlying data has the same
 | 
						||
/// memory layout as slint::Rgb8Pixel or slint::Rgba8Pixel. Otherwise, you will have to do a
 | 
						||
/// pixel conversion as you copy the pixels:
 | 
						||
///
 | 
						||
/// ```cpp
 | 
						||
/// slint::SharedPixelBuffer::<slint::Rgb8Pixel> pixel_buffer(the_width, the_height);
 | 
						||
/// slint::Rgb8Pixel *raw_data = pixel_buffer.begin();
 | 
						||
/// for (int i = 0; i < the_width * the_height; i++) {
 | 
						||
///   raw_data[i] = { bgr_data[i * 3 + 2], bgr_data[i * 3 + 1], bgr_data[i * 3] };
 | 
						||
/// }
 | 
						||
/// ```
 | 
						||
struct Image
 | 
						||
{
 | 
						||
public:
 | 
						||
    /// This enum describes the origin to use when rendering a borrowed OpenGL texture.
 | 
						||
    enum class BorrowedOpenGLTextureOrigin {
 | 
						||
        /// The top-left of the texture is the top-left of the texture drawn on the screen.
 | 
						||
        TopLeft,
 | 
						||
        /// The bottom-left of the texture is the top-left of the texture draw on the screen,
 | 
						||
        /// flipping it vertically.
 | 
						||
        BottomLeft,
 | 
						||
    };
 | 
						||
 | 
						||
    Image() : data(Data::ImageInner_None()) { }
 | 
						||
 | 
						||
#ifndef SLINT_FEATURE_FREESTANDING
 | 
						||
    /// Load an image from an image file
 | 
						||
    [[nodiscard]] static Image load_from_path(const SharedString &file_path)
 | 
						||
    {
 | 
						||
        Image img;
 | 
						||
        cbindgen_private::types::slint_image_load_from_path(&file_path, &img.data);
 | 
						||
        return img;
 | 
						||
    }
 | 
						||
#endif
 | 
						||
 | 
						||
    /// Constructs a new Image from an existing OpenGL texture. The texture remains borrowed by
 | 
						||
    /// Slint for the duration of being used for rendering, such as when assigned as source property
 | 
						||
    /// to an `Image` element. It's the application's responsibility to delete the texture when it
 | 
						||
    /// is not used anymore.
 | 
						||
    ///
 | 
						||
    /// The texture must be bindable against the `GL_TEXTURE_2D` target, have `GL_RGBA` as format
 | 
						||
    /// for the pixel data.
 | 
						||
    ///
 | 
						||
    /// When Slint renders the texture, it assumes that the origin of the texture is at the
 | 
						||
    /// top-left. This is different from the default OpenGL coordinate system. If you want to
 | 
						||
    /// flip the origin, use BorrowedOpenGLTextureOrigin::BottomLeft.
 | 
						||
    ///
 | 
						||
    /// Safety:
 | 
						||
    ///
 | 
						||
    /// This function is unsafe because invalid texture ids may lead to undefined behavior in OpenGL
 | 
						||
    /// drivers. A valid texture id is one that was created by the same OpenGL context that is
 | 
						||
    /// current during any of the invocations of the callback set on
 | 
						||
    /// [`Window::set_rendering_notifier()`]. OpenGL contexts between instances of [`slint::Window`]
 | 
						||
    /// are not sharing resources. Consequently
 | 
						||
    /// [`slint::Image`] objects created from borrowed OpenGL textures cannot be shared between
 | 
						||
    /// different windows.
 | 
						||
    [[nodiscard]] static Image create_from_borrowed_gl_2d_rgba_texture(
 | 
						||
            uint32_t texture_id, Size<uint32_t> size,
 | 
						||
            BorrowedOpenGLTextureOrigin origin = BorrowedOpenGLTextureOrigin::TopLeft)
 | 
						||
    {
 | 
						||
        cbindgen_private::types::BorrowedOpenGLTextureOrigin origin_private =
 | 
						||
                origin == BorrowedOpenGLTextureOrigin::TopLeft
 | 
						||
                ? cbindgen_private::types::BorrowedOpenGLTextureOrigin::TopLeft
 | 
						||
                : cbindgen_private::types::BorrowedOpenGLTextureOrigin::BottomLeft;
 | 
						||
        return Image(Data::ImageInner_BorrowedOpenGLTexture(
 | 
						||
                cbindgen_private::types::BorrowedOpenGLTexture {
 | 
						||
                        texture_id,
 | 
						||
                        size,
 | 
						||
                        origin_private,
 | 
						||
                })
 | 
						||
 | 
						||
        );
 | 
						||
    }
 | 
						||
 | 
						||
    /// Construct an image from a SharedPixelBuffer of RGB pixels.
 | 
						||
    Image(SharedPixelBuffer<Rgb8Pixel> buffer)
 | 
						||
        : data(Data::ImageInner_EmbeddedImage(
 | 
						||
                cbindgen_private::types::ImageCacheKey::Invalid(),
 | 
						||
                cbindgen_private::types::SharedImageBuffer::RGB8(
 | 
						||
                        cbindgen_private::types::SharedPixelBuffer<Rgb8Pixel> {
 | 
						||
                                .width = buffer.width(),
 | 
						||
                                .height = buffer.height(),
 | 
						||
                                .data = buffer.m_data })))
 | 
						||
    {
 | 
						||
    }
 | 
						||
 | 
						||
    /// Construct an image from a SharedPixelBuffer of RGBA pixels.
 | 
						||
    Image(SharedPixelBuffer<Rgba8Pixel> buffer)
 | 
						||
        : data(Data::ImageInner_EmbeddedImage(
 | 
						||
                cbindgen_private::types::ImageCacheKey::Invalid(),
 | 
						||
                cbindgen_private::types::SharedImageBuffer::RGBA8(
 | 
						||
                        cbindgen_private::types::SharedPixelBuffer<Rgba8Pixel> {
 | 
						||
                                .width = buffer.width(),
 | 
						||
                                .height = buffer.height(),
 | 
						||
                                .data = buffer.m_data })))
 | 
						||
    {
 | 
						||
    }
 | 
						||
 | 
						||
    /// Returns the size of the Image in pixels.
 | 
						||
    Size<uint32_t> size() const
 | 
						||
    {
 | 
						||
        return cbindgen_private::types::slint_image_size(&data);
 | 
						||
    }
 | 
						||
 | 
						||
    /// Returns the path of the image on disk, if it was constructed via Image::load_from_path().
 | 
						||
    std::optional<slint::SharedString> path() const
 | 
						||
    {
 | 
						||
        if (auto *str = cbindgen_private::types::slint_image_path(&data)) {
 | 
						||
            return *str;
 | 
						||
        } else {
 | 
						||
            return {};
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    /// Sets the nine-slice edges of the image.
 | 
						||
    ///
 | 
						||
    /// [Nine-slice scaling](https://en.wikipedia.org/wiki/9-slice_scaling) is a method for scaling
 | 
						||
    /// images in such a way that the corners are not distorted.
 | 
						||
    /// The arguments define the pixel sizes of the edges that cut the image into 9 slices.
 | 
						||
    void set_nine_slice_edges(unsigned short top, unsigned short right, unsigned short bottom,
 | 
						||
                              unsigned short left)
 | 
						||
    {
 | 
						||
        cbindgen_private::types::slint_image_set_nine_slice_edges(&data, top, right, bottom, left);
 | 
						||
    }
 | 
						||
 | 
						||
    /// Returns true if \a a refers to the same image as \a b; false otherwise.
 | 
						||
    friend bool operator==(const Image &a, const Image &b)
 | 
						||
    {
 | 
						||
        return cbindgen_private::types::slint_image_compare_equal(&a.data, &b.data);
 | 
						||
    }
 | 
						||
    /// Returns false if \a a refers to the same image as \a b; true otherwise.
 | 
						||
    friend bool operator!=(const Image &a, const Image &b)
 | 
						||
    {
 | 
						||
        return !(a == b);
 | 
						||
    }
 | 
						||
 | 
						||
    /// \private
 | 
						||
    explicit Image(cbindgen_private::types::Image inner) : data(inner) { }
 | 
						||
 | 
						||
private:
 | 
						||
    using Tag = cbindgen_private::types::ImageInner::Tag;
 | 
						||
    using Data = cbindgen_private::types::Image;
 | 
						||
    Data data;
 | 
						||
};
 | 
						||
 | 
						||
namespace private_api {
 | 
						||
inline Image load_image_from_embedded_data(std::span<const uint8_t> data,
 | 
						||
                                           std::string_view extension)
 | 
						||
{
 | 
						||
    cbindgen_private::types::Image img(cbindgen_private::types::Image::ImageInner_None());
 | 
						||
    cbindgen_private::types::slint_image_load_from_embedded_data(
 | 
						||
            slint::cbindgen_private::Slice<uint8_t> { const_cast<uint8_t *>(data.data()),
 | 
						||
                                                      data.size() },
 | 
						||
            slint::cbindgen_private::Slice<uint8_t> {
 | 
						||
                    const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(extension.data())),
 | 
						||
                    extension.size() },
 | 
						||
            &img);
 | 
						||
    return Image(img);
 | 
						||
}
 | 
						||
 | 
						||
inline Image image_from_embedded_textures(const cbindgen_private::types::StaticTextures *textures)
 | 
						||
{
 | 
						||
    cbindgen_private::types::Image img(cbindgen_private::types::Image::ImageInner_None());
 | 
						||
    cbindgen_private::types::slint_image_from_embedded_textures(textures, &img);
 | 
						||
    return Image(img);
 | 
						||
}
 | 
						||
}
 | 
						||
 | 
						||
}
 |