aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVivek Jadhav <vivek.jadhav@ittiam.com>2024-03-22 18:33:03 +0530
committerDichenZhang1 <140119224+DichenZhang1@users.noreply.github.com>2024-04-05 05:32:25 -0700
commit1cdc2a99c72b82dd60462b2fe004d2238f92149f (patch)
tree5f3894444c0727417577d66f254ceabd90dd87a7
parentbd8f3c8e260ffb1e85f3ebf09124de0cde97692b (diff)
downloadlibultrahdr-1cdc2a99c72b82dd60462b2fe004d2238f92149f.tar.gz
Update easy editing methods for all supported color formats
Test: ./ultrahdr_unit_test Change-Id: Iede30d5ca54722d20a498c3c60d14e987b90ac07
-rw-r--r--lib/include/ultrahdr/editorhelper.h89
-rw-r--r--lib/include/ultrahdr/ultrahdrcommon.h9
-rw-r--r--lib/src/editorhelper.cpp506
-rw-r--r--lib/src/ultrahdr_api.cpp168
-rw-r--r--tests/editorhelper_test.cpp726
5 files changed, 727 insertions, 771 deletions
diff --git a/lib/include/ultrahdr/editorhelper.h b/lib/include/ultrahdr/editorhelper.h
index 1dd904a..3a82e0e 100644
--- a/lib/include/ultrahdr/editorhelper.h
+++ b/lib/include/ultrahdr/editorhelper.h
@@ -17,27 +17,86 @@
#ifndef ULTRAHDR_EDITORHELPER_H
#define ULTRAHDR_EDITORHELPER_H
-#include "ultrahdr/ultrahdr.h"
-#include "ultrahdr/jpegr.h"
+#include "ultrahdr_api.h"
+#include "ultrahdr/ultrahdrcommon.h"
+
+// todo: move this to ultrahdr_api.h
+/*!\brief List of supported mirror directions */
+typedef enum uhdr_mirror_direction {
+ UHDR_MIRROR_VERTICAL, /**< flip image over x axis */
+ UHDR_MIRROR_HORIZONTAL, /**< flip image over y axis */
+} uhdr_mirror_direction_t; /**< alias for enum uhdr_mirror_direction */
namespace ultrahdr {
-typedef enum {
- ULTRAHDR_MIRROR_VERTICAL,
- ULTRAHDR_MIRROR_HORIZONTAL,
-} ultrahdr_mirroring_direction;
-status_t crop(jr_uncompressed_ptr const in_img,
- int left, int right, int top, int bottom, jr_uncompressed_ptr out_img);
+/*!\brief uhdr image effect descriptor */
+typedef struct uhdr_effect_desc {
+ virtual std::string to_string() = 0;
+
+ virtual ~uhdr_effect_desc() = default;
+} uhdr_effect_desc_t; /**< alias for struct uhdr_effect_desc */
+
+/*!\brief mirror effect descriptor */
+typedef struct uhdr_mirror_effect : uhdr_effect_desc {
+ uhdr_mirror_effect(uhdr_mirror_direction_t direction) : m_direction{direction} {}
+
+ std::string to_string() {
+ return "effect : mirror, metadata : direction - " + ((m_direction == UHDR_MIRROR_HORIZONTAL)
+ ? std::string{"horizontal"}
+ : std::string{"vertical"});
+ }
+
+ uhdr_mirror_direction_t m_direction;
+} uhdr_mirror_effect_t; /**< alias for struct uhdr_mirror_effect */
+
+/*!\brief rotate effect descriptor */
+typedef struct uhdr_rotate_effect : uhdr_effect_desc {
+ uhdr_rotate_effect(int degree) : m_degree{degree} {}
+
+ std::string to_string() {
+ return "effect : rotate, metadata : degree - " + std::to_string(m_degree);
+ }
+
+ int m_degree;
+} uhdr_rotate_effect_t; /**< alias for struct uhdr_rotate_effect */
+
+/*!\brief crop effect descriptor */
+typedef struct uhdr_crop_effect : uhdr_effect_desc {
+ uhdr_crop_effect(int left, int right, int top, int bottom)
+ : m_left{left}, m_right{right}, m_top{top}, m_bottom{bottom} {}
+
+ std::string to_string() {
+ return "effect : crop, metadata : left, right, top, bottom - " + std::to_string(m_left) + " ," +
+ std::to_string(m_right) + " ," + std::to_string(m_top) + " ," + std::to_string(m_bottom);
+ }
+
+ int m_left;
+ int m_right;
+ int m_top;
+ int m_bottom;
+} uhdr_crop_effect_t; /**< alias for struct uhdr_crop_effect */
+
+/*!\brief resize effect descriptor */
+typedef struct uhdr_resize_effect : uhdr_effect_desc {
+ uhdr_resize_effect(int width, int height) : m_width{width}, m_height{height} {}
+
+ std::string to_string() {
+ return "effect : resize, metadata : dimensions w, h" + std::to_string(m_width) + " ," +
+ std::to_string(m_height);
+ }
+
+ int m_width;
+ int m_height;
+} uhdr_resize_effect_t; /**< alias for struct uhdr_resize_effect */
+
+std::unique_ptr<uhdr_raw_image_ext_t> apply_rotate(uhdr_raw_image_t* src, int degree);
-status_t mirror(jr_uncompressed_ptr const in_img,
- ultrahdr_mirroring_direction mirror_dir,
- jr_uncompressed_ptr out_img);
+std::unique_ptr<uhdr_raw_image_ext_t> apply_mirror(uhdr_raw_image_t* src,
+ uhdr_mirror_direction_t direction);
-status_t rotate(jr_uncompressed_ptr const in_img, int clockwise_degree,
- jr_uncompressed_ptr out_img);
+std::unique_ptr<uhdr_raw_image_ext_t> apply_resize(uhdr_raw_image* src, int dst_w, int dst_h);
-status_t resize(jr_uncompressed_ptr const in_img, int out_width, int out_height,
- jr_uncompressed_ptr out_img);
+void apply_crop(uhdr_raw_image_t* src, int left, int top, int wd, int ht);
} // namespace ultrahdr
diff --git a/lib/include/ultrahdr/ultrahdrcommon.h b/lib/include/ultrahdr/ultrahdrcommon.h
index 1ab512a..8bc6d2e 100644
--- a/lib/include/ultrahdr/ultrahdrcommon.h
+++ b/lib/include/ultrahdr/ultrahdrcommon.h
@@ -19,8 +19,10 @@
//#define LOG_NDEBUG 0
+#include <deque>
#include <map>
#include <memory>
+#include <string>
#include <vector>
#include "ultrahdr_api.h"
@@ -103,6 +105,9 @@ typedef struct uhdr_compressed_image_ext : uhdr_compressed_image_t {
std::unique_ptr<ultrahdr::uhdr_memory_block> m_block;
} uhdr_compressed_image_ext_t; /**< alias for struct uhdr_compressed_image_ext */
+/*!\brief forward declaration for image effect descriptor */
+typedef struct uhdr_effect_desc uhdr_effect_desc_t;
+
} // namespace ultrahdr
// ===============================================================================================
@@ -110,7 +115,9 @@ typedef struct uhdr_compressed_image_ext : uhdr_compressed_image_t {
// ===============================================================================================
struct uhdr_codec_private {
- virtual ~uhdr_codec_private() = default;
+ std::deque<ultrahdr::uhdr_effect_desc_t*> m_effects;
+
+ virtual ~uhdr_codec_private();
};
struct uhdr_encoder_private : uhdr_codec_private {
diff --git a/lib/src/editorhelper.cpp b/lib/src/editorhelper.cpp
index cdbd84e..1b33bc3 100644
--- a/lib/src/editorhelper.cpp
+++ b/lib/src/editorhelper.cpp
@@ -14,352 +14,224 @@
* limitations under the License.
*/
-#include <algorithm>
-#include <cmath>
-#include <string.h>
-
-#include <fstream>
-#include <iostream>
+#include <cstring>
+#include <cstdint>
#include "ultrahdr/editorhelper.h"
-using namespace std;
-
namespace ultrahdr {
-status_t crop(jr_uncompressed_ptr const in_img,
- int left, int right, int top, int bottom,
- jr_uncompressed_ptr out_img) {
- if (in_img == nullptr || in_img->data == nullptr ||
- out_img == nullptr || out_img->data == nullptr) {
- return ERROR_JPEGR_BAD_PTR;
- }
- if (left < 0 || right >= in_img->width || top < 0 || bottom >= in_img->height) {
- return ERROR_JPEGR_INVALID_CROPPING_PARAMETERS;
- }
- if (in_img->pixelFormat != ULTRAHDR_PIX_FMT_YUV420 &&
- in_img->pixelFormat != ULTRAHDR_PIX_FMT_MONOCHROME) {
- return ERROR_JPEGR_UNSUPPORTED_FEATURE;
- }
-
- out_img->colorGamut = in_img->colorGamut;
- out_img->pixelFormat = in_img->pixelFormat;
-
- int in_luma_stride = in_img->luma_stride != 0 ? in_img->luma_stride : in_img->width;
- out_img->width = right - left + 1;
- out_img->height = bottom - top + 1;
- out_img->luma_stride = out_img->width;
- uint8_t* src = reinterpret_cast<uint8_t*>(in_img->data) + in_luma_stride * top + left;
- uint8_t* dest = reinterpret_cast<uint8_t*>(out_img->data);
-
- for (int i = 0; i < out_img->height; i++) {
- memcpy(dest + i * out_img->luma_stride, src + i * in_luma_stride, out_img->width);
- }
-
- if (in_img->pixelFormat == ULTRAHDR_PIX_FMT_MONOCHROME) {
- return JPEGR_NO_ERROR;
- }
-
- // Assume input is YUV 420
- int in_chroma_stride = in_img->chroma_stride != 0 ?
- in_img->chroma_stride : (in_luma_stride >> 1);
- out_img->chroma_stride = out_img->luma_stride / 2;
- out_img->chroma_data = reinterpret_cast<uint8_t*>(out_img->data) +
- out_img->luma_stride * out_img->height;
- src = reinterpret_cast<uint8_t*>(in_img->chroma_data);
- if (src == nullptr) {
- src = reinterpret_cast<uint8_t*>(in_img->data) + in_luma_stride * in_img->height;
- }
- src = src + in_chroma_stride * (top / 2) + (left / 2);
- dest = reinterpret_cast<uint8_t*>(out_img->chroma_data);
- for (int i = 0; i < out_img->height; i++) {
- memcpy(dest + i * out_img->chroma_stride, src + i * in_chroma_stride, out_img->width / 2);
- }
-
- return JPEGR_NO_ERROR;
-}
-
-status_t mirror(jr_uncompressed_ptr const in_img,
- ultrahdr_mirroring_direction mirror_dir,
- jr_uncompressed_ptr out_img) {
- if (in_img == nullptr || in_img->data == nullptr ||
- out_img == nullptr || out_img->data == nullptr) {
- return ERROR_JPEGR_BAD_PTR;
- }
- if (in_img->pixelFormat != ULTRAHDR_PIX_FMT_YUV420 &&
- in_img->pixelFormat != ULTRAHDR_PIX_FMT_MONOCHROME) {
- return ERROR_JPEGR_UNSUPPORTED_FEATURE;
- }
- out_img->colorGamut = in_img->colorGamut;
- out_img->pixelFormat = in_img->pixelFormat;
-
- int in_luma_stride = in_img->luma_stride != 0 ? in_img->luma_stride : in_img->width;
- out_img->width = in_img->width;
- out_img->height = in_img->height;
- out_img->luma_stride = in_luma_stride;
- if (mirror_dir == ULTRAHDR_MIRROR_VERTICAL) {
- uint8_t* src = reinterpret_cast<uint8_t*>(in_img->data);
- uint8_t* dest = reinterpret_cast<uint8_t*>(out_img->data);
- for (int i = 0; i < out_img->height; i++) {
- memcpy(dest + (out_img->height - i - 1) * out_img->luma_stride,
- src + i * in_luma_stride,
- out_img->width);
- }
- } else {
- for (int i = 0; i < out_img->height; i++) {
- for (int j = 0; j < out_img->width; j++) {
- *(reinterpret_cast<uint8_t*>(out_img->data) + i * out_img->luma_stride + j) =
- *(reinterpret_cast<uint8_t*>(in_img->data) +
- i * in_luma_stride + (in_img->width - j - 1));
+template <typename T>
+void rotate_buffer_clockwise(T* src_buffer, T* dst_buffer, int src_w, int src_h, int src_stride,
+ int dst_stride, int degree) {
+ if (degree == 90) {
+ int dst_w = src_h;
+ int dst_h = src_w;
+ for (int i = 0; i < dst_h; i++) {
+ for (int j = 0; j < dst_w; j++) {
+ dst_buffer[i * dst_stride + j] = src_buffer[(src_h - j - 1) * src_stride + i];
}
}
- }
-
- if (in_img->pixelFormat == ULTRAHDR_PIX_FMT_MONOCHROME) {
- return JPEGR_NO_ERROR;
- }
-
- // Assume input is YUV 420
- int in_chroma_stride = in_img->chroma_stride != 0 ?
- in_img->chroma_stride : (in_luma_stride >> 1);
- out_img->chroma_stride = out_img->luma_stride / 2;
- out_img->chroma_data = reinterpret_cast<uint8_t*>(out_img->data) +
- out_img->luma_stride * out_img->height;
- if (mirror_dir == ULTRAHDR_MIRROR_VERTICAL) {
- // U
- uint8_t* src = reinterpret_cast<uint8_t*>(in_img->chroma_data);
- if (src == nullptr) {
- src = reinterpret_cast<uint8_t*>(in_img->data) + in_luma_stride * in_img->height;
- }
- uint8_t* dest = reinterpret_cast<uint8_t*>(out_img->chroma_data);
- for (int i = 0; i < out_img->height / 2; i++) {
- memcpy(dest + (out_img->height / 2 - i - 1) * out_img->chroma_stride,
- src + i * in_chroma_stride,
- out_img->width / 2);
- }
- // V
- src = src + in_chroma_stride * (in_img->height / 2);
- dest = dest + out_img->chroma_stride * (out_img->height / 2);
- for (int i = 0; i < out_img->height / 2; i++) {
- memcpy(dest + (out_img->height / 2 - i - 1) * out_img->chroma_stride,
- src + i * in_chroma_stride,
- out_img->width / 2);
- }
- } else {
- // U
- uint8_t* src = reinterpret_cast<uint8_t*>(in_img->chroma_data);
- if (src == nullptr) {
- src = reinterpret_cast<uint8_t*>(in_img->data) + in_luma_stride * in_img->height;
- }
- uint8_t* dest = reinterpret_cast<uint8_t*>(out_img->chroma_data);
- for (int i = 0; i < out_img->height / 2; i++) {
- for (int j = 0; j < out_img->width / 2; j++) {
- *(dest + i * out_img->chroma_stride + j) =
- *(src + i * in_chroma_stride + (in_img->width / 2 - j - 1));
+ } else if (degree == 180) {
+ int dst_w = src_w;
+ int dst_h = src_h;
+ for (int i = 0; i < dst_h; i++) {
+ for (int j = 0; j < dst_w; j++) {
+ dst_buffer[i * dst_stride + j] = src_buffer[(src_h - i - 1) * src_stride + (src_w - j - 1)];
}
}
- // V
- src = src + in_chroma_stride * (in_img->height / 2);
- dest = dest + out_img->chroma_stride * (out_img->height / 2);
- for (int i = 0; i < out_img->height / 2; i++) {
- for (int j = 0; j < out_img->width / 2; j++) {
- *(dest + i * out_img->chroma_stride + j) =
- *(src + i * in_chroma_stride + (in_img->width / 2 - j - 1));
+ } else if (degree == 270) {
+ int dst_w = src_h;
+ int dst_h = src_w;
+ for (int i = 0; i < dst_h; i++) {
+ for (int j = 0; j < dst_w; j++) {
+ dst_buffer[i * dst_stride + j] = src_buffer[j * src_stride + (src_w - i - 1)];
}
}
}
-
- return JPEGR_NO_ERROR;
}
-status_t rotate(jr_uncompressed_ptr const in_img, int clockwise_degree,
- jr_uncompressed_ptr out_img) {
- if (in_img == nullptr || in_img->data == nullptr ||
- out_img == nullptr || out_img->data == nullptr) {
- return ERROR_JPEGR_BAD_PTR;
- }
- if (clockwise_degree != 90 && clockwise_degree != 180 && clockwise_degree != 270) {
- return ERROR_JPEGR_INVALID_CROPPING_PARAMETERS;
- }
- if (in_img->pixelFormat != ULTRAHDR_PIX_FMT_YUV420 &&
- in_img->pixelFormat != ULTRAHDR_PIX_FMT_MONOCHROME) {
- return ERROR_JPEGR_UNSUPPORTED_FEATURE;
- }
-
- out_img->colorGamut = in_img->colorGamut;
- out_img->pixelFormat = in_img->pixelFormat;
-
- int in_luma_stride = in_img->luma_stride != 0 ? in_img->luma_stride : in_img->width;
- if (clockwise_degree == 90) {
- out_img->width = in_img->height;
- out_img->height = in_img->width;
- out_img->luma_stride = out_img->width;
- for (int i = 0; i < out_img->height; i++) {
- for (int j = 0; j < out_img->width; j++) {
- *(reinterpret_cast<uint8_t*>(out_img->data) + i * out_img->luma_stride + j) =
- *(reinterpret_cast<uint8_t*>(in_img->data) +
- (in_img->height - j - 1) * in_luma_stride + i);
- }
- }
- } else if (clockwise_degree == 180) {
- out_img->width = in_img->width;
- out_img->height = in_img->height;
- out_img->luma_stride = in_luma_stride;
- for (int i = 0; i < out_img->height; i++) {
- for (int j = 0; j < out_img->width; j++) {
- *(reinterpret_cast<uint8_t*>(out_img->data) + i * out_img->luma_stride + j) =
- *(reinterpret_cast<uint8_t*>(in_img->data) +
- (in_img->height - i - 1) * in_luma_stride + (in_img->width - j - 1));
- }
- }
- } else if (clockwise_degree == 270) {
- out_img->width = in_img->height;
- out_img->height = in_img->width;
- out_img->luma_stride = out_img->width;
- for (int i = 0; i < out_img->height; i++) {
- for (int j = 0; j < out_img->width; j++) {
- *(reinterpret_cast<uint8_t*>(out_img->data) + i * out_img->luma_stride + j) =
- *(reinterpret_cast<uint8_t*>(in_img->data) +
- j * in_luma_stride + (in_img->width - i - 1));
+template <typename T>
+void mirror_buffer(T* src_buffer, T* dst_buffer, int src_w, int src_h, int src_stride,
+ int dst_stride, uhdr_mirror_direction_t direction) {
+ if (direction == UHDR_MIRROR_VERTICAL) {
+ for (int i = 0; i < src_h; i++) {
+ memcpy(&dst_buffer[(src_h - i - 1) * dst_stride], &src_buffer[i * src_stride],
+ src_w * sizeof(T));
+ }
+ } else if (direction == UHDR_MIRROR_HORIZONTAL) {
+ for (int i = 0; i < src_h; i++) {
+ for (int j = 0; j < src_w; j++) {
+ dst_buffer[i * dst_stride + j] = src_buffer[i * src_stride + (src_w - j - 1)];
}
}
}
+}
- if (in_img->pixelFormat == ULTRAHDR_PIX_FMT_MONOCHROME) {
- return JPEGR_NO_ERROR;
+template <typename T>
+void resize_buffer(T* src_buffer, T* dst_buffer, int src_w, int src_h, int dst_w, int dst_h,
+ int src_stride, int dst_stride) {
+ for (int i = 0; i < dst_h; i++) {
+ for (int j = 0; j < dst_w; j++) {
+ dst_buffer[i * dst_stride + j] =
+ src_buffer[i * (src_h / dst_h) * src_stride + j * (src_w / dst_w)];
+ }
}
+}
- // Assume input is YUV 420
- int in_chroma_stride = in_img->chroma_stride != 0 ?
- in_img->chroma_stride : (in_luma_stride >> 1);
- out_img->chroma_stride = out_img->luma_stride / 2;
- out_img->chroma_data = reinterpret_cast<uint8_t*>(out_img->data) +
- out_img->luma_stride * out_img->height;
- if (clockwise_degree == 90) {
- // U
- uint8_t* src = reinterpret_cast<uint8_t*>(in_img->chroma_data);
- if (src == nullptr) {
- src = reinterpret_cast<uint8_t*>(in_img->data) + in_luma_stride * in_img->height;
- }
- uint8_t* dest = reinterpret_cast<uint8_t*>(out_img->chroma_data);
- for (int i = 0; i < out_img->height / 2; i++) {
- for (int j = 0; j < out_img->width / 2; j++) {
- *(dest + i * out_img->chroma_stride + j) =
- *(src + (in_img->height / 2 - j - 1) * in_chroma_stride + i);
- }
- }
- // V
- src = src + in_chroma_stride * (in_img->height / 2);
- dest = dest + out_img->chroma_stride * (out_img->height / 2);
- for (int i = 0; i < out_img->height / 2; i++) {
- for (int j = 0; j < out_img->width / 2; j++) {
- *(dest + i * out_img->chroma_stride + j) =
- *(src + (in_img->height / 2 - j - 1) * in_chroma_stride + i);
- }
- }
- } else if (clockwise_degree == 180) {
- // U
- uint8_t* src = reinterpret_cast<uint8_t*>(in_img->chroma_data);
- if (src == nullptr) {
- src = reinterpret_cast<uint8_t*>(in_img->data) + in_luma_stride * in_img->height;
- }
- uint8_t* dest = reinterpret_cast<uint8_t*>(out_img->chroma_data);
- for (int i = 0; i < out_img->height / 2; i++) {
- for (int j = 0; j < out_img->width / 2; j++) {
- *(dest + i * out_img->chroma_stride + j) =
- *(src + (in_img->height / 2 - i - 1) * in_chroma_stride +
- (in_img->width / 2 - j - 1));
- }
- }
- // V
- src = src + in_chroma_stride * (in_img->height / 2);
- dest = dest + out_img->chroma_stride * (out_img->height / 2);
- for (int i = 0; i < out_img->height / 2; i++) {
- for (int j = 0; j < out_img->width / 2; j++) {
- *(dest + i * out_img->chroma_stride + j) =
- *(src + (in_img->height / 2 - i - 1) * in_chroma_stride +
- (in_img->width / 2 - j - 1));
- }
- }
- } else if (clockwise_degree == 270) {
- // U
- uint8_t* src = reinterpret_cast<uint8_t*>(in_img->chroma_data);
- if (src == nullptr) {
- src = reinterpret_cast<uint8_t*>(in_img->data) + in_luma_stride * in_img->height;
- }
- uint8_t* dest = reinterpret_cast<uint8_t*>(out_img->chroma_data);
- for (int i = 0; i < out_img->height / 2; i++) {
- for (int j = 0; j < out_img->width / 2; j++) {
- *(dest + i * out_img->chroma_stride + j) =
- *(src + j * in_chroma_stride + (in_img->width / 2 - i - 1));
+std::unique_ptr<uhdr_raw_image_ext_t> apply_rotate(uhdr_raw_image_t* src, int degree) {
+ std::unique_ptr<uhdr_raw_image_ext_t> dst;
+
+ if (degree == 90 || degree == 270) {
+ dst = std::make_unique<uhdr_raw_image_ext_t>(src->fmt, src->cg, src->ct, src->range, src->h,
+ src->w, 1);
+ } else if (degree == 180) {
+ dst = std::make_unique<uhdr_raw_image_ext_t>(src->fmt, src->cg, src->ct, src->range, src->w,
+ src->h, 1);
+ } else {
+ return nullptr;
+ }
+
+ if (src->fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
+ uint16_t* src_buffer = static_cast<uint16_t*>(src->planes[UHDR_PLANE_Y]);
+ uint16_t* dst_buffer = static_cast<uint16_t*>(dst->planes[UHDR_PLANE_Y]);
+ rotate_buffer_clockwise(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_Y],
+ dst->stride[UHDR_PLANE_Y], degree);
+ uint32_t* src_uv_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_UV]);
+ uint32_t* dst_uv_buffer = static_cast<uint32_t*>(dst->planes[UHDR_PLANE_UV]);
+ rotate_buffer_clockwise(src_uv_buffer, dst_uv_buffer, src->w / 2, src->h / 2,
+ src->stride[UHDR_PLANE_UV] / 2, dst->stride[UHDR_PLANE_UV] / 2, degree);
+ } else if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420 || src->fmt == UHDR_IMG_FMT_8bppYCbCr400) {
+ uint8_t* src_buffer = static_cast<uint8_t*>(src->planes[UHDR_PLANE_Y]);
+ uint8_t* dst_buffer = static_cast<uint8_t*>(dst->planes[UHDR_PLANE_Y]);
+ rotate_buffer_clockwise(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_Y],
+ dst->stride[UHDR_PLANE_Y], degree);
+ if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420) {
+ for (int i = 1; i < 3; i++) {
+ src_buffer = static_cast<uint8_t*>(src->planes[i]);
+ dst_buffer = static_cast<uint8_t*>(dst->planes[i]);
+ rotate_buffer_clockwise(src_buffer, dst_buffer, src->w / 2, src->h / 2, src->stride[i],
+ dst->stride[i], degree);
}
}
- // V
- src = src + in_chroma_stride * (in_img->height / 2);
- dest = dest + out_img->chroma_stride * (out_img->height / 2);
- for (int i = 0; i < out_img->height / 2; i++) {
- for (int j = 0; j < out_img->width / 2; j++) {
- *(dest + i * out_img->chroma_stride + j) =
- *(src + j * in_chroma_stride + (in_img->width / 2 - i - 1));
+ } else if (src->fmt == UHDR_IMG_FMT_32bppRGBA1010102 || src->fmt == UHDR_IMG_FMT_32bppRGBA8888) {
+ uint32_t* src_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_PACKED]);
+ uint32_t* dst_buffer = static_cast<uint32_t*>(dst->planes[UHDR_PLANE_PACKED]);
+ rotate_buffer_clockwise(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_PACKED],
+ dst->stride[UHDR_PLANE_PACKED], degree);
+ } else if (src->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat) {
+ uint64_t* src_buffer = static_cast<uint64_t*>(src->planes[UHDR_PLANE_PACKED]);
+ uint64_t* dst_buffer = static_cast<uint64_t*>(dst->planes[UHDR_PLANE_PACKED]);
+ rotate_buffer_clockwise(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_PACKED],
+ dst->stride[UHDR_PLANE_PACKED], degree);
+ }
+ return std::move(dst);
+}
+
+std::unique_ptr<uhdr_raw_image_ext_t> apply_mirror(uhdr_raw_image_t* src,
+ uhdr_mirror_direction_t direction) {
+ std::unique_ptr<uhdr_raw_image_ext_t> dst = std::make_unique<uhdr_raw_image_ext_t>(
+ src->fmt, src->cg, src->ct, src->range, src->w, src->h, 1);
+
+ if (src->fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
+ uint16_t* src_buffer = static_cast<uint16_t*>(src->planes[UHDR_PLANE_Y]);
+ uint16_t* dst_buffer = static_cast<uint16_t*>(dst->planes[UHDR_PLANE_Y]);
+ mirror_buffer(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_Y],
+ dst->stride[UHDR_PLANE_Y], direction);
+ uint32_t* src_uv_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_UV]);
+ uint32_t* dst_uv_buffer = static_cast<uint32_t*>(dst->planes[UHDR_PLANE_UV]);
+ mirror_buffer(src_uv_buffer, dst_uv_buffer, src->w / 2, src->h / 2,
+ src->stride[UHDR_PLANE_UV] / 2, dst->stride[UHDR_PLANE_UV] / 2, direction);
+ } else if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420 || src->fmt == UHDR_IMG_FMT_8bppYCbCr400) {
+ uint8_t* src_buffer = static_cast<uint8_t*>(src->planes[UHDR_PLANE_Y]);
+ uint8_t* dst_buffer = static_cast<uint8_t*>(dst->planes[UHDR_PLANE_Y]);
+ mirror_buffer(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_Y],
+ dst->stride[UHDR_PLANE_Y], direction);
+ if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420) {
+ for (int i = 1; i < 3; i++) {
+ src_buffer = static_cast<uint8_t*>(src->planes[i]);
+ dst_buffer = static_cast<uint8_t*>(dst->planes[i]);
+ mirror_buffer(src_buffer, dst_buffer, src->w / 2, src->h / 2, src->stride[i],
+ dst->stride[i], direction);
}
}
- }
-
- return JPEGR_NO_ERROR;
+ } else if (src->fmt == UHDR_IMG_FMT_32bppRGBA1010102 || src->fmt == UHDR_IMG_FMT_32bppRGBA8888) {
+ uint32_t* src_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_PACKED]);
+ uint32_t* dst_buffer = static_cast<uint32_t*>(dst->planes[UHDR_PLANE_PACKED]);
+ mirror_buffer(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_PACKED],
+ dst->stride[UHDR_PLANE_PACKED], direction);
+ } else if (src->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat) {
+ uint64_t* src_buffer = static_cast<uint64_t*>(src->planes[UHDR_PLANE_PACKED]);
+ uint64_t* dst_buffer = static_cast<uint64_t*>(dst->planes[UHDR_PLANE_PACKED]);
+ mirror_buffer(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_PACKED],
+ dst->stride[UHDR_PLANE_PACKED], direction);
+ }
+ return std::move(dst);
}
-status_t resize(jr_uncompressed_ptr const in_img, int out_width, int out_height,
- jr_uncompressed_ptr out_img) {
- if (in_img == nullptr || in_img->data == nullptr ||
- out_img == nullptr || out_img->data == nullptr) {
- return ERROR_JPEGR_BAD_PTR;
- }
- if (in_img->pixelFormat != ULTRAHDR_PIX_FMT_YUV420 &&
- in_img->pixelFormat != ULTRAHDR_PIX_FMT_MONOCHROME) {
- return ERROR_JPEGR_UNSUPPORTED_FEATURE;
- }
-
- out_img->colorGamut = in_img->colorGamut;
- out_img->pixelFormat = in_img->pixelFormat;
-
- int in_luma_stride = in_img->luma_stride != 0 ? in_img->luma_stride : in_img->width;
- out_img->width = out_width;
- out_img->height = out_height;
- out_img->luma_stride = out_img->width;
-
- for (int i = 0; i < out_img->height; i++) {
- for (int j = 0; j < out_img->width; j++) {
- *(reinterpret_cast<uint8_t*>(out_img->data) + i * out_img->luma_stride + j) =
- *(reinterpret_cast<uint8_t*>(in_img->data) +
- i * in_img->height / out_img->height * in_luma_stride +
- j * in_img->width / out_img->width );
+void apply_crop(uhdr_raw_image_t* src, int left, int top, int wd, int ht) {
+ if (src->fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
+ uint16_t* src_buffer = static_cast<uint16_t*>(src->planes[UHDR_PLANE_Y]);
+ src->planes[UHDR_PLANE_Y] = &src_buffer[top * src->stride[UHDR_PLANE_Y] + left];
+ uint32_t* src_uv_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_UV]);
+ src->planes[UHDR_PLANE_UV] =
+ &src_uv_buffer[(top / 2) * (src->stride[UHDR_PLANE_UV] / 2) + (left / 2)];
+ } else if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420 || src->fmt == UHDR_IMG_FMT_8bppYCbCr400) {
+ uint8_t* src_buffer = static_cast<uint8_t*>(src->planes[UHDR_PLANE_Y]);
+ src->planes[UHDR_PLANE_Y] = &src_buffer[top * src->stride[UHDR_PLANE_Y] + left];
+ if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420) {
+ for (int i = 1; i < 3; i++) {
+ src->planes[i] = &src_buffer[(top / 2) * src->stride[i] + (left / 2)];
+ }
}
+ } else if (src->fmt == UHDR_IMG_FMT_32bppRGBA1010102 || src->fmt == UHDR_IMG_FMT_32bppRGBA8888) {
+ uint32_t* src_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_PACKED]);
+ src->planes[UHDR_PLANE_PACKED] = &src_buffer[top * src->stride[UHDR_PLANE_PACKED] + left];
+ } else if (src->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat) {
+ uint64_t* src_buffer = static_cast<uint64_t*>(src->planes[UHDR_PLANE_PACKED]);
+ src->planes[UHDR_PLANE_PACKED] = &src_buffer[top * src->stride[UHDR_PLANE_PACKED] + left];
}
+ src->w = wd;
+ src->h = ht;
+}
- if (in_img->pixelFormat == ULTRAHDR_PIX_FMT_MONOCHROME) {
- return JPEGR_NO_ERROR;
- }
-
- // Assume input is YUV 420
- int in_chroma_stride = in_img->chroma_stride != 0 ?
- in_img->chroma_stride : (in_luma_stride >> 1);
- out_img->chroma_stride = out_img->luma_stride / 2;
- out_img->chroma_data = reinterpret_cast<uint8_t*>(out_img->data) +
- out_img->luma_stride * out_img->height;
- uint8_t* src = reinterpret_cast<uint8_t*>(in_img->chroma_data);
- if (src == nullptr) {
- src = reinterpret_cast<uint8_t*>(in_img->data) + in_luma_stride * in_img->height;
- }
- uint8_t* dest = reinterpret_cast<uint8_t*>(out_img->chroma_data);
- for (int i = 0; i < out_img->height; i++) {
- for (int j = 0; j < out_img->width / 2; j++) {
- *(dest + i * out_img->chroma_stride + j) =
- *(src + i * in_img->height / out_img->height * in_chroma_stride +
- j * in_img->width / out_img->width );
+std::unique_ptr<uhdr_raw_image_ext_t> apply_resize(uhdr_raw_image_t* src, int dst_w, int dst_h) {
+ std::unique_ptr<uhdr_raw_image_ext_t> dst = std::make_unique<uhdr_raw_image_ext_t>(
+ src->fmt, src->cg, src->ct, src->range, dst_w, dst_h, 1);
+
+ if (src->fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
+ uint16_t* src_buffer = static_cast<uint16_t*>(src->planes[UHDR_PLANE_Y]);
+ uint16_t* dst_buffer = static_cast<uint16_t*>(dst->planes[UHDR_PLANE_Y]);
+ resize_buffer(src_buffer, dst_buffer, src->w, src->h, dst->w, dst->h, src->stride[UHDR_PLANE_Y],
+ dst->stride[UHDR_PLANE_Y]);
+ uint32_t* src_uv_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_UV]);
+ uint32_t* dst_uv_buffer = static_cast<uint32_t*>(dst->planes[UHDR_PLANE_UV]);
+ resize_buffer(src_uv_buffer, dst_uv_buffer, src->w / 4, src->h / 2, dst->w / 4, dst->h / 2,
+ src->stride[UHDR_PLANE_UV] / 2, dst->stride[UHDR_PLANE_UV] / 2);
+ } else if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420 || src->fmt == UHDR_IMG_FMT_8bppYCbCr400) {
+ uint8_t* src_buffer = static_cast<uint8_t*>(src->planes[UHDR_PLANE_Y]);
+ uint8_t* dst_buffer = static_cast<uint8_t*>(dst->planes[UHDR_PLANE_Y]);
+ resize_buffer(src_buffer, dst_buffer, src->w, src->h, dst->w, dst->h, src->stride[UHDR_PLANE_Y],
+ dst->stride[UHDR_PLANE_Y]);
+ if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420) {
+ for (int i = 1; i < 3; i++) {
+ src_buffer = static_cast<uint8_t*>(src->planes[i]);
+ dst_buffer = static_cast<uint8_t*>(dst->planes[i]);
+ resize_buffer(src_buffer, dst_buffer, src->w / 2, src->h / 2, dst->w / 2, dst->h / 2,
+ src->stride[i], dst->stride[i]);
+ }
}
- }
-
- return JPEGR_NO_ERROR;
+ } else if (src->fmt == UHDR_IMG_FMT_32bppRGBA1010102 || src->fmt == UHDR_IMG_FMT_32bppRGBA8888) {
+ uint32_t* src_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_PACKED]);
+ uint32_t* dst_buffer = static_cast<uint32_t*>(dst->planes[UHDR_PLANE_PACKED]);
+ resize_buffer(src_buffer, dst_buffer, src->w, src->h, dst->w, dst->h,
+ src->stride[UHDR_PLANE_PACKED], dst->stride[UHDR_PLANE_PACKED]);
+ } else if (src->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat) {
+ uint64_t* src_buffer = static_cast<uint64_t*>(src->planes[UHDR_PLANE_PACKED]);
+ uint64_t* dst_buffer = static_cast<uint64_t*>(dst->planes[UHDR_PLANE_PACKED]);
+ resize_buffer(src_buffer, dst_buffer, src->w, src->h, dst->w, dst->h,
+ src->stride[UHDR_PLANE_PACKED], dst->stride[UHDR_PLANE_PACKED]);
+ }
+ return std::move(dst);
}
-
} // namespace ultrahdr
diff --git a/lib/src/ultrahdr_api.cpp b/lib/src/ultrahdr_api.cpp
index 7d0f7f9..17280f2 100644
--- a/lib/src/ultrahdr_api.cpp
+++ b/lib/src/ultrahdr_api.cpp
@@ -19,6 +19,7 @@
#include "ultrahdr_api.h"
#include "ultrahdr/ultrahdrcommon.h"
+#include "ultrahdr/editorhelper.h"
#include "ultrahdr/jpegr.h"
#include "ultrahdr/jpegrutils.h"
@@ -102,8 +103,81 @@ uhdr_compressed_image_ext::uhdr_compressed_image_ext(uhdr_color_gamut_t cg,
this->range = range;
}
+uhdr_error_info_t apply_effects(uhdr_decoder_private* dec) {
+ for (auto& it : dec->m_effects) {
+ std::unique_ptr<ultrahdr::uhdr_raw_image_ext_t> disp_img = nullptr;
+ std::unique_ptr<ultrahdr::uhdr_raw_image_ext_t> gm_img = nullptr;
+
+ if (nullptr != dynamic_cast<uhdr_rotate_effect_t*>(it)) {
+ int degree = (dynamic_cast<ultrahdr::uhdr_rotate_effect_t*>(it))->m_degree;
+ disp_img = apply_rotate(dec->m_decoded_img_buffer.get(), degree);
+ gm_img = apply_rotate(dec->m_gainmap_img_buffer.get(), degree);
+ } else if (nullptr != dynamic_cast<uhdr_mirror_effect_t*>(it)) {
+ uhdr_mirror_direction_t direction = (dynamic_cast<uhdr_mirror_effect_t*>(it))->m_direction;
+ disp_img = apply_mirror(dec->m_decoded_img_buffer.get(), direction);
+ gm_img = apply_mirror(dec->m_gainmap_img_buffer.get(), direction);
+ } else if (nullptr != dynamic_cast<uhdr_crop_effect_t*>(it)) {
+ auto crop_effect = dynamic_cast<uhdr_crop_effect_t*>(it);
+ uhdr_raw_image_t* disp = dec->m_decoded_img_buffer.get();
+ uhdr_raw_image_t* gm = dec->m_gainmap_img_buffer.get();
+ int left = (std::max)(0, crop_effect->m_left);
+ int right = (std::min)((int)disp->w, crop_effect->m_right);
+ int top = (std::max)(0, crop_effect->m_top);
+ int bottom = (std::min)((int)disp->h, crop_effect->m_bottom);
+ int scale_factor = disp->w / gm->w;
+
+ if (right - left <= scale_factor || bottom - top <= scale_factor) {
+ uhdr_error_info_t status;
+ status.error_code = UHDR_CODEC_UNKNOWN_ERROR;
+ status.has_detail = 1;
+ snprintf(status.detail, sizeof status.detail,
+ "After crop image dimensions are <= 0, display image dimensions %dx%d, gain map "
+ "image dimensions %dx%d",
+ right - left, bottom - top, (right - left) / scale_factor,
+ (bottom - top) / scale_factor);
+ return status;
+ }
+ apply_crop(disp, left, top, right - left, bottom - top);
+ apply_crop(gm, left / scale_factor, top / scale_factor, (right - left) / scale_factor,
+ (bottom - top) / scale_factor);
+ continue;
+ } else if (nullptr != dynamic_cast<uhdr_resize_effect_t*>(it)) {
+ auto resize_effect = dynamic_cast<uhdr_resize_effect_t*>(it);
+ int dst_w = resize_effect->m_width;
+ int dst_h = resize_effect->m_height;
+ if (dst_w == 0 || dst_h == 0) {
+ uhdr_error_info_t status;
+ status.error_code = UHDR_CODEC_INVALID_PARAM;
+ snprintf(status.detail, sizeof status.detail,
+ "destination width or destination height cannot be zero");
+ return status;
+ }
+ disp_img = apply_resize(dec->m_decoded_img_buffer.get(), dst_w, dst_h);
+ gm_img = apply_resize(dec->m_gainmap_img_buffer.get(), dst_w, dst_h);
+ }
+
+ if (disp_img == nullptr || gm_img == nullptr) {
+ uhdr_error_info_t status;
+ status.error_code = UHDR_CODEC_UNKNOWN_ERROR;
+ status.has_detail = 1;
+ snprintf(status.detail, sizeof status.detail,
+ "encountered unknown error while applying effect %s", it->to_string().c_str());
+ return status;
+ }
+ dec->m_decoded_img_buffer = std::move(disp_img);
+ dec->m_gainmap_img_buffer = std::move(gm_img);
+ }
+
+ return g_no_error;
+}
+
} // namespace ultrahdr
+uhdr_codec_private::~uhdr_codec_private() {
+ for (auto it : m_effects) delete it;
+ m_effects.clear();
+}
+
ultrahdr::ultrahdr_pixel_format map_pix_fmt_to_internal_pix_fmt(uhdr_img_fmt_t fmt) {
switch (fmt) {
case UHDR_IMG_FMT_12bppYCbCr420:
@@ -682,6 +756,13 @@ uhdr_error_info_t uhdr_encode(uhdr_codec_private_t* enc) {
uhdr_error_info_t& status = handle->m_encode_call_status;
+ if (handle->m_effects.size() != 0) {
+ status.error_code = UHDR_CODEC_INVALID_PARAM;
+ status.has_detail = 1;
+ snprintf(status.detail, sizeof status.detail, "image effects are not currently enabled");
+ return status;
+ }
+
ultrahdr::status_t internal_status = ultrahdr::JPEGR_NO_ERROR;
if (handle->m_output_format == UHDR_CODEC_JPG) {
ultrahdr::jpegr_exif_struct exif{};
@@ -836,6 +917,8 @@ void uhdr_reset_encoder(uhdr_codec_private_t* enc) {
uhdr_encoder_private* handle = dynamic_cast<uhdr_encoder_private*>(enc);
// clear entries and restore defaults
+ for (auto it : handle->m_effects) delete it;
+ handle->m_effects.clear();
handle->m_raw_images.clear();
handle->m_compressed_images.clear();
handle->m_quality.clear();
@@ -1249,6 +1332,10 @@ uhdr_error_info_t uhdr_decode(uhdr_codec_private_t* dec) {
handle->m_decoded_img_buffer->cg = map_internal_cg_to_cg(dest.colorGamut);
}
+ if (status.error_code == UHDR_CODEC_OK && dec->m_effects.size() != 0) {
+ status = ultrahdr::apply_effects(handle);
+ }
+
return status;
}
@@ -1283,6 +1370,8 @@ void uhdr_reset_decoder(uhdr_codec_private_t* dec) {
uhdr_decoder_private* handle = dynamic_cast<uhdr_decoder_private*>(dec);
// clear entries and restore defaults
+ for (auto it : handle->m_effects) delete it;
+ handle->m_effects.clear();
handle->m_uhdr_compressed_img.reset();
handle->m_output_fmt = UHDR_IMG_FMT_64bppRGBAHalfFloat;
handle->m_output_ct = UHDR_CT_LINEAR;
@@ -1308,3 +1397,82 @@ void uhdr_reset_decoder(uhdr_codec_private_t* dec) {
handle->m_decode_call_status = g_no_error;
}
}
+
+uhdr_error_info_t uhdr_add_effect_mirror(uhdr_codec_private_t* codec,
+ uhdr_mirror_direction_t direction) {
+ uhdr_error_info_t status = g_no_error;
+
+ if (codec == nullptr) {
+ status.error_code = UHDR_CODEC_INVALID_PARAM;
+ status.has_detail = 1;
+ snprintf(status.detail, sizeof status.detail, "received nullptr for uhdr codec instance");
+ return status;
+ }
+
+ if (direction != UHDR_MIRROR_HORIZONTAL && direction != UHDR_MIRROR_VERTICAL) {
+ status.error_code = UHDR_CODEC_INVALID_PARAM;
+ status.has_detail = 1;
+ snprintf(
+ status.detail, sizeof status.detail,
+ "unsupported direction, expects one of {UHDR_MIRROR_HORIZONTAL, UHDR_MIRROR_VERTICAL}");
+ return status;
+ }
+
+ codec->m_effects.push_back(new ultrahdr::uhdr_mirror_effect_t(direction));
+
+ return status;
+}
+
+uhdr_error_info_t uhdr_add_effect_rotate(uhdr_codec_private_t* codec, int degrees) {
+ uhdr_error_info_t status = g_no_error;
+
+ if (codec == nullptr) {
+ status.error_code = UHDR_CODEC_INVALID_PARAM;
+ status.has_detail = 1;
+ snprintf(status.detail, sizeof status.detail, "received nullptr for uhdr codec instance");
+ return status;
+ }
+
+ if (degrees != 90 && degrees != 180 && degrees != 270) {
+ status.error_code = UHDR_CODEC_INVALID_PARAM;
+ status.has_detail = 1;
+ snprintf(status.detail, sizeof status.detail,
+ "unsupported degrees, expects one of {90, 180, 270}");
+ return status;
+ }
+
+ codec->m_effects.push_back(new ultrahdr::uhdr_rotate_effect_t(degrees));
+
+ return status;
+}
+
+uhdr_error_info_t uhdr_add_effect_crop(uhdr_codec_private_t* codec, int left, int right, int top,
+ int bottom) {
+ uhdr_error_info_t status = g_no_error;
+
+ if (codec == nullptr) {
+ status.error_code = UHDR_CODEC_INVALID_PARAM;
+ status.has_detail = 1;
+ snprintf(status.detail, sizeof status.detail, "received nullptr for uhdr codec instance");
+ return status;
+ }
+
+ codec->m_effects.push_back(new ultrahdr::uhdr_crop_effect_t(left, right, top, bottom));
+
+ return status;
+}
+
+uhdr_error_info_t uhdr_add_effect_resize(uhdr_codec_private_t* codec, int width, int height) {
+ uhdr_error_info_t status = g_no_error;
+
+ if (codec == nullptr) {
+ status.error_code = UHDR_CODEC_INVALID_PARAM;
+ status.has_detail = 1;
+ snprintf(status.detail, sizeof status.detail, "received nullptr for uhdr codec instance");
+ return status;
+ }
+
+ codec->m_effects.push_back(new ultrahdr::uhdr_resize_effect_t(width, height));
+
+ return status;
+}
diff --git a/tests/editorhelper_test.cpp b/tests/editorhelper_test.cpp
index 7994ef4..d08ea7c 100644
--- a/tests/editorhelper_test.cpp
+++ b/tests/editorhelper_test.cpp
@@ -20,15 +20,71 @@
#include <iostream>
#include "ultrahdr/editorhelper.h"
-#include "ultrahdr/jpegr.h"
-//#define DUMP_OUTPUT
+// #define DUMP_OUTPUT
+
+#define OUTPUT_P010_IMAGE "output.p010"
+#define OUTPUT_YUV_IMAGE "output.yuv"
+#define OUTPUT_RGBA_IMAGE "output.rgb"
#ifdef DUMP_OUTPUT
-static bool writeFile(const char* filename, void*& result, int length) {
+static bool writeFile(std::string prefixName, uhdr_raw_image_t* img) {
+ char filename[50];
+
+ if (img->fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
+ snprintf(filename, sizeof filename, "%s_%d_%s", prefixName.c_str(), img->fmt,
+ OUTPUT_P010_IMAGE);
+ } else if (img->fmt == UHDR_IMG_FMT_12bppYCbCr420 || img->fmt == UHDR_IMG_FMT_8bppYCbCr400) {
+ snprintf(filename, sizeof filename, "%s_%d_%s", prefixName.c_str(), img->fmt, OUTPUT_YUV_IMAGE);
+ } else if (img->fmt == UHDR_IMG_FMT_32bppRGBA1010102 || img->fmt == UHDR_IMG_FMT_32bppRGBA8888 ||
+ img->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat) {
+ snprintf(filename, sizeof filename, "%s_%d_%s", prefixName.c_str(), img->fmt,
+ OUTPUT_RGBA_IMAGE);
+ } else {
+ return false;
+ }
+
std::ofstream ofd(filename, std::ios::binary);
if (ofd.is_open()) {
- ofd.write(static_cast<char*>(result), length);
+ int bpp = 1;
+
+ if (img->fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
+ bpp = 2;
+ } else if (img->fmt == UHDR_IMG_FMT_32bppRGBA8888 ||
+ img->fmt == UHDR_IMG_FMT_32bppRGBA1010102) {
+ bpp = 4;
+ } else if (img->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat) {
+ bpp = 8;
+ }
+
+ const char* data = static_cast<char*>(img->planes[UHDR_PLANE_Y]);
+ size_t stride = img->stride[UHDR_PLANE_Y] * bpp;
+ size_t length = img->w * bpp;
+ for (int i = 0; i < img->h; i++, data += stride) {
+ ofd.write(data, length);
+ }
+
+ if (img->fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
+ data = static_cast<char*>(img->planes[UHDR_PLANE_UV]);
+ size_t stride = img->stride[UHDR_PLANE_UV] * bpp;
+ size_t length = img->w * bpp;
+ for (int i = 0; i < img->h / 2; i++, data += stride) {
+ ofd.write(data, length);
+ }
+ } else if (img->fmt == UHDR_IMG_FMT_12bppYCbCr420) {
+ data = static_cast<char*>(img->planes[UHDR_PLANE_U]);
+ size_t stride = img->stride[UHDR_PLANE_U] * bpp;
+ size_t length = (img->w / 2) * bpp;
+ for (int i = 0; i < img->h / 2; i++, data += stride) {
+ ofd.write(data, length);
+ }
+ data = static_cast<char*>(img->planes[UHDR_PLANE_V]);
+ size_t stride = img->stride[UHDR_PLANE_V] * bpp;
+ size_t length = (img->w / 2) * bpp;
+ for (int i = 0; i < img->h / 2; i++, data += stride) {
+ ofd.write(data, length);
+ }
+ }
return true;
}
std::cerr << "unable to write to file : " << filename << std::endl;
@@ -38,477 +94,271 @@ static bool writeFile(const char* filename, void*& result, int length) {
namespace ultrahdr {
-#ifdef __ANDROID__
-#define YUV_IMAGE "/data/local/tmp/minnie-320x240.yu12"
-#define GREY_IMAGE "/data/local/tmp/minnie-320x240.y"
-#else
-#define YUV_IMAGE "./data/minnie-320x240.yu12"
-#define GREY_IMAGE "./data/minnie-320x240.y"
-#endif
-#define IMAGE_WIDTH 320
-#define IMAGE_HEIGHT 240
-
-class EditorHelperTest : public testing::Test {
- public:
- struct Image {
- std::unique_ptr<uint8_t[]> buffer;
- size_t size;
- };
- EditorHelperTest();
- ~EditorHelperTest();
-
- protected:
- virtual void SetUp();
- virtual void TearDown();
-
- Image mYuvImage, mGreyImage;
-};
-
-EditorHelperTest::EditorHelperTest() {}
-
-EditorHelperTest::~EditorHelperTest() {}
-
-static bool loadFile(const char filename[], EditorHelperTest::Image* result) {
- std::ifstream ifd(filename, std::ios::binary | std::ios::ate);
+static bool loadFile(const char* filename, uhdr_raw_image_t* handle) {
+ std::ifstream ifd(filename, std::ios::binary);
if (ifd.good()) {
- int size = ifd.tellg();
- ifd.seekg(0, std::ios::beg);
- result->buffer.reset(new uint8_t[size]);
- ifd.read(reinterpret_cast<char*>(result->buffer.get()), size);
- ifd.close();
- result->size = size;
- return true;
+ if (handle->fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
+ const int bpp = 2;
+ ifd.read(static_cast<char*>(handle->planes[UHDR_PLANE_Y]), handle->w * handle->h * bpp);
+ ifd.read(static_cast<char*>(handle->planes[UHDR_PLANE_UV]),
+ (handle->w / 2) * (handle->h / 2) * bpp * 2);
+ return true;
+ } else if (handle->fmt == UHDR_IMG_FMT_12bppYCbCr420) {
+ ifd.read(static_cast<char*>(handle->planes[UHDR_PLANE_Y]), handle->w * handle->h);
+ ifd.read(static_cast<char*>(handle->planes[UHDR_PLANE_U]), (handle->w / 2) * (handle->h / 2));
+ ifd.read(static_cast<char*>(handle->planes[UHDR_PLANE_V]), (handle->w / 2) * (handle->h / 2));
+ return true;
+ } else if (handle->fmt == UHDR_IMG_FMT_32bppRGBA8888 ||
+ handle->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat ||
+ handle->fmt == UHDR_IMG_FMT_32bppRGBA1010102) {
+ int bpp = handle->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat ? 8 : 4;
+ ifd.read(static_cast<char*>(handle->planes[UHDR_PLANE_PACKED]), handle->w * handle->h * bpp);
+ return true;
+ } else if (handle->fmt == UHDR_IMG_FMT_8bppYCbCr400) {
+ ifd.read(static_cast<char*>(handle->planes[UHDR_PLANE_Y]), handle->w * handle->h);
+ return true;
+ }
+ return false;
}
+ std::cerr << "unable to open file : " << filename << std::endl;
return false;
}
-void EditorHelperTest::SetUp() {
- if (!loadFile(YUV_IMAGE, &mYuvImage)) {
- FAIL() << "Load file " << YUV_IMAGE << " failed";
- }
- if (!loadFile(GREY_IMAGE, &mGreyImage)) {
- FAIL() << "Load file " << GREY_IMAGE << " failed";
+void initImageHandle(uhdr_raw_image_t* handle, int width, int height, uhdr_img_fmt_t format) {
+ handle->fmt = format;
+ handle->cg = UHDR_CG_DISPLAY_P3;
+ handle->ct = UHDR_CT_SRGB;
+ handle->range = UHDR_CR_UNSPECIFIED;
+ handle->w = width;
+ handle->h = height;
+ if (handle->fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
+ handle->planes[UHDR_PLANE_Y] = malloc(width * height * 2);
+ handle->planes[UHDR_PLANE_UV] = malloc((width / 2) * (height / 2) * 2 * 2);
+ handle->planes[UHDR_PLANE_V] = nullptr;
+ handle->stride[UHDR_PLANE_Y] = width;
+ handle->stride[UHDR_PLANE_UV] = width;
+ handle->stride[UHDR_PLANE_V] = 0;
+ } else if (handle->fmt == UHDR_IMG_FMT_12bppYCbCr420) {
+ handle->planes[UHDR_PLANE_Y] = malloc(width * height);
+ handle->planes[UHDR_PLANE_U] = malloc((width / 2) * (height / 2));
+ handle->planes[UHDR_PLANE_V] = malloc((width / 2) * (height / 2));
+ handle->stride[UHDR_PLANE_Y] = width;
+ handle->stride[UHDR_PLANE_U] = width / 2;
+ handle->stride[UHDR_PLANE_V] = width / 2;
+ } else if (handle->fmt == UHDR_IMG_FMT_32bppRGBA8888 ||
+ handle->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat ||
+ handle->fmt == UHDR_IMG_FMT_32bppRGBA1010102) {
+ int bpp = handle->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat ? 8 : 4;
+ handle->planes[UHDR_PLANE_PACKED] = malloc(width * height * bpp);
+ handle->planes[UHDR_PLANE_U] = nullptr;
+ handle->planes[UHDR_PLANE_V] = nullptr;
+ handle->stride[UHDR_PLANE_PACKED] = width;
+ handle->stride[UHDR_PLANE_U] = 0;
+ handle->stride[UHDR_PLANE_V] = 0;
+ } else if (handle->fmt == UHDR_IMG_FMT_8bppYCbCr400) {
+ handle->planes[UHDR_PLANE_Y] = malloc(width * height);
+ handle->planes[UHDR_PLANE_U] = nullptr;
+ handle->planes[UHDR_PLANE_V] = nullptr;
+ handle->stride[UHDR_PLANE_Y] = width;
+ handle->stride[UHDR_PLANE_U] = 0;
+ handle->stride[UHDR_PLANE_V] = 0;
}
}
-void EditorHelperTest::TearDown() {}
-
-TEST_F(EditorHelperTest, croppingYuvImage) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
- const int left = 10;
- const int right = 99;
- const int top = 20;
- const int bottom = 199;
- int out_width = right - left + 1;
- int out_height = bottom - top + 1;
-
- in_img.data = mYuvImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_YUV420;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int outSize = out_width * out_height * 3 / 2;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(crop(&in_img, left, right, top, bottom, &out_img) == JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = out_width);
- EXPECT_TRUE(out_img.height = out_height);
- EXPECT_TRUE(out_img.colorGamut == in_img.colorGamut);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
-#ifdef DUMP_OUTPUT
- if (!writeFile("cropped.yuv", out_img.data, outSize)) {
- std::cerr << "unable to write output file" << std::endl;
- }
-#endif
-}
+void compare_planes(void* ref_plane, void* test_plane, int ref_stride, int test_stride, int width,
+ int height, int bpp) {
+ uint8_t* ref = (uint8_t*)ref_plane;
+ uint8_t* test = (uint8_t*)test_plane;
+ const size_t length = width * bpp;
-TEST_F(EditorHelperTest, croppingGreyImage) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
- const int left = 10;
- const int right = 99;
- const int top = 20;
- const int bottom = 199;
- int out_width = right - left + 1;
- int out_height = bottom - top + 1;
-
- in_img.data = mGreyImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_MONOCHROME;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int outSize = out_width * out_height;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(crop(&in_img, left, right, top, bottom, &out_img)== JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = out_width);
- EXPECT_TRUE(out_img.height = out_height);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
-#ifdef DUMP_OUTPUT
- if (!writeFile("cropped.y", out_img.data, outSize)) {
- std::cerr << "unable to write output file" << std::endl;
+ for (int i = 0; i < height; i++, ref += (ref_stride * bpp), test += (test_stride * bpp)) {
+ ASSERT_EQ(0, memcmp(ref, ref, length));
}
-#endif
-}
-
-TEST_F(EditorHelperTest, mirroringYuvImageVertical) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
-
- in_img.data = mYuvImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_YUV420;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int outSize = IMAGE_WIDTH * IMAGE_HEIGHT * 3 / 2;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(mirror(&in_img, ULTRAHDR_MIRROR_VERTICAL, &out_img)== JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = IMAGE_WIDTH);
- EXPECT_TRUE(out_img.height = IMAGE_HEIGHT);
- EXPECT_TRUE(out_img.colorGamut == in_img.colorGamut);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
-#ifdef DUMP_OUTPUT
- if (!writeFile("mirrored_vertical.yuv", out_img.data, outSize)) {
- std::cerr << "unable to write output file" << std::endl;
- }
-#endif
-}
-
-TEST_F(EditorHelperTest, mirroringYuvImageHorizontal) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
-
- in_img.data = mYuvImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_YUV420;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int outSize = IMAGE_WIDTH * IMAGE_HEIGHT * 3 / 2;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(mirror(&in_img, ULTRAHDR_MIRROR_HORIZONTAL, &out_img)== JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = IMAGE_WIDTH);
- EXPECT_TRUE(out_img.height = IMAGE_HEIGHT);
- EXPECT_TRUE(out_img.colorGamut == in_img.colorGamut);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
-#ifdef DUMP_OUTPUT
- if (!writeFile("mirrored_horizontal.yuv", out_img.data, outSize)) {
- std::cerr << "unable to write output file" << std::endl;
- }
-#endif
-}
-
-TEST_F(EditorHelperTest, mirroringGreyImageVertical) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
-
- in_img.data = mGreyImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_MONOCHROME;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int outSize = IMAGE_WIDTH * IMAGE_HEIGHT;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(mirror(&in_img, ULTRAHDR_MIRROR_VERTICAL, &out_img)== JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = IMAGE_WIDTH);
- EXPECT_TRUE(out_img.height = IMAGE_HEIGHT);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
-#ifdef DUMP_OUTPUT
- if (!writeFile("mirrored_vertical.y", out_img.data, outSize)) {
- std::cerr << "unable to write output file" << std::endl;
- }
-#endif
}
-TEST_F(EditorHelperTest, mirroringGreyImageHorizontal) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
-
- in_img.data = mGreyImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_MONOCHROME;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int outSize = IMAGE_WIDTH * IMAGE_HEIGHT;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(mirror(&in_img, ULTRAHDR_MIRROR_HORIZONTAL, &out_img)== JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = IMAGE_WIDTH);
- EXPECT_TRUE(out_img.height = IMAGE_HEIGHT);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
-#ifdef DUMP_OUTPUT
- if (!writeFile("mirrored_horizontal.y", out_img.data, outSize)) {
- std::cerr << "unable to write output file" << std::endl;
+void compareImg(uhdr_raw_image_t* ref, uhdr_raw_image_t* test) {
+ ASSERT_EQ(ref->fmt, test->fmt);
+ ASSERT_EQ(ref->cg, test->cg);
+ ASSERT_EQ(ref->ct, test->ct);
+ ASSERT_EQ(ref->range, test->range);
+ ASSERT_EQ(ref->w, test->w);
+ ASSERT_EQ(ref->h, test->h);
+ int bpp = 1;
+ if (ref->fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
+ bpp = 2;
+ compare_planes(ref->planes[UHDR_PLANE_Y], test->planes[UHDR_PLANE_Y], ref->stride[UHDR_PLANE_Y],
+ test->stride[UHDR_PLANE_Y], ref->w, ref->h, bpp);
+ compare_planes(ref->planes[UHDR_PLANE_UV], test->planes[UHDR_PLANE_UV],
+ ref->stride[UHDR_PLANE_UV], test->stride[UHDR_PLANE_UV], ref->w, ref->h / 2,
+ bpp);
+ } else if (ref->fmt == UHDR_IMG_FMT_12bppYCbCr420) {
+ compare_planes(ref->planes[UHDR_PLANE_Y], test->planes[UHDR_PLANE_Y], ref->stride[UHDR_PLANE_Y],
+ test->stride[UHDR_PLANE_Y], ref->w, ref->h, bpp);
+ compare_planes(ref->planes[UHDR_PLANE_U], test->planes[UHDR_PLANE_U], ref->stride[UHDR_PLANE_U],
+ test->stride[UHDR_PLANE_U], ref->w / 2, ref->h / 2, bpp);
+ compare_planes(ref->planes[UHDR_PLANE_V], test->planes[UHDR_PLANE_V], ref->stride[UHDR_PLANE_V],
+ test->stride[UHDR_PLANE_V], ref->w / 2, ref->h / 2, bpp);
+ } else if (ref->fmt == UHDR_IMG_FMT_32bppRGBA8888 || ref->fmt == UHDR_IMG_FMT_32bppRGBA1010102 ||
+ ref->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat) {
+ bpp = ref->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat ? 8 : 4;
+ compare_planes(ref->planes[UHDR_PLANE_PACKED], test->planes[UHDR_PLANE_PACKED],
+ ref->stride[UHDR_PLANE_PACKED], test->stride[UHDR_PLANE_PACKED], ref->w, ref->h,
+ bpp);
+ } else if (ref->fmt == UHDR_IMG_FMT_8bppYCbCr400) {
+ compare_planes(ref->planes[UHDR_PLANE_Y], test->planes[UHDR_PLANE_Y], ref->stride[UHDR_PLANE_Y],
+ test->stride[UHDR_PLANE_Y], ref->w, ref->h, bpp);
}
-#endif
}
-TEST_F(EditorHelperTest, rotatingYuvImage90) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
-
- in_img.data = mYuvImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_YUV420;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int outSize = IMAGE_WIDTH * IMAGE_HEIGHT * 3 / 2;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(rotate(&in_img, 90, &out_img)== JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = IMAGE_HEIGHT);
- EXPECT_TRUE(out_img.height = IMAGE_WIDTH);
- EXPECT_TRUE(out_img.colorGamut == in_img.colorGamut);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
-#ifdef DUMP_OUTPUT
- if (!writeFile("rotated_90.yuv", out_img.data, outSize)) {
- std::cerr << "unable to write output file" << std::endl;
+class EditorHelperTest
+ : public ::testing::TestWithParam<std::tuple<std::string, int, int, uhdr_img_fmt_t>> {
+ public:
+ EditorHelperTest()
+ : filename(std::get<0>(GetParam())),
+ width(std::get<1>(GetParam())),
+ height(std::get<2>(GetParam())),
+ fmt(std::get<3>(GetParam())){};
+
+ ~EditorHelperTest() {
+ int count = sizeof img_a.planes / sizeof img_a.planes[0];
+ for (int i = 0; i < count; i++) {
+ if (img_a.planes[i]) {
+ free(img_a.planes[i]);
+ }
+ }
}
-#endif
-}
-TEST_F(EditorHelperTest, rotatingYuvImage180) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
-
- in_img.data = mYuvImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_YUV420;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int outSize = IMAGE_WIDTH * IMAGE_HEIGHT * 3 / 2;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(rotate(&in_img, 180, &out_img)== JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = IMAGE_WIDTH);
- EXPECT_TRUE(out_img.height = IMAGE_HEIGHT);
- EXPECT_TRUE(out_img.colorGamut == in_img.colorGamut);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
-#ifdef DUMP_OUTPUT
- if (!writeFile("rotated_180.yuv", out_img.data, outSize)) {
- std::cerr << "unable to write output file" << std::endl;
- }
-#endif
-}
+ std::string filename;
+ int width;
+ int height;
+ uhdr_img_fmt_t fmt;
+ uhdr_raw_image_t img_a;
+};
-TEST_F(EditorHelperTest, rotatingYuvImage270) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
-
- in_img.data = mYuvImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_YUV420;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int outSize = IMAGE_WIDTH * IMAGE_HEIGHT * 3 / 2;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(rotate(&in_img, 270, &out_img)== JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = IMAGE_HEIGHT);
- EXPECT_TRUE(out_img.height = IMAGE_WIDTH);
- EXPECT_TRUE(out_img.colorGamut == in_img.colorGamut);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
-#ifdef DUMP_OUTPUT
- if (!writeFile("rotated_270.yuv", out_img.data, outSize)) {
- std::cerr << "unable to write output file" << std::endl;
- }
-#endif
+TEST_P(EditorHelperTest, Rotate) {
+ initImageHandle(&img_a, width, height, fmt);
+ ASSERT_TRUE(loadFile(filename.c_str(), &img_a)) << "unable to load file " << filename;
+ auto dst = apply_rotate(&img_a, 90);
+ dst = apply_rotate(dst.get(), 90);
+ dst = apply_rotate(dst.get(), 180);
+ dst = apply_rotate(dst.get(), 270);
+ dst = apply_rotate(dst.get(), 90);
+ dst = apply_rotate(dst.get(), 90);
+ dst = apply_rotate(dst.get(), 270);
+ ASSERT_NO_FATAL_FAILURE(compareImg(&img_a, dst.get()));
}
-TEST_F(EditorHelperTest, rotatingGreyImage90) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
-
- in_img.data = mGreyImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_MONOCHROME;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int outSize = IMAGE_WIDTH * IMAGE_HEIGHT;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(rotate(&in_img, 90, &out_img)== JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = IMAGE_HEIGHT);
- EXPECT_TRUE(out_img.height = IMAGE_WIDTH);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
-#ifdef DUMP_OUTPUT
- if (!writeFile("rotated_90.y", out_img.data, outSize)) {
- std::cerr << "unable to write output file" << std::endl;
- }
-#endif
+TEST_P(EditorHelperTest, Mirror) {
+ initImageHandle(&img_a, width, height, fmt);
+ ASSERT_TRUE(loadFile(filename.c_str(), &img_a)) << "unable to load file " << filename;
+ auto dst = apply_mirror(&img_a, UHDR_MIRROR_VERTICAL);
+ dst = apply_mirror(dst.get(), UHDR_MIRROR_VERTICAL);
+ dst = apply_mirror(dst.get(), UHDR_MIRROR_HORIZONTAL);
+ dst = apply_mirror(dst.get(), UHDR_MIRROR_HORIZONTAL);
+ ASSERT_NO_FATAL_FAILURE(compareImg(&img_a, dst.get()));
}
-TEST_F(EditorHelperTest, rotatingGreyImage180) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
-
- in_img.data = mGreyImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_MONOCHROME;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int outSize = IMAGE_WIDTH * IMAGE_HEIGHT;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(rotate(&in_img, 180, &out_img)== JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = IMAGE_WIDTH);
- EXPECT_TRUE(out_img.height = IMAGE_HEIGHT);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
-#ifdef DUMP_OUTPUT
- if (!writeFile("rotated_180.y", out_img.data, outSize)) {
- std::cerr << "unable to write output file" << std::endl;
- }
-#endif
+TEST_P(EditorHelperTest, MultipleEffects) {
+ initImageHandle(&img_a, width, height, fmt);
+ ASSERT_TRUE(loadFile(filename.c_str(), &img_a)) << "unable to load file " << filename;
+ auto dst = apply_mirror(&img_a, UHDR_MIRROR_VERTICAL);
+ dst = apply_rotate(dst.get(), 180);
+ dst = apply_mirror(dst.get(), UHDR_MIRROR_HORIZONTAL);
+ ASSERT_NO_FATAL_FAILURE(compareImg(&img_a, dst.get()));
+
+ dst = apply_mirror(dst.get(), UHDR_MIRROR_HORIZONTAL);
+ dst = apply_rotate(dst.get(), 90);
+ dst = apply_rotate(dst.get(), 90);
+ dst = apply_mirror(dst.get(), UHDR_MIRROR_VERTICAL);
+ ASSERT_NO_FATAL_FAILURE(compareImg(&img_a, dst.get()));
+
+ dst = apply_rotate(dst.get(), 270);
+ dst = apply_mirror(dst.get(), UHDR_MIRROR_VERTICAL);
+ dst = apply_rotate(dst.get(), 90);
+ dst = apply_mirror(dst.get(), UHDR_MIRROR_HORIZONTAL);
+ ASSERT_NO_FATAL_FAILURE(compareImg(&img_a, dst.get()));
+
+ dst = apply_resize(dst.get(), width / 2, height / 2);
+ ASSERT_EQ(img_a.fmt, dst->fmt);
+ ASSERT_EQ(img_a.cg, dst->cg);
+ ASSERT_EQ(img_a.ct, dst->ct);
+ ASSERT_EQ(img_a.range, dst->range);
+ ASSERT_EQ(dst->w, width / 2);
+ ASSERT_EQ(dst->h, height / 2);
+
+ uhdr_raw_image_ext_t* img_copy = dst.get();
+ apply_crop(img_copy, 8, 8, width / 4, height / 4);
+ ASSERT_EQ(dst->fmt, img_copy->fmt);
+ ASSERT_EQ(dst->cg, img_copy->cg);
+ ASSERT_EQ(dst->ct, img_copy->ct);
+ ASSERT_EQ(dst->range, img_copy->range);
+ ASSERT_EQ(width / 4, img_copy->w);
+ ASSERT_EQ(height / 4, img_copy->h);
}
-TEST_F(EditorHelperTest, rotatingGreyImage270) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
-
- in_img.data = mGreyImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_MONOCHROME;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int outSize = IMAGE_WIDTH * IMAGE_HEIGHT;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(rotate(&in_img, 270, &out_img)== JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = IMAGE_HEIGHT);
- EXPECT_TRUE(out_img.height = IMAGE_WIDTH);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
+TEST_P(EditorHelperTest, Crop) {
+ initImageHandle(&img_a, width, height, fmt);
+ ASSERT_TRUE(loadFile(filename.c_str(), &img_a)) << "unable to load file " << filename;
+ uhdr_raw_image_t img_copy = img_a;
+ apply_crop(&img_copy, 8, 8, width / 2, height / 2);
+
+ ASSERT_EQ(img_a.fmt, img_copy.fmt);
+ ASSERT_EQ(img_a.cg, img_copy.cg);
+ ASSERT_EQ(img_a.ct, img_copy.ct);
+ ASSERT_EQ(img_a.range, img_copy.range);
+ ASSERT_EQ(img_copy.w, width / 2);
+ ASSERT_EQ(img_copy.h, height / 2);
#ifdef DUMP_OUTPUT
- if (!writeFile("rotated_270.y", out_img.data, outSize)) {
+ if (!writeFile("cropped", &img_copy)) {
std::cerr << "unable to write output file" << std::endl;
}
#endif
}
-TEST_F(EditorHelperTest, resizeYuvImageUp) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
-
- in_img.data = mYuvImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_YUV420;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int out_width = IMAGE_WIDTH * 3 / 2;
- int out_height = IMAGE_HEIGHT * 3 / 2;
- int outSize = out_width * out_height * 3 / 2;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(resize(&in_img, out_width, out_height, &out_img)== JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = out_width);
- EXPECT_TRUE(out_img.height = out_height);
- EXPECT_TRUE(out_img.colorGamut == in_img.colorGamut);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
+TEST_P(EditorHelperTest, Resize) {
+ initImageHandle(&img_a, width, height, fmt);
+ ASSERT_TRUE(loadFile(filename.c_str(), &img_a)) << "unable to load file " << filename;
+ auto dst = apply_resize(&img_a, width / 2, height / 2);
+
+ ASSERT_EQ(img_a.fmt, dst->fmt);
+ ASSERT_EQ(img_a.cg, dst->cg);
+ ASSERT_EQ(img_a.ct, dst->ct);
+ ASSERT_EQ(img_a.range, dst->range);
+ ASSERT_EQ(dst->w, width / 2);
+ ASSERT_EQ(dst->h, height / 2);
#ifdef DUMP_OUTPUT
- if (!writeFile("resize_up.yuv", out_img.data, outSize)) {
+ if (!writeFile("resize", dst.get())) {
std::cerr << "unable to write output file" << std::endl;
}
#endif
}
-TEST_F(EditorHelperTest, resizeYuvImageDown) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
-
- in_img.data = mYuvImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_YUV420;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int out_width = IMAGE_WIDTH * 2 / 3;
- int out_height = IMAGE_HEIGHT * 2 / 3;
- int outSize = out_width * out_height * 3 / 2;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(resize(&in_img, out_width, out_height, &out_img)== JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = out_width);
- EXPECT_TRUE(out_img.height = out_height);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
-#ifdef DUMP_OUTPUT
- if (!writeFile("resize_down.yuv", out_img.data, outSize)) {
- std::cerr << "unable to write output file" << std::endl;
- }
-#endif
-}
+#ifdef __ANDROID__
+INSTANTIATE_TEST_SUITE_P(
+ EditorAPIParameterizedTests, EditorHelperTest,
+ ::testing::Values(std::make_tuple("/data/local/tmp/raw_p010_image.p010", 1280, 720,
+ UHDR_IMG_FMT_24bppYCbCrP010),
+ std::make_tuple("/data/local/tmp/raw_yuv420_image.yuv420", 1280, 720,
+ UHDR_IMG_FMT_12bppYCbCr420),
+ std::make_tuple("/data/local/tmp/raw_yuv420_image.yuv420", 1280, 720,
+ UHDR_IMG_FMT_8bppYCbCr400),
+ std::make_tuple("/data/local/tmp/raw_p010_image.p010", 352, 288,
+ UHDR_IMG_FMT_32bppRGBA1010102),
+ std::make_tuple("/data/local/tmp/raw_p010_image.p010", 352, 288,
+ UHDR_IMG_FMT_64bppRGBAHalfFloat),
+ std::make_tuple("/data/local/tmp/raw_p010_image.p010", 352, 288,
+ UHDR_IMG_FMT_32bppRGBA8888)));
-TEST_F(EditorHelperTest, resizeGreyImageUp) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
-
- in_img.data = mGreyImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_MONOCHROME;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int out_width = IMAGE_WIDTH * 3 / 2;
- int out_height = IMAGE_HEIGHT * 3 / 2;
- int outSize = out_width * out_height;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(resize(&in_img, out_width, out_height, &out_img)== JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = out_width);
- EXPECT_TRUE(out_img.height = out_height);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
-#ifdef DUMP_OUTPUT
- if (!writeFile("resize_up.y", out_img.data, outSize)) {
- std::cerr << "unable to write output file" << std::endl;
- }
+#else
+INSTANTIATE_TEST_SUITE_P(
+ EditorAPIParameterizedTests, EditorHelperTest,
+ ::testing::Values(
+ std::make_tuple("./data/raw_p010_image.p010", 1280, 720, UHDR_IMG_FMT_24bppYCbCrP010),
+ std::make_tuple("./data/raw_yuv420_image.yuv420", 1280, 720, UHDR_IMG_FMT_12bppYCbCr420),
+ std::make_tuple("./data/raw_yuv420_image.yuv420", 1280, 720, UHDR_IMG_FMT_8bppYCbCr400),
+ std::make_tuple("./data/raw_p010_image.p010", 352, 288, UHDR_IMG_FMT_32bppRGBA1010102),
+ std::make_tuple("./data/raw_p010_image.p010", 352, 288, UHDR_IMG_FMT_64bppRGBAHalfFloat),
+ std::make_tuple("./data/raw_p010_image.p010", 352, 288, UHDR_IMG_FMT_32bppRGBA8888)));
#endif
-}
-TEST_F(EditorHelperTest, resizeGreyImageDown) {
- jpegr_uncompressed_struct in_img;
- jpegr_uncompressed_struct out_img;
-
- in_img.data = mGreyImage.buffer.get();
- in_img.width = IMAGE_WIDTH;
- in_img.height = IMAGE_HEIGHT;
- in_img.pixelFormat = ultrahdr_pixel_format::ULTRAHDR_PIX_FMT_MONOCHROME;
-
- std::unique_ptr<uint8_t[]> out_img_data;
- int out_width = IMAGE_WIDTH * 2 / 3;
- int out_height = IMAGE_HEIGHT * 2 / 3;
- int outSize = out_width * out_height;
- out_img_data.reset(new uint8_t[outSize]);
- out_img.data = out_img_data.get();
- EXPECT_TRUE(resize(&in_img, out_width, out_height, &out_img)== JPEGR_NO_ERROR);
- EXPECT_TRUE(out_img.width = out_width);
- EXPECT_TRUE(out_img.height = out_height);
- EXPECT_TRUE(out_img.pixelFormat == in_img.pixelFormat);
-#ifdef DUMP_OUTPUT
- if (!writeFile("resize_down.y", out_img.data, outSize)) {
- std::cerr << "unable to write output file" << std::endl;
- }
-#endif
-}
} // namespace ultrahdr