Loading...
Searching...
No Matches
Bitmap.h
Go to the documentation of this file.
1/**************************************************************************************************
2 * This file is a part of Ultralight. *
3 * *
4 * See <https://ultralig.ht> for licensing and more. *
5 * *
6 * (C) 2024 Ultralight, Inc. *
7 **************************************************************************************************/
8#pragma once
10#include <Ultralight/RefPtr.h>
11#include <Ultralight/Geometry.h>
12#include <Ultralight/Buffer.h>
13
14namespace ultralight {
15
16///
17/// The various Bitmap formats.
18///
19enum class BitmapFormat : uint8_t {
20 ///
21 /// Alpha channel only, 8-bits per pixel.
22 ///
23 /// Encoding: 8-bits per channel, unsigned normalized.
24 ///
25 /// Color-space: Linear (no gamma), alpha-coverage only.
26 ///
28
29 ///
30 /// Blue Green Red Alpha channels, 32-bits per pixel.
31 ///
32 /// Encoding: 8-bits per channel, unsigned normalized.
33 ///
34 /// Color-space: sRGB gamma with premultiplied linear alpha channel.
35 ///
37};
38
39///
40/// Macro to get the bytes per pixel from a BitmapFormat
41///
42#define GetBytesPerPixel(x) (x == BitmapFormat::A8_UNORM ? 1 : 4)
43
44///
45/// Forward declaration for the LockedPixels class.
46///
47template<typename T>
48class LockedPixels;
49
50///
51/// Function signature for a user-defined destruction callback to be optionally called when the
52/// Bitmap is destroyed.
53///
54/// @param user_data Pointer to user-defined user-data (this will be the same value as what was
55/// passed to Bitmap::Create, if any)
56///
57/// @param data Pointer to raw Bitmap pixel data.
58///
59typedef void (*DestroyBitmapCallback)(void* user_data, void* data);
60
61///
62/// A thread-safe container for pixel data.
63///
64/// The bitmap class is used to store pixel data in a variety of formats. It intelligently manages
65/// the lifetime of the pixel buffer and provides thread-safe access to the pixel data.
66///
67/// ## Accessing Pixel Data
68///
69/// You can access the underlying pixel data by using the LockPixelsSafe() method. An example
70/// follows:
71///
72/// ```
73/// auto bitmap = Bitmap::Create(100, 100, BitmapFormat::BGRA8_UNORM_SRGB);
74/// auto pixels = bitmap->LockPixelsSafe();
75/// if (pixels && pixels.data()) {
76/// // Zero out the pixel buffer by setting every byte to 0.
77/// memset(pixels.data(), 0, pixels.size());
78/// }
79///
80/// // 'pixels' is automatically unlocked when it goes out of scope.
81/// ```
82class UExport Bitmap : public RefCounted {
83 public:
84 ///
85 /// Create an empty Bitmap. No pixels will be allocated.
86 ///
88
89 ///
90 /// Create a Bitmap with a certain configuration. Pixels will be allocated but not initialized.
91 ///
92 /// @param width The width in pixels.
93 ///
94 /// @param height The height in pixels.
95 ///
96 /// @param format The pixel format to use.
97 ///
98 /// @return A ref-pointer to a new Bitmap instance.
99 ///
100 static RefPtr<Bitmap> Create(uint32_t width, uint32_t height, BitmapFormat format);
101
102 ///
103 /// Create an aligned Bitmap with a certain configuration. Pixels will be allocated but not
104 /// initialized. Row bytes will be padded to reach the specified alignment.
105 ///
106 /// @param width The width in pixels.
107 ///
108 /// @param height The height in pixels.
109 ///
110 /// @param format The pixel format to use.
111 ///
112 /// @param alignment The alignment (in bytes) to use. Row bytes will be padded to reach a
113 /// multiple of this value and the underlying storage will be allocated with
114 /// this alignment.
115 ///
116 /// @return A ref-pointer to a new Bitmap instance.
117 ///
118 static RefPtr<Bitmap> Create(uint32_t width, uint32_t height, BitmapFormat format,
119 uint32_t alignment);
120
121 ///
122 /// Create a Bitmap with existing pixel data, a copy will be made unless should_copy is false.
123 ///
124 /// @param width The width in pixels.
125 ///
126 /// @param height The height in pixels.
127 ///
128 /// @param format The pixel format to use.
129 ///
130 /// @param row_bytes The number of bytes between each row (note that this value should be >=
131 /// width * bytes_per_pixel).
132 ///
133 /// @param pixels Pointer to raw pixel buffer.
134 ///
135 /// @param size Size of the raw pixel buffer.
136 ///
137 /// @param should_copy Whether or not a copy should be made of the pixels. If this is false
138 /// the returned Bitmap will use the raw pixels passed in as its own, but
139 /// you are still responsible for destroying your buffer afterwards.
140 ///
141 /// @return A ref-pointer to a new Bitmap instance.
142 ///
143 static RefPtr<Bitmap> Create(uint32_t width, uint32_t height, BitmapFormat format,
144 uint32_t row_bytes, const void* pixels, size_t size,
145 bool should_copy = true);
146
147 ///
148 /// Create a Bitmap that wraps existing pixel data, a user-defined destruction callback will be
149 /// called when the Bitmap wants to destroy the data.
150 ///
151 /// @param width The width in pixels.
152 ///
153 /// @param height The height in pixels.
154 ///
155 /// @param format The pixel format to use.
156 ///
157 /// @param row_bytes The number of bytes between each row (note that this value should be >=
158 /// width * bytes_per_pixel).
159 ///
160 /// @param pixels Pointer to raw pixel buffer.
161 ///
162 /// @param size Size of the raw pixel buffer.
163 ///
164 /// @param user_data Optional user data that will be passed to destruction_callback when the
165 /// Bitmap wants to destroy the pixel data. (Pass nullptr to ignore)
166 ///
167 /// @param destruction_callback Callback that will be called upon destruction.
168 ///
169 /// @return A ref-pointer to a new Bitmap instance.
170 ///
171 static RefPtr<Bitmap> Create(uint32_t width, uint32_t height, BitmapFormat format,
172 uint32_t row_bytes, const void* pixels, size_t size,
173 void* user_data, DestroyBitmapCallback destruction_callback);
174
175 ///
176 /// Create a bitmap from a deep copy of another Bitmap.
177 ///
178 static RefPtr<Bitmap> Create(const Bitmap& bitmap);
179
180 ///
181 /// Get the width in pixels.
182 ///
183 virtual uint32_t width() const = 0;
184
185 ///
186 /// Get the height in pixels.
187 ///
188 virtual uint32_t height() const = 0;
189
190 ///
191 /// Get the bounds as an IntRect
192 ///
193 virtual IntRect bounds() const = 0;
194
195 ///
196 /// Get the pixel format.
197 ///
198 virtual BitmapFormat format() const = 0;
199
200 ///
201 /// Get the number of bytes per pixel.
202 ///
203 virtual uint32_t bpp() const = 0;
204
205 ///
206 /// Get the number of bytes between each row of pixels.
207 ///
208 /// @note This value is usually calculated as width * bytes_per_pixel (bpp) but it may be larger
209 /// due to alignment rules in the allocator.
210 ///
211 virtual uint32_t row_bytes() const = 0;
212
213 ///
214 /// Get the size in bytes of the pixel buffer.
215 ///
216 /// @note Size is calculated as row_bytes() * height().
217 ///
218 virtual size_t size() const = 0;
219
220 ///
221 /// Whether or not this Bitmap owns the pixel buffer and will destroy it at the end of its
222 /// lifetime.
223 ///
224 virtual bool owns_pixels() const = 0;
225
226 ///
227 /// Lock the pixel buffer for reading/writing (safe version, automatically unlocks).
228 ///
229 /// @return A managed container that can be used to access the pixels (LockedPixels::data()).
230 /// This container will automatically unlock the pixels when it goes out of scope.
231 ///
233
234 ///
235 /// Lock the pixel buffer for reading/writing.
236 ///
237 /// @return A pointer to the pixel buffer.
238 ///
239 virtual void* LockPixels() = 0;
240
241 ///
242 /// Unlock the pixel buffer.
243 ///
244 virtual void UnlockPixels() = 0;
245
246 ///
247 /// Lock the pixel buffer for reading/writing. (const)
248 ///
249 /// @return A const pointer to the pixel buffer.
250 ///
251 virtual const void* LockPixels() const = 0;
252
253 ///
254 /// Unlock the pixel buffer. (const)
255 ///
256 virtual void UnlockPixels() const = 0;
257
258 ///
259 /// Get the raw pixel buffer.
260 ///
261 /// @note You should only call this if pixels are already locked.
262 ///
263 virtual void* raw_pixels() = 0;
264
265 ///
266 /// Whether or not this Bitmap is empty (no pixels allocated).
267 ///
268 virtual bool IsEmpty() const = 0;
269
270 ///
271 /// Erase the Bitmap (set all pixels to 0).
272 ///
273 virtual void Erase() = 0;
274
275 ///
276 /// Assign another bitmap to this one.
277 ///
278 /// @param bitmap The bitmap to copy from.
279 ///
280 virtual void Set(RefPtr<Bitmap> bitmap) = 0;
281
282 ///
283 /// Draw another bitmap to this bitmap.
284 ///
285 /// @note Formats do not need to match. Bitmap formats will be converted to one another
286 /// automatically. Note that when converting from BGRA8 to A8, only the Blue channel will
287 /// be used.
288 ///
289 /// @param src_rect The source rectangle, relative to src bitmap.
290 ///
291 /// @param dest_rect The destination rectangle, relative to this bitmap.
292 ///
293 /// @param src The source bitmap.
294 ///
295 /// @param pad_repeat Whether or not we should pad the drawn bitmap by one pixel of repeated
296 /// edge pixels from the source bitmap.
297 ///
298 /// @return Whether or not the operation succeeded (this can fail if the src_rect and/or
299 /// dest_rect are invalid).
300 ///
301 virtual bool DrawBitmap(IntRect src_rect, IntRect dest_rect, RefPtr<Bitmap> src, bool pad_repeat)
302 = 0;
303
304 ///
305 /// Encode this Bitmap as a PNG image and store the encoded bytes in a Buffer.
306 ///
307 /// @param convert_to_rgba The PNG format expects RGBA format but our bitmap is stored as BGRA,
308 /// set this to true to perform the conversion automatically.
309 ///
310 /// @param convert_to_straight_alpha The PNG format expects semi-transparent values to be
311 /// stored as straight alpha instead of premultiplied alpha,
312 /// set this to true to perform the conversion automatically.
313 ///
314 /// @return On success, a buffer containing the encoded bytes, otherwise a null RefPtr.
315 ///
316 virtual RefPtr<Buffer> EncodePNG(bool convert_to_rgba = true,
317 bool convert_to_straight_alpha = true) const = 0;
318
319 ///
320 /// Write this Bitmap out to a PNG image.
321 ///
322 /// @param path The filepath to write to (opened with fopen())
323 ///
324 /// @param convert_to_rgba The PNG format expects RGBA format but our bitmap is stored as BGRA,
325 /// set this to true to perform the conversion automatically.
326 ///
327 /// @param convert_to_straight_alpha The PNG format expects semi-transparent values to be
328 /// stored as straight alpha instead of premultiplied alpha,
329 /// set this to true to perform the conversion automatically.
330 ///
331 /// @return Whether or not the operation succeeded.
332 ///
333 virtual bool WritePNG(const char* path, bool convert_to_rgba = true,
334 bool convert_to_straight_alpha = true) const = 0;
335
336 ///
337 /// Make a resized copy of this bitmap by writing to a pre-allocated destination bitmap.
338 ///
339 /// @param destination The bitmap to store the result in, the width and height of the
340 /// destination will be used.
341 ///
342 /// @param high_quality Whether or not a high quality resampling will be used during the
343 /// resize. (Otherwise, just uses fast nearest-neighbor sampling)
344 ///
345 /// @return Whether or not the operation succeeded. This operation is only valid if both formats
346 /// are BitmapFormat::BGRA8_UNORM_SRGB and the source and destination are non-empty.
347 ///
348 virtual bool Resample(RefPtr<Bitmap> destination, bool high_quality) = 0;
349
350 ///
351 /// Convert a BGRA bitmap to RGBA bitmap and vice-versa by swapping the red and blue channels.
352 ///
353 /// @note Only valid if the format is BitmapFormat::BGRA8_UNORM_SRGB
354 ///
355 virtual void SwapRedBlueChannels() = 0;
356
357 ///
358 /// Convert a BGRA bitmap from premultiplied alpha (the default) to straight alpha.
359 ///
360 /// @note Only valid if the format is BitmapFormat::BGRA8_UNORM_SRGB
361 ///
362 virtual void ConvertToStraightAlpha() = 0;
363
364 ///
365 /// Convert a BGRA bitmap from straight alpha to premultiplied alpha.
366 ///
367 /// @note Only valid if the format is BitmapFormat::BGRA8_UNORM_SRGB
368 ///
369 virtual void ConvertToPremultipliedAlpha() = 0;
370
371 protected:
373 virtual ~Bitmap();
374 Bitmap(const Bitmap&);
375 void operator=(const Bitmap&);
376};
377
378template <typename T>
380 public:
381 LockedPixels(const LockedPixels&) = delete;
383 LockedPixels(int) = delete;
384 explicit LockedPixels(T& lockable) : lockable_(lockable), data_(nullptr), size_(0) { lock(); }
385
387 if (lockable_)
388 lockable_->UnlockPixels();
389 }
390
391 ///
392 /// Access the locked pixel data.
393 ///
394 void* data() { return data_; }
395
396 ///
397 /// Access the size of the locked pixel data.
398 ///
399 size_t size() { return size_; }
400
401 explicit operator bool() const { return !!lockable_; }
402
403 LockedPixels(LockedPixels&& other) : lockable_(other.lockable_), data_(other.data_),
404 size_(other.size_) {
405 other.lockable_ = nullptr;
406 other.data_ = nullptr;
407 other.size_ = 0;
408 }
409
411 if (lockable_)
412 lockable_->UnlockPixels();
413 lockable_ = other.lockable_;
414 data_ = other.data_;
415 size_ = other.size_;
416 other.lockable_ = nullptr;
417 other.data_ = nullptr;
418 other.size_ = 0;
419 return *this;
420 }
421
422 private:
423 void lock() {
424 if (lockable_) {
425 data_ = lockable_->LockPixels();
426 size_ = lockable_->size();
427 }
428 }
429
430 T lockable_;
431 void* data_;
432 size_t size_;
433};
434
435
436} // namespace ultralight
#define UExport
Definition Exports.h:25
A thread-safe container for pixel data.
Definition Bitmap.h:82
virtual RefPtr< Buffer > EncodePNG(bool convert_to_rgba=true, bool convert_to_straight_alpha=true) const =0
Encode this Bitmap as a PNG image and store the encoded bytes in a Buffer.
virtual bool owns_pixels() const =0
Whether or not this Bitmap owns the pixel buffer and will destroy it at the end of its lifetime.
static RefPtr< Bitmap > Create()
Create an empty Bitmap.
virtual bool DrawBitmap(IntRect src_rect, IntRect dest_rect, RefPtr< Bitmap > src, bool pad_repeat)=0
Draw another bitmap to this bitmap.
void operator=(const Bitmap &)
virtual uint32_t height() const =0
Get the height in pixels.
virtual bool IsEmpty() const =0
Whether or not this Bitmap is empty (no pixels allocated).
static RefPtr< Bitmap > Create(const Bitmap &bitmap)
Create a bitmap from a deep copy of another Bitmap.
virtual uint32_t row_bytes() const =0
Get the number of bytes between each row of pixels.
Bitmap(const Bitmap &)
virtual void Set(RefPtr< Bitmap > bitmap)=0
Assign another bitmap to this one.
static RefPtr< Bitmap > Create(uint32_t width, uint32_t height, BitmapFormat format)
Create a Bitmap with a certain configuration.
static RefPtr< Bitmap > Create(uint32_t width, uint32_t height, BitmapFormat format, uint32_t row_bytes, const void *pixels, size_t size, void *user_data, DestroyBitmapCallback destruction_callback)
Create a Bitmap that wraps existing pixel data, a user-defined destruction callback will be called wh...
virtual uint32_t width() const =0
Get the width in pixels.
static RefPtr< Bitmap > Create(uint32_t width, uint32_t height, BitmapFormat format, uint32_t alignment)
Create an aligned Bitmap with a certain configuration.
virtual void SwapRedBlueChannels()=0
Convert a BGRA bitmap to RGBA bitmap and vice-versa by swapping the red and blue channels.
virtual void Erase()=0
Erase the Bitmap (set all pixels to 0).
virtual void * LockPixels()=0
Lock the pixel buffer for reading/writing.
virtual bool WritePNG(const char *path, bool convert_to_rgba=true, bool convert_to_straight_alpha=true) const =0
Write this Bitmap out to a PNG image.
virtual IntRect bounds() const =0
Get the bounds as an IntRect.
virtual void ConvertToPremultipliedAlpha()=0
Convert a BGRA bitmap from straight alpha to premultiplied alpha.
virtual void UnlockPixels()=0
Unlock the pixel buffer.
static RefPtr< Bitmap > Create(uint32_t width, uint32_t height, BitmapFormat format, uint32_t row_bytes, const void *pixels, size_t size, bool should_copy=true)
Create a Bitmap with existing pixel data, a copy will be made unless should_copy is false.
virtual uint32_t bpp() const =0
Get the number of bytes per pixel.
virtual LockedPixels< RefPtr< Bitmap > > LockPixelsSafe() const =0
Lock the pixel buffer for reading/writing (safe version, automatically unlocks).
virtual const void * LockPixels() const =0
Lock the pixel buffer for reading/writing.
virtual void UnlockPixels() const =0
Unlock the pixel buffer.
virtual size_t size() const =0
Get the size in bytes of the pixel buffer.
virtual bool Resample(RefPtr< Bitmap > destination, bool high_quality)=0
Make a resized copy of this bitmap by writing to a pre-allocated destination bitmap.
virtual void ConvertToStraightAlpha()=0
Convert a BGRA bitmap from premultiplied alpha (the default) to straight alpha.
virtual BitmapFormat format() const =0
Get the pixel format.
virtual void * raw_pixels()=0
Get the raw pixel buffer.
Forward declaration for the LockedPixels class.
Definition Bitmap.h:379
void * data()
Access the locked pixel data.
Definition Bitmap.h:394
size_t size()
Access the size of the locked pixel data.
Definition Bitmap.h:399
~LockedPixels()
Definition Bitmap.h:386
LockedPixels(const LockedPixels &)=delete
LockedPixels & operator=(LockedPixels &&other)
Definition Bitmap.h:410
LockedPixels & operator=(const LockedPixels &)=delete
LockedPixels(T &lockable)
Definition Bitmap.h:384
LockedPixels(LockedPixels &&other)
Definition Bitmap.h:403
Interface for all ref-counted objects that will be managed using the RefPtr<> smart pointer.
Definition RefPtr.h:47
A nullable smart pointer.
Definition RefPtr.h:79
Definition App.h:14
void(* DestroyBitmapCallback)(void *user_data, void *data)
Function signature for a user-defined destruction callback to be optionally called when the Bitmap is...
Definition Bitmap.h:59
BitmapFormat
The various Bitmap formats.
Definition Bitmap.h:19
@ A8_UNORM
Alpha channel only, 8-bits per pixel.
@ BGRA8_UNORM_SRGB
Blue Green Red Alpha channels, 32-bits per pixel.
Integer Rectangle Helper.
Definition Geometry.h:529