Skip to content

Commit a3ed1b1

Browse files
committed
rewrite overlay image area intersection (#1226)
1 parent e382107 commit a3ed1b1

File tree

3 files changed

+81
-64
lines changed

3 files changed

+81
-64
lines changed

libheif/context.cc

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,9 +326,9 @@ Error ImageOverlay::parse(size_t num_images, const std::vector<uint8_t>& data)
326326
std::stringstream sstr;
327327
sstr << "Overlay image data version " << ((int) m_version) << " is not implemented yet";
328328

329-
return Error(heif_error_Unsupported_feature,
330-
heif_suberror_Unsupported_data_version,
331-
sstr.str());
329+
return {heif_error_Unsupported_feature,
330+
heif_suberror_Unsupported_data_version,
331+
sstr.str()};
332332
}
333333

334334
int field_len = ((m_flags & 1) ? 4 : 2);
@@ -346,6 +346,12 @@ Error ImageOverlay::parse(size_t num_images, const std::vector<uint8_t>& data)
346346
m_width = readvec(data, ptr, field_len);
347347
m_height = readvec(data, ptr, field_len);
348348

349+
if (m_width==0 || m_height==0) {
350+
return {heif_error_Invalid_input,
351+
heif_suberror_Invalid_overlay_data,
352+
"Overlay image with zero width or height."};
353+
}
354+
349355
m_offsets.resize(num_images);
350356

351357
for (size_t i = 0; i < num_images; i++) {

libheif/pixelimage.cc

Lines changed: 71 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,20 @@ Error HeifPixelImage::fill_RGB_16bit(uint16_t r, uint16_t g, uint16_t b, uint16_
748748
}
749749

750750

751-
Error HeifPixelImage::overlay(std::shared_ptr<HeifPixelImage>& overlay, int dx, int dy)
751+
uint32_t negate_negative_int32(int32_t x)
752+
{
753+
assert(x <= 0);
754+
755+
if (x == INT32_MIN) {
756+
return static_cast<uint32_t>(INT32_MAX) + 1;
757+
}
758+
else {
759+
return static_cast<uint32_t>(-x);
760+
}
761+
}
762+
763+
764+
Error HeifPixelImage::overlay(std::shared_ptr<HeifPixelImage>& overlay, int32_t dx, int32_t dy)
752765
{
753766
std::set<enum heif_channel> channels = overlay->get_channel_set();
754767

@@ -773,90 +786,88 @@ Error HeifPixelImage::overlay(std::shared_ptr<HeifPixelImage>& overlay, int dx,
773786
in_p = overlay->get_plane(channel, &in_stride);
774787
out_p = get_plane(channel, &out_stride);
775788

776-
int in_w = overlay->get_width(channel);
777-
int in_h = overlay->get_height(channel);
778-
assert(in_w >= 0);
779-
assert(in_h >= 0);
789+
uint32_t in_w = overlay->get_width(channel);
790+
uint32_t in_h = overlay->get_height(channel);
780791

781-
int out_w = get_width(channel);
782-
int out_h = get_height(channel);
783-
assert(out_w >= 0);
784-
assert(out_h >= 0);
792+
uint32_t out_w = get_width(channel);
793+
uint32_t out_h = get_height(channel);
785794

786-
// overlay image extends past the right border -> cut width for copy
787-
if (dx + in_w > out_w) {
788-
in_w = out_w - dx;
789-
}
795+
// top-left points where to start copying in source and destination
796+
uint32_t in_x0;
797+
uint32_t in_y0;
798+
uint32_t out_x0;
799+
uint32_t out_y0;
790800

791-
// overlay image extends past the bottom border -> cut height for copy
792-
if (dy + in_h > out_h) {
793-
in_h = out_h - dy;
801+
if (dx > 0 && static_cast<uint32_t>(dx) >= out_w) {
802+
// the overlay image is completely outside the right border -> skip overlaying
803+
return Error::Ok;
804+
}
805+
else if (dx < 0 && in_w <= negate_negative_int32(dx)) {
806+
// the overlay image is completely outside the left border -> skip overlaying
807+
return Error::Ok;
794808
}
795809

796-
// overlay image completely outside right or bottom border -> do not copy
797-
if (in_w < 0 || in_h < 0) {
798-
return Error(heif_error_Invalid_input,
799-
heif_suberror_Overlay_image_outside_of_canvas,
800-
"Overlay image outside of right or bottom canvas border");
810+
if (dx < 0) {
811+
// overlay image started partially outside of left border
812+
813+
in_x0 = negate_negative_int32(dx);
814+
out_x0 = 0;
815+
in_w = in_w - in_x0; // in_x0 < in_w because in_w > -dx = in_x0
816+
}
817+
else {
818+
in_x0 = 0;
819+
out_x0 = static_cast<uint32_t>(dx);
801820
}
802821

822+
// we know that dx >= 0 && dx < out_w
803823

804-
// calculate top-left point where to start copying in source and destination
805-
int in_x0 = 0;
806-
int in_y0 = 0;
807-
int out_x0 = dx;
808-
int out_y0 = dy;
824+
if (static_cast<uint32_t>(dx) > UINT32_MAX - in_w ||
825+
dx + in_w > out_w) {
826+
// overlay image extends partially outside of right border
809827

810-
// overlay image started outside of left border
811-
// -> move start into the image and start at left output column
812-
if (dx < 0) {
813-
in_x0 = -dx;
814-
out_x0 = 0;
828+
in_w = out_w - static_cast<uint32_t>(dx); // we know that dx < out_w from first condition
829+
}
830+
831+
832+
if (dy > 0 && static_cast<uint32_t>(dy) >= out_h) {
833+
// the overlay image is completely outside the bottom border -> skip overlaying
834+
return Error::Ok;
835+
}
836+
else if (dy < 0 && in_h <= negate_negative_int32(dy)) {
837+
// the overlay image is completely outside the top border -> skip overlaying
838+
return Error::Ok;
815839
}
816840

817-
// overlay image started outside of top border
818-
// -> move start into the image and start at top output row
819841
if (dy < 0) {
820-
in_y0 = -dy;
842+
// overlay image started partially outside of top border
843+
844+
in_y0 = negate_negative_int32(dy);
821845
out_y0 = 0;
846+
in_h = in_h - in_y0; // in_y0 < in_h because in_h > -dy = in_y0
822847
}
823-
824-
// if overlay image is completely outside at left border, do not copy anything.
825-
if (in_w <= in_x0 ||
826-
in_h <= in_y0) {
827-
return Error(heif_error_Invalid_input,
828-
heif_suberror_Overlay_image_outside_of_canvas,
829-
"Overlay image outside of left or top canvas border");
848+
else {
849+
in_y0 = 0;
850+
out_y0 = static_cast<uint32_t>(dy);
830851
}
831852

832-
// verify that the destination points are within the bounds of the image's dimensions
833-
if (out_x0 < 0 ||
834-
out_x0 >= out_w ||
835-
out_y0 < 0 ||
836-
out_y0 >= out_h) {
837-
return Error(heif_error_Invalid_input,
838-
heif_suberror_Invalid_overlay_data,
839-
"Overlay image has invalid offsets");
840-
}
853+
// we know that dy >= 0 && dy < out_h
854+
855+
if (static_cast<uint32_t>(dy) > UINT32_MAX - in_h ||
856+
dy + in_h > out_h) {
857+
// overlay image extends partially outside of bottom border
841858

842-
// verify that the source points are within the bounds of the image's dimensions
843-
if (in_x0 < 0 ||
844-
in_x0 >= in_w ||
845-
in_y0 < 0 ||
846-
in_y0 >= in_h) {
847-
return Error(heif_error_Invalid_input,
848-
heif_suberror_Invalid_overlay_data,
849-
"Overlay image has invalid offsets");
859+
in_h = out_h - static_cast<uint32_t>(dy); // we know that dy < out_h from first condition
850860
}
851861

852-
for (int y = in_y0; y < in_h; y++) {
862+
863+
for (uint32_t y = in_y0; y < in_h; y++) {
853864
if (!has_alpha) {
854865
memcpy(out_p + out_x0 + (out_y0 + y - in_y0) * out_stride,
855866
in_p + in_x0 + y * in_stride,
856867
in_w - in_x0);
857868
}
858869
else {
859-
for (int x = in_x0; x < in_w; x++) {
870+
for (uint32_t x = in_x0; x < in_w; x++) {
860871
uint8_t* outptr = &out_p[out_x0 + (out_y0 + y - in_y0) * out_stride + x];
861872
uint8_t in_val = in_p[in_x0 + y * in_stride + x];
862873
uint8_t alpha_val = alpha_p[in_x0 + y * in_stride + x];

libheif/pixelimage.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class HeifPixelImage : public std::enable_shared_from_this<HeifPixelImage>,
109109

110110
Error fill_RGB_16bit(uint16_t r, uint16_t g, uint16_t b, uint16_t a);
111111

112-
Error overlay(std::shared_ptr<HeifPixelImage>& overlay, int dx, int dy);
112+
Error overlay(std::shared_ptr<HeifPixelImage>& overlay, int32_t dx, int32_t dy);
113113

114114
Error scale_nearest_neighbor(std::shared_ptr<HeifPixelImage>& output, int width, int height) const;
115115

0 commit comments

Comments
 (0)