Files
workinf_Blender_Wasm/blender-5.2.0/source/blender/imbuf/IMB_imbuf.hh
2026-08-12 04:47:48 -04:00

663 lines
23 KiB
C++

/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbuf
*/
#pragma once
#include "../gpu/GPU_texture.hh"
#include "BLI_enum_flags.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_span.hh"
#include "BLI_vector.hh"
#include "IMB_imbuf_types.hh"
namespace blender {
struct ImBuf;
struct rctf;
struct rcti;
struct ImageFormatData;
struct Stereo3dFormat;
/**
* Module init/exit.
*/
void IMB_init();
void IMB_exit();
/**
* Module GPU context management.
*/
void IMB_ensure_gpu_context();
void IMB_activate_gpu_context();
void IMB_deactivate_gpu_context();
/**
* Load image.
*/
ImBuf *IMB_load_image_from_memory(const unsigned char *mem,
size_t size,
ImBufFlags flags,
const char *descr,
const char *filepath = nullptr,
char r_colorspace[IM_MAX_SPACE] = nullptr);
ImBuf *IMB_load_image_from_file_descriptor(int file,
ImBufFlags flags,
const char *filepath = nullptr,
char r_colorspace[IM_MAX_SPACE] = nullptr);
ImBuf *IMB_load_image_from_filepath(const char *filepath,
ImBufFlags flags,
char r_colorspace[IM_MAX_SPACE] = nullptr);
/**
* Save image.
*/
bool IMB_save_image(ImBuf *ibuf, const char *filepath, ImBufFlags flags);
Vector<uint8_t> IMB_save_image_to_buffer(ImBuf *ibuf, ImBufFlags flags);
/**
* Test image file.
*/
bool IMB_test_image(const char *filepath);
bool IMB_test_image_type_matches(const char *filepath, eImbFileType filetype);
eImbFileType IMB_test_image_type_from_memory(const unsigned char *buf, size_t buf_size);
eImbFileType IMB_test_image_type(const char *filepath);
/**
* Return true if the file type is supported (compiled in).
*/
bool IMB_ftype_is_supported(eImbFileType ftype);
/**
* Return the string identifier for a file type, or nullptr if not found.
*/
const char *IMB_ftype_to_id(eImbFileType ftype);
/**
* Return the file type enum value for a string identifier, or #IMB_FTYPE_NONE if not found.
*/
eImbFileType IMB_ftype_from_id(const char *id);
/**
* Return the null-terminated list of extensions for a file type, or nullptr if not found.
*/
const char **IMB_ftype_file_extensions(eImbFileType ftype);
/**
* Return the read capability flags for a file type.
*/
eImFileTypeCapability IMB_ftype_capability_read(eImbFileType ftype);
/**
* Return the write capability flags for a file type.
*/
eImFileTypeCapability IMB_ftype_capability_write(eImbFileType ftype);
/**
* Load thumbnail image.
*/
enum class IMBThumbLoadFlags {
Zero = 0,
/** Normally files larger than 100MB are not loaded for thumbnails, except when this flag is set.
*/
LoadLargeFiles = (1 << 0),
};
ENUM_OPERATORS(IMBThumbLoadFlags);
ImBuf *IMB_thumb_load_image(const char *filepath,
size_t max_thumb_size,
char colorspace[IM_MAX_SPACE],
IMBThumbLoadFlags load_flags = IMBThumbLoadFlags::Zero);
/**
* Allocate and free image buffer.
*/
ImBuf *IMB_allocImBuf(unsigned int x, unsigned int y, ImBufFlags flags);
void IMB_freeImBuf(ImBuf *ibuf);
/**
* Initialize given ImBuf.
*
* Use in cases when temporary image buffer is allocated on stack.
*/
bool IMB_initImBuf(ImBuf *ibuf, unsigned int x, unsigned int y, ImBufFlags flags);
/**
* Create a copy of a pixel buffer and wrap it to a new ImBuf
* (transferring ownership to the in imbuf).
*/
ImBuf *IMB_allocFromBufferOwn(uint8_t *byte_buffer,
float *float_buffer,
unsigned int w,
unsigned int h,
unsigned int channels);
/**
* Create a copy of a pixel buffer and wrap it to a new ImBuf
*/
ImBuf *IMB_allocFromBuffer(const uint8_t *byte_buffer,
const float *float_buffer,
unsigned int w,
unsigned int h,
unsigned int channels);
/**
* Assign the GPU texture of the buffer to the given texture. The current GPU texture is released.
*
* \note Does not modify the topology (width, height, number of channels).
*/
void IMB_assign_gpu_texture(ImBuf *ibuf, gpu::Texture *texture);
/**
* Reads the GPU data texture of the image buffer if it exists and assigns the data to the float
* buffer. This is only done if the buffer has the IB_HOST_BUFFER_INVALID flag is set, which is
* then reset after the function executes.
*
* \warning Not thread-safe, so callee should worry about thread locks.
*/
void IMB_ensure_host_buffer(ImBuf *ibuf);
/**
* Increase reference count to imbuf
* (to delete an imbuf you have to call freeImBuf as many times as it
* is referenced)
*/
void IMB_refImBuf(ImBuf *ibuf);
ImBuf *IMB_makeSingleUser(ImBuf *ibuf);
ImBuf *IMB_dupImBuf(const ImBuf *ibuf1);
/**
* Approximate size of ImBuf in memory
*/
size_t IMB_get_size_in_memory(const ImBuf *ibuf);
/**
* \brief Get the length of the data of the given image buffer in pixels.
*
* This is the width * the height of the image buffer.
* This function is preferred over `ibuf->x * ibuf->y` due to 32 bit int overflow
* issues when working with very large resolution images.
*/
size_t IMB_get_pixel_count(const ImBuf *ibuf);
enum IMB_BlendMode {
IMB_BLEND_MIX = 0,
IMB_BLEND_ADD = 1,
IMB_BLEND_SUB = 2,
IMB_BLEND_MUL = 3,
IMB_BLEND_LIGHTEN = 4,
IMB_BLEND_DARKEN = 5,
IMB_BLEND_ERASE_ALPHA = 6,
IMB_BLEND_ADD_ALPHA = 7,
IMB_BLEND_OVERLAY = 8,
IMB_BLEND_HARDLIGHT = 9,
IMB_BLEND_COLORBURN = 10,
IMB_BLEND_LINEARBURN = 11,
IMB_BLEND_COLORDODGE = 12,
IMB_BLEND_SCREEN = 13,
IMB_BLEND_SOFTLIGHT = 14,
IMB_BLEND_PINLIGHT = 15,
IMB_BLEND_VIVIDLIGHT = 16,
IMB_BLEND_LINEARLIGHT = 17,
IMB_BLEND_DIFFERENCE = 18,
IMB_BLEND_EXCLUSION = 19,
IMB_BLEND_HUE = 20,
IMB_BLEND_SATURATION = 21,
IMB_BLEND_LUMINOSITY = 22,
IMB_BLEND_COLOR = 23,
IMB_BLEND_INTERPOLATE = 24,
IMB_BLEND_COPY_RGB = 1001,
IMB_BLEND_COPY_ALPHA = 1002,
};
void IMB_blend_color_byte(unsigned char dst[4],
const unsigned char src1[4],
const unsigned char src2[4],
IMB_BlendMode mode);
void IMB_blend_color_float(float dst[4],
const float src1[4],
const float src2[4],
IMB_BlendMode mode);
void IMB_blend_color_float(MutableSpan<float4> dst,
Span<float4> src1,
Span<float4> src2,
IMB_BlendMode mode);
/**
* Copy a rectangle of pixel data from one image buffer to another. The source and destination
* buffers are described by the pointers and corresponding 2D sizes. They must not reference the
* same memory.
*/
void IMB_copy_rect(float *dst,
const int2 &dst_size,
const float *src,
const int2 &src_size,
int channels,
const int2 &src_rect_pos,
const int2 &dst_rect_pos,
const int2 &rect_size);
void IMB_copy_rect(uchar *dst,
const int2 &dst_size,
const uchar *src,
const int2 &src_size,
const int2 &src_rect_pos,
const int2 &dst_rect_pos,
const int2 &rect_size);
/**
* In-place image crop. `rect` is *inclusive*.
*/
void IMB_crop(ImBuf *ibuf, const int2 &rect_pos, const int2 &rect_size);
/**
* Copy a rectangle of pixel data from one image buffer to another. Data outside of the destination
* rectangle is not written to.
*/
void IMB_copy_rect(ImBuf *dst,
const ImBuf *src,
const int2 &src_rect_pos,
const int2 &dst_rect_pos,
const int2 &rect_size);
/**
* In-place size setting (caller must fill in buffer contents).
*/
void IMB_rect_size_set(ImBuf *ibuf, const uint size[2]);
void IMB_rectclip(ImBuf *dbuf,
const ImBuf *sbuf,
int *destx,
int *desty,
int *srcx,
int *srcy,
int *width,
int *height);
void IMB_rectblend(ImBuf *dbuf,
const ImBuf *obuf,
const ImBuf *sbuf,
unsigned short *dmask,
const unsigned short *curvemask,
const unsigned short *texmask,
float mask_max,
int destx,
int desty,
int origx,
int origy,
int srcx,
int srcy,
int width,
int height,
IMB_BlendMode mode,
bool accumulate);
void IMB_rectblend_threaded(ImBuf *dbuf,
const ImBuf *obuf,
const ImBuf *sbuf,
unsigned short *dmask,
const unsigned short *curvemask,
const unsigned short *texmask,
float mask_max,
int destx,
int desty,
int origx,
int origy,
int srcx,
int srcy,
int width,
int height,
IMB_BlendMode mode,
bool accumulate);
enum eIMBInterpolationFilterMode {
IMB_FILTER_NEAREST,
IMB_FILTER_BILINEAR,
IMB_FILTER_CUBIC_BSPLINE,
IMB_FILTER_CUBIC_MITCHELL,
IMB_FILTER_BOX,
};
#define FILTER_MASK_NULL 0
#define FILTER_MASK_MARGIN 1
#define FILTER_MASK_USED 2
void IMB_mask_filter_extend(char *mask, int width, int height);
void IMB_mask_clear(ImBuf *ibuf, const char *mask, int val);
/**
* If alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0
* When a mask is given, the mask will be used instead of the alpha channel, where only
* pixels with a mask value of 0 will be written to, and only pixels with a mask value of 1
* will be used for the average. The mask will be set to one for the pixels which were written.
*/
void IMB_filter_extend(ImBuf *ibuf, char *mask, int filter);
void IMB_filtery(ImBuf *ibuf);
/** Interpolation filter used by `IMB_scale`. */
enum class IMBScaleFilter {
/** No filtering (point sampling). This is fastest but lowest quality. */
Nearest,
/**
* Bilinear filter: each pixel in result image interpolates between 2x2 pixels of source image.
*/
Bilinear,
/**
* Box filter. Behaves exactly like Bilinear when scaling up,
* better results when scaling down by more than 2x.
*/
Box,
};
void IMB_scale_box(const float *src_buffer,
int2 src_size,
int channels,
float *dst_buffer,
int2 dst_size,
bool threaded);
void IMB_scale_box(const uchar *src_buffer,
int2 src_size,
int channels,
uchar *dst_buffer,
int2 dst_size,
bool threaded);
/**
* Scale/resize image to new dimensions.
* Return true if \a ibuf is modified.
*/
bool IMB_scale(ImBuf *ibuf, int2 new_size, IMBScaleFilter filter, bool threaded = true);
inline bool IMB_scale(
ImBuf *ibuf, unsigned int newx, unsigned int newy, IMBScaleFilter filter, bool threaded = true)
{
return IMB_scale(ibuf, int2(newx, newy), filter, threaded);
}
/**
* Scale/resize image to new dimensions, into a newly created result image.
* Metadata of input image (if any) is copied into the result image.
*/
ImBuf *IMB_scale_into_new(const ImBuf *ibuf,
int2 new_size,
IMBScaleFilter filter,
bool threaded = true);
inline ImBuf *IMB_scale_into_new(const ImBuf *ibuf,
unsigned int newx,
unsigned int newy,
IMBScaleFilter filter,
bool threaded = true)
{
return IMB_scale_into_new(ibuf, int2(newx, newy), filter, threaded);
}
/**
* Test if color-space conversions of pixels in buffer need to take into account alpha.
*/
bool IMB_alpha_affects_rgb(const ImBuf *ibuf);
/**
* Create char buffer, color corrected if necessary, for ImBufs that lack one.
*/
void IMB_byte_from_float(ImBuf *ibuf);
void IMB_float_from_byte_ex(ImBuf *dst, const ImBuf *src, const rcti *region_to_update);
void IMB_float_from_byte(ImBuf *ibuf);
void IMB_color_to_bw(ImBuf *ibuf);
void IMB_saturation(ImBuf *ibuf, float sat);
/**
* Convert float pixels to byte pixels.
* \param dest Destination, always 4 channel RGBA, non-premultiplied.
* \param src Source.
* \param src_channels Source channels (1, 3, 4).
* \param dither Amount of dithering to apply to destination.
* \param predivide Is source alpha premultiplied.
* \param width Width in pixels.
* \param height Height in pixels.
* \param stride Row stride in pixels.
*/
void IMB_buffer_byte_from_float(unsigned char *dest,
const float *src,
int src_channels,
float dither,
bool predivide,
int width,
int height,
int stride,
int start_y = 0);
/**
* Same as #IMB_buffer_byte_from_float, but only writes destination
* pixels where corresponding mask value is #FILTER_MASK_USED.
*/
void IMB_buffer_byte_from_float_mask(unsigned char *dest,
const float *src,
int src_channels,
float dither,
int width,
int height,
const char *mask);
/**
* Convert byte pixels to float pixels.
* \param dest Destination, always 4 channel RGBA, non-premultiplied.
* \param src Source, always 4 channel RGBA, non-premultiplied.
* \param width Width in pixels.
* \param height Height in pixels.
* \param dest_stride Destination row stride in pixels.
* \param src_stride Source row stride in pixels.
*/
void IMB_buffer_float_from_byte(
float *dest, const unsigned char *src, int width, int height, int dest_stride, int src_stride);
/**
* Convert 1/3/4 channel float pixels to 4 channel (RGBA) float pixels.
* \param dest Destination, always 4 channel.
* \param src Source.
* \param src_channels Source channels (1, 3, 4).
* \param width Width in pixels.
* \param height Height in pixels.
*/
void IMB_buffer_float_rgba_from_float(
float *dest, const float *src, int src_channels, int width, int height);
/**
* Same as #IMB_buffer_float_rgba_from_float, but only writes destination
* pixels where corresponding mask value is #FILTER_MASK_USED.
*/
void IMB_buffer_float_rgba_from_float_mask(
float *dest, const float *src, int src_channels, int width, int height, const char *mask);
void IMB_buffer_float_rgba_srgb_to_linear(float *buffer, int width, int height);
void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3]);
void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, const float backcol[3]);
void IMB_flipx(ImBuf *ibuf);
void IMB_flipy(ImBuf *ibuf);
/** Rotate by 90 degree increments. Returns true if the ImBuf is altered. */
bool IMB_rotate_orthogonal(ImBuf *ibuf, int degrees);
/* Pre-multiply alpha. */
void IMB_premultiply_alpha(ImBuf *ibuf);
void IMB_unpremultiply_alpha(ImBuf *ibuf);
/**
* Replace pixels of entire image with solid color.
* \param drect: An image to be filled with color. It must be 4 channel image.
* \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
*/
void IMB_rectfill(ImBuf *drect, const float col[4]);
/**
* Blend pixels of image area with solid color.
*
* \param ibuf: an image to be filled with color. It must be 4 channel image.
* \param scene_linear_color: RGBA color in scene linear colorspace. For byte buffers, this is
* converted to the byte buffer colorspace.
* \param x1, y1, x2, y2: (x1, y1) defines starting point
* of the rectangular area to be filled, (x2, y2) is the end point. Note that values are allowed to
* be loosely ordered, which means that x2 is allowed to be lower than x1, as well as y2 is allowed
* to be lower than y1. No matter the order the area between x1 and x2, and y1 and y2 is filled.
*/
void IMB_rectfill_area(
ImBuf *ibuf, const float scene_linear_color[4], int x1, int y1, int x2, int y2);
void IMB_rectfill_alpha(ImBuf *ibuf, float value);
/**
* Exported for image tools in blender, to quickly allocate 32 bits rect.
*/
void *imb_alloc_pixels(unsigned int x,
unsigned int y,
unsigned int channels,
size_t typesize,
bool initialize_pixels,
const char *alloc_name);
/**
* Allocate storage for byte type pixels.
* If the image already contains byte data storage, it is freed first.
*/
bool IMB_alloc_byte_pixels(ImBuf *ibuf, bool initialize_pixels = true);
/**
* Deallocate image byte storage.
*/
void IMB_free_byte_pixels(ImBuf *ibuf);
/**
* Allocate storage for float type pixels.
* If the image already contains float data storage, it is freed first.
*/
bool IMB_alloc_float_pixels(ImBuf *ibuf, unsigned int channels, bool initialize_pixels = true);
/**
* Deallocate image float storage.
*/
void IMB_free_float_pixels(ImBuf *ibuf);
/** Deallocate all CPU side data storage (byte, float). */
void IMB_free_all_data(ImBuf *ibuf);
/**
* Free the GPU textures of the given image buffer, leaving the CPU buffers unchanged.
* The ibuf can be nullptr, in which case the function does nothing.
*/
void IMB_free_gpu_textures(ImBuf *ibuf);
/**
* \brief Transform modes to use for IMB_transform function.
*
* These are not flags as the combination of cropping and repeat can lead to different expectation.
*/
enum eIMBTransformMode {
/** \brief Do not crop or repeat. */
IMB_TRANSFORM_MODE_REGULAR = 0,
/** \brief Crop the source buffer. */
IMB_TRANSFORM_MODE_CROP_SRC = 1,
/** \brief Wrap repeat the source buffer. Only supported in with nearest filtering. */
IMB_TRANSFORM_MODE_WRAP_REPEAT = 2,
};
/**
* \brief Transform source image buffer onto destination image buffer using a transform matrix.
*
* \param src: Image buffer to read from.
* \param dst: Image buffer to write to. rect or rect_float must already be initialized.
* - dst buffer must be a 4 channel buffers.
* - Only one data type buffer will be used (rect_float has priority over rect)
* \param mode: Cropping/Wrap repeat effect to apply during transformation.
* \param filter: Interpolation to use during sampling.
* \param transform_matrix: Transformation matrix to use.
* The given matrix should transform between dst pixel space to src pixel space.
* One unit is one pixel.
* \param src_crop: Cropping region how to crop the source buffer. Should only be passed when mode
* is set to #IMB_TRANSFORM_MODE_CROP_SRC. For any other mode this should be empty.
*
* During transformation no data/color conversion will happens.
* When transforming between float images the number of channels of the source buffer may be
* between 1 and 4. When source buffer has one channel the data will be read as a gray scale value.
*/
void IMB_transform(const ImBuf *src,
ImBuf *dst,
eIMBTransformMode mode,
eIMBInterpolationFilterMode filter,
const float3x3 &transform_matrix,
const rctf *src_crop);
/* Creates a GPU texture from the given image buffer and name. If use_high_bitdepth is true, float
* image buffers will be stored in full float textures, otherwise, they will be stored in half
* float textures. If use_premult is true, the image buffer data will be stored premultiplied. If
* limit_size is true, the texture will be scaled down to match the maximum size allowed by the
* U.glreslimit user preferences setting. */
gpu::Texture *IMB_create_gpu_texture(const char *name,
ImBuf *ibuf,
bool use_high_bitdepth,
bool use_premult,
const bool limit_size);
gpu::TextureFormat IMB_gpu_get_texture_format(const ImBuf *ibuf,
bool high_bitdepth,
bool use_grayscale);
bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, gpu::TextureFormat *r_texture_format);
/**
* Ensures that values stored in the float rect can safely loaded into half float gpu textures.
*
* Does nothing when given image_buffer doesn't contain a float rect.
*/
void IMB_gpu_clamp_half_float(ImBuf *image_buffer);
/**
* The `ibuf` is only here to detect the storage type. The produced texture will have undefined
* content. It will need to be populated by using #IMB_update_gpu_texture_sub().
*/
gpu::Texture *IMB_touch_gpu_texture(const char *name,
ImBuf *ibuf,
int w,
int h,
int layers,
bool use_high_bitdepth,
bool use_grayscale);
/**
* Will update a #gpu::Texture using the content of the #ImBuf. Only one layer will be
* updated. Will resize the ibuf if needed. Z is the layer to update. Unused if the texture is 2D.
*/
void IMB_update_gpu_texture_sub(gpu::Texture *tex,
ImBuf *ibuf,
int x,
int y,
int z,
int w,
int h,
bool use_high_bitdepth,
bool use_grayscale,
bool use_premult);
void IMB_stereo3d_write_dimensions(
char mode, bool is_squeezed, size_t width, size_t height, size_t *r_width, size_t *r_height);
void IMB_stereo3d_read_dimensions(
char mode, bool is_squeezed, size_t width, size_t height, size_t *r_width, size_t *r_height);
/**
* Left/right are always float.
*/
ImBuf *IMB_stereo3d_ImBuf(const ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right);
/**
* Reading a stereo encoded ibuf (*left) and generating two ibufs from it (*left and *right).
*/
void IMB_ImBufFromStereo3d(const Stereo3dFormat *s3d,
ImBuf *ibuf_stereo3d,
ImBuf **r_ibuf_left,
ImBuf **r_ibuf_right);
} // namespace blender