Yalantis/uCrop · error · CImgArgumentException
draw_image(): Sprite (%u,%u,%u,%u,%p) and mask (%u,%u,%u,%u,
Error message
draw_image(): Sprite (%u,%u,%u,%u,%p) and mask (%u,%u,%u,%u,%p) have incompatible dimensions.
What it means
draw_image() with a mask requires the mask to have exactly the same width, height and depth as the sprite, and throws CImgArgumentException with both images' full dimensions when they differ. The mask modulates per-pixel blending, so a one-to-one spatial correspondence between sprite and mask pixels is mandatory; spectrum (channels) may differ.
Source
Thrown at ucrop/src/main/jni/CImg.h:52751
\param x0 X-coordinate of the sprite position in the image instance.
\param y0 Y-coordinate of the sprite position in the image instance.
\param z0 Z-coordinate of the sprite position in the image instance.
\param c0 C-coordinate of the sprite position in the image instance.
\param mask_max_value Maximum pixel value of the mask image \c mask.
\param opacity Drawing opacity.
\note
- Pixel values of \c mask set the opacity of the corresponding pixels in \c sprite.
- Dimensions along x,y and z of \p sprite and \p mask must be the same.
**/
template<typename ti, typename tm>
CImg<T>& draw_image(const int x0, const int y0, const int z0, const int c0,
const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
const float mask_max_value=1) {
if (is_empty() || !sprite || !mask) return *this;
if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,mask,opacity,mask_max_value);
if (is_overlapped(mask)) return draw_image(x0,y0,z0,c0,sprite,+mask,opacity,mask_max_value);
if (mask._width!=sprite._width || mask._height!=sprite._height || mask._depth!=sprite._depth)
throw CImgArgumentException(_cimg_instance
"draw_image(): Sprite (%u,%u,%u,%u,%p) and mask (%u,%u,%u,%u,%p) have "
"incompatible dimensions.",
cimg_instance,
sprite._width,sprite._height,sprite._depth,sprite._spectrum,sprite._data,
mask._width,mask._height,mask._depth,mask._spectrum,mask._data);
const bool bx = x0<0, by = y0<0, bz = z0<0, bc = c0<0;
const int
dx0 = bx?0:x0, dy0 = by?0:y0, dz0 = bz?0:z0, dc0 = bc?0:c0,
sx0 = dx0 - x0, sy0 = dy0 - y0, sz0 = dz0 - z0, sc0 = dc0 - c0,
lx = sprite.width() - sx0 - (x0 + sprite.width()>width()?x0 + sprite.width() - width():0),
ly = sprite.height() - sy0 - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0),
lz = sprite.depth() - sz0 - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0),
lc = sprite.spectrum() - sc0 - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0);
const ulongT msize = mask.size();
if (lx>0 && ly>0 && lz>0 && lc>0) {
for (int c = 0; c<lc; ++c)View on GitHub (pinned to f788b534b4)
Solutions
- Resize the mask to the sprite geometry before drawing: mask.resize(sprite.width(),sprite.height(),sprite.depth(),-100,0,0).
- Recreate the mask from the same source dimensions as the sprite.
- Log/assert sprite.dimensions()==mask.dimensions() (compare width/height/depth only) before the draw call.
- If the mask was meant to be a scalar constant, use the opacity parameter instead of a mask image.
Example fix
// before CImg<float> mask = makeMask(); // may differ in size img.draw_image(x,y,sprite,mask); // after CImg<float> mask = makeMask(); mask.resize(sprite.width(),sprite.height(),sprite.depth(),-100,0); img.draw_image(x,y,sprite,mask);
Defensive patterns
Strategy: validation
Validate before calling
if (mask.width()!=sprite.width() || mask.height()!=sprite.height() || mask.depth()!=sprite.depth())
mask.resize(sprite.width(),sprite.height(),sprite.depth(),-100,0);
img.draw_image(x,y,z,c,sprite,mask,opacity); Type guard
bool maskMatches(const CImg<float>& sprite, const CImg<float>& mask){
return !mask.is_empty() && mask.width()==sprite.width() &&
mask.height()==sprite.height() && mask.depth()==sprite.depth();
} Try / catch
try { img.draw_image(x,y,sprite,mask); }
catch (CImgArgumentException& e) { log_error("draw_image sprite/mask mismatch: %s", e.what()); } Prevention
- Resize masks to sprite geometry immediately after generating them.
- Keep sprite and mask production in the same pipeline stage so dimensions stay coupled.
- Assert dimension equality in debug builds before draw calls.
- Never hardcode mask sizes; derive from sprite.dimensions().
When it happens
Trigger: Calling img.draw_image(x,y,z,c,sprite,mask) where mask.width/height/depth != sprite.width/height/depth — e.g. mask generated at a different resolution, mask resized independently, or a single-channel mask built with wrong geometry (transposed or cropped).
Common situations: Alpha masks produced by a segmentation or blur pipeline at another scale than the sprite; hardcoding mask dimensions that no longer match after sprite source changed; forgetting to call mask.resize(sprite.width(),sprite.height(),sprite.depth()).
Understand the failure class
Background: Tensor shape mismatch errors ("must have shape", "expected shape ... got ..."): when tensor dimensions disagree with what an op or layer was told to expect — this error's family across 6 libraries.
Related errors
- _cimg_instance "MSE(): Instance and specified image (%u,%u,%
- draw_polygon(): Invalid specified point set (%u,%u,%u,%u).
- draw_quiver(): Invalid dimensions of specified flow (%u,%u,%
- draw_mandelbrot(): Instance and specified colormap (%u,%u,%u
- atXYZC(): Empty instance.
AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08).
Data as JSON: /api/errors/d2f0e36062dd9075.
Report an issue: GitHub.