Fix cropping of YUV images by amounts that are finer than the U/V resolution (and...
authorCarl Hetherington <cth@carlh.net>
Tue, 9 Jul 2013 22:43:22 +0000 (23:43 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 9 Jul 2013 22:43:22 +0000 (23:43 +0100)
src/lib/image.cc
test/image_test.cc

index 0eabbe84d5bcaff2188c1b81ce7e5d0d0c7092f6..ac30f4ff05f23992ba6dd0f2f8394468d960c7a2 100644 (file)
@@ -214,7 +214,11 @@ Image::crop (Crop crop, bool aligned) const
 
        for (int c = 0; c < components(); ++c) {
                int const crop_left_in_bytes = bytes_per_pixel(c) * crop.left;
-               int const cropped_width_in_bytes = bytes_per_pixel(c) * cropped_size.width;
+               /* bytes_per_pixel() could be a fraction; in this case the stride will be rounded
+                  up, and we need to make sure that we copy over the width (up to the stride)
+                  rather than short of the width; hence the ceil() here.
+               */
+               int const cropped_width_in_bytes = ceil (bytes_per_pixel(c) * cropped_size.width);
 
                /* Start of the source line, cropped from the top but not the left */
                uint8_t* in_p = data()[c] + (crop.top / out->line_factor(c)) * stride()[c];
index 9dd3a1ba4e656484777dc6c7c4ca22e58afa105d..b74531c46dcd821f133a9f9a16b172198cc48343 100644 (file)
@@ -107,3 +107,33 @@ BOOST_AUTO_TEST_CASE (crop_image_test)
        crop.top = 3;
        image->crop (crop, false);
 }
+
+/* Test cropping of a YUV 4:2:0 image by 1 pixel, which used to fail because
+   the U/V copying was not rounded up to the next sample.
+*/
+BOOST_AUTO_TEST_CASE (crop_image_test2)
+{
+       /* Here's a 1998 x 1080 image which is black */
+       shared_ptr<Image> image (new SimpleImage (PIX_FMT_YUV420P, libdcp::Size (1998, 1080), true));
+       image->make_black ();
+
+       /* Crop it by 1 pixel */
+       Crop crop;
+       crop.left = 1;
+       image = image->crop (crop, true);
+
+       /* Convert it back to RGB to make comparison to black easier */
+       image = image->scale_and_convert_to_rgb (image->size(), Scaler::from_id ("bicubic"), true);
+
+       /* Check that its still black after the crop */
+       uint8_t* p = image->data()[0];
+       for (int y = 0; y < image->size().height; ++y) {
+               uint8_t* q = p;
+               for (int x = 0; x < image->size().width; ++x) {
+                       BOOST_CHECK_EQUAL (*q++, 0);
+                       BOOST_CHECK_EQUAL (*q++, 0);
+                       BOOST_CHECK_EQUAL (*q++, 0);
+               }
+               p += image->stride()[0];
+       }
+}