/* * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include //! This function extracts a value for a specific bit per pixel depth from an image buffer //! at a specific x y position. //! @note inlined to support performance requirements of iterating over every pixel in an image //! @param buffer pointer to a buffer containing pixel image data //! @param x the x coordinates for the pixel to retrieve //! @param y the y coordinates for the pixel to retrieve //! @param width provides the image width //! @param row_stride_bytes the byte-aligned width in bytes //! @param bitdepth bits per pixel for the image (1,2,4 or 8 supported) //! @return The value from the image buffer at the specified coordinates static ALWAYS_INLINE uint8_t raw_image_get_value_for_bitdepth(const uint8_t *raw_image_buffer, uint32_t x, uint32_t y, uint16_t row_stride_bytes, uint8_t bitdepth) { // Retrieve the byte from the image buffer containing the requested pixel uint32_t pixel_in_byte = raw_image_buffer[y * row_stride_bytes + (x * bitdepth / 8)]; // Find the index of the pixel in terms of coordinates and aligned_width uint32_t pixel_index = y * (row_stride_bytes * 8 / bitdepth) + x; // Shift and mask the requested pixel data from the byte containing it and return return (uint8_t)((pixel_in_byte >> ((((8 / bitdepth) - 1) - (pixel_index % (8 / bitdepth))) * bitdepth)) & ~(~0 << bitdepth)); } //! This function sets a pixel value for a specific bits-per-pixel depth in an image buffer //! at a specific (x, y) coordinate. //! @note inlined to support performance requirements of iterating over every pixel in an image //! @param raw_image_buffer Pointer to a buffer containing image pixel data //! @param x The x coordinate for the pixel to retrieve //! @param y The y coordinate for the pixel to retrieve //! @param row_stride_bytes The byte-aligned width of each row in bytes //! @param bitdepth The bits-per-pixel for the image (Only 1, 2, 4 or 8 bitdepths are supported) //! @param value The pixel value to set in the image buffer at the specified (x, y) coordinates static ALWAYS_INLINE void raw_image_set_value_for_bitdepth(uint8_t *raw_image_buffer, uint32_t x, uint32_t y, uint16_t row_stride_bytes, uint8_t bitdepth, uint8_t value) { const uint8_t pixels_per_byte = (uint8_t)(8 / bitdepth); // Retrieve the byte from the image buffer containing the requested pixel const uint32_t byte_offset = y * row_stride_bytes + (x * bitdepth / 8); const uint8_t pixel_in_byte = raw_image_buffer[byte_offset]; // Find the index of the pixel in terms of coordinates and aligned_width const uint32_t pixel_index = (y * (row_stride_bytes * pixels_per_byte) + x) % pixels_per_byte; // For example, bitdepth=1 -> bitdepth_mask=0b1, bitdepth=2 -> bitdepth_mask=0b11, etc. const uint8_t bitdepth_mask = (uint8_t)~(~0 << bitdepth); const uint32_t bits_to_shift = (pixels_per_byte - 1 - pixel_index) * bitdepth; const uint8_t value_position_mask = ~(bitdepth_mask << bits_to_shift); const uint8_t value_shifted_to_position = (value & bitdepth_mask) << bits_to_shift; // Finally, update the byte where the pixel is located using the value_mask const uint8_t new_byte_value = (pixel_in_byte & value_position_mask) | value_shifted_to_position; raw_image_buffer[byte_offset] = new_byte_value; }