From a6f27c7c5df758d47008e6956190518ad8ef780d Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Wed, 18 Dec 2024 11:35:37 -0800 Subject: [PATCH 1/2] FIX: set max row count to avoid iterating off the end of the data buffer --- pycaqtimage/pycaqtimage.sip | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/pycaqtimage/pycaqtimage.sip b/pycaqtimage/pycaqtimage.sip index 535a74d..b924755 100644 --- a/pycaqtimage/pycaqtimage.sip +++ b/pycaqtimage/pycaqtimage.sip @@ -349,8 +349,17 @@ static int rowIncMult1[8] = { 0, 0, -1, -1, 0, 0, 1, 1}; /* Scaled static int rowIncMult2[8] = { 0, 2, 0, 0, 0, -2, 0, 0}; /* Scaled by srcwidth */ static int rowIncK[8] = { 0, 0, -1, 1, 0, 0, 1, -1}; /* Constant */ +int _max_row(ImageBuffer *imageBuffer, long count) +{ + if (imageBuffer->imgwidth > 0) { + return std::min(imageBuffer->imgheight, (int) std::floor(count / imageBuffer->imgwidth)); + } else { + return 0; + } +} + template -void _pyDoAvg(ImageBuffer *imageBuffer, T *cadata) +void _pyDoAvg(ImageBuffer *imageBuffer, T *cadata, long count) { T *src = cadata; uint32_t *dst = imageBuffer->imageData; @@ -365,10 +374,11 @@ void _pyDoAvg(ImageBuffer *imageBuffer, T *cadata) int col_inc = imageBuffer->srcwidth * colIncMult[orientation] + colIncK[orientation]; int iNewAverage = imageBuffer->iNumAveraged + 1; + int row_max = _max_row(imageBuffer, count); src += init_offset; if (iNewAverage == 1) { - for (int iRow = 0; iRow < imageBuffer->imgheight; ++iRow) { + for (int iRow = 0; iRow < row_max; ++iRow) { for (int iCol = 0; iCol < imageBuffer->imgwidth; ++iCol) { *dstF++ = *src; *dst++ = *src; @@ -377,7 +387,7 @@ void _pyDoAvg(ImageBuffer *imageBuffer, T *cadata) src += row_inc; } } else { - for (int iRow = 0; iRow < imageBuffer->imgheight; ++iRow) { + for (int iRow = 0; iRow < row_max; ++iRow) { for (int iCol = 0; iCol < imageBuffer->imgwidth; ++iCol) { *dstF += (*src - *dstF) / iNewAverage; *dst++ = *dstF++; @@ -408,14 +418,14 @@ static void _pyColorImagePvCallback(void* cadata, long count, size_t size, void* int col_inc = imageBuffer->srcwidth * colIncMult[orientation] + colIncK[orientation]; int iNewAverage = imageBuffer->iNumAveraged + 1; + int row_max = _max_row(imageBuffer, count); - UNUSED(count); UNUSED(size); /* If we're using the color image, don't average, just copy and we're done! */ if (!imageBuffer->useGray) { src += 3 * init_offset; - for (int iRow = 0; iRow < imageBuffer->imgheight; ++iRow) { + for (int iRow = 0; iRow < row_max; ++iRow) { for (int iCol = 0; iCol < imageBuffer->imgwidth; ++iCol) { *dst++ = RGB(src); src += 3 * col_inc; @@ -426,7 +436,7 @@ static void _pyColorImagePvCallback(void* cadata, long count, size_t size, void* } else { if (iNewAverage == 1) { src += 3 * init_offset; - for (int iRow = 0; iRow < imageBuffer->imgheight; ++iRow) { + for (int iRow = 0; iRow < row_max; ++iRow) { for (int iCol = 0; iCol < imageBuffer->imgwidth; ++iCol) { *dstF = GRAY(src); *dst++ = *dstF++; @@ -436,7 +446,7 @@ static void _pyColorImagePvCallback(void* cadata, long count, size_t size, void* } } else { src += 3 * init_offset; - for (int iRow = 0; iRow < imageBuffer->imgheight; ++iRow) { + for (int iRow = 0; iRow < row_max; ++iRow) { for (int iCol = 0; iCol < imageBuffer->imgwidth; ++iCol) { *dstF += (GRAY(src) - *dstF) / iNewAverage; *dst++ = *dstF++; @@ -456,16 +466,15 @@ static void _pyImagePvCallback(void* cadata, long count, size_t size, void* usr) { ImageBuffer* imageBuffer = reinterpret_cast(usr); - UNUSED(count); switch (size) { case 4: - _pyDoAvg(imageBuffer, reinterpret_cast(cadata)); + _pyDoAvg(imageBuffer, reinterpret_cast(cadata), count); break; case 2: - _pyDoAvg(imageBuffer, reinterpret_cast(cadata)); + _pyDoAvg(imageBuffer, reinterpret_cast(cadata), count); break; case 1: - _pyDoAvg(imageBuffer, reinterpret_cast(cadata)); + _pyDoAvg(imageBuffer, reinterpret_cast(cadata), count); break; default: fprintf(stderr, "Image pixel size is %d bytes?\n", (int) size); From bd0c62c77e7189e588e92100b6cabfde141e7509 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 19 Dec 2024 13:41:17 -0800 Subject: [PATCH 2/2] ENH: add a warning for buffer size mismatch --- camviewer_ui_impl.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/camviewer_ui_impl.py b/camviewer_ui_impl.py index 068fed1..c5fea24 100644 --- a/camviewer_ui_impl.py +++ b/camviewer_ui_impl.py @@ -1991,6 +1991,22 @@ def connectCamera(self, sCameraPv, index, sNotifyPv=None): # Get camera configuration self.getConfig() + # Check the expected size against the count to generate warnings + first_image_count = len(self.camera.value) + expected_count = self.rowPv.value * self.colPv.value + if first_image_count != expected_count: + QMessageBox.warning( + None, + "Warning", + ( + "IOC misconfiguration likely!\n" + f"Received {first_image_count} pixels, expected {expected_count} " + f"for {self.rowPv.value} x {self.colPv.value}." + ), + QMessageBox.Ok, + QMessageBox.Ok, + ) + def setCameraMenu(self, index): for a in self.camactions: a.setChecked(False)