Yalantis/uCrop · error · CImgArgumentException

draw_quiver(): Invalid sampling value %g (should be >0)

Error message

draw_quiver(): Invalid sampling value %g (should be >0)

What it means

draw_quiver() validates that its sampling parameter (the grid spacing in pixels between drawn arrows) is strictly positive, throwing CImgArgumentException with the offending value otherwise. Sampling controls downsampling of the flow field; zero or negative spacing is mathematically meaningless for the stride loop.

Solutions

  1. Clamp before calling: if (sampling<1) sampling=1.
  2. Ensure derived sampling uses at least std::max(1u, width/step).
  3. Validate the user/config-facing density parameter and reject or clamp non-positive values at the input boundary.
  4. If a very dense quiver plot is intended, use sampling=1, not 0.

Example fix

// before
unsigned sampling = img.width()/density; // density>width => 0
img.draw_quiver(flow,color,1.f,sampling);
// after
unsigned sampling = std::max(1u, img.width()/density);
img.draw_quiver(flow,color,1.f,sampling);
Defensive patterns

Strategy: validation

Validate before calling

unsigned sampling = std::max(1u, computedSampling);
img.draw_quiver(flow,color,1.f,sampling);

Try / catch

try { img.draw_quiver(flow,color,1.f,sampling); }
catch (CImgArgumentException& e) { log_error("draw_quiver sampling=%u rejected", sampling); }

Prevention

When it happens

Trigger: Calling img.draw_quiver(flow,color,opacity,0) or with a negative sampling value; computing sampling dynamically (e.g. width/step) where step>width yields 0; passing float 0 through a default-argument chain.

Common situations: Auto-deriving sampling from image size for tiny images (e.g. sampling = w/64 == 0 for small thumbnails); user-configurable density setting allowed to be 0 or negative; unit mix-ups where sampling was given as a density instead of spacing.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08). Data as JSON: /api/errors/154b43fc0193aa69. Report an issue: GitHub.

Appendix: source

Thrown at ucrop/src/main/jni/CImg.h:53108

       \param sampling Length (in pixels) between each arrow.
       \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).
       \param is_arrow Tells if arrows must be drawn, instead of oriented segments.
       \param pattern Used pattern to draw lines.
       \note Clipping is supported.
    **/
    template<typename t1, typename t2>
    CImg<T>& draw_quiver(const CImg<t1>& flow,
                         const CImg<t2>& color, const float opacity=1,
                         const unsigned int sampling=25, const float factor=-20,
                         const bool is_arrow=true, const unsigned int pattern=~0U) {
      if (is_empty()) return *this;
      if (!flow || flow._spectrum!=2)
        throw CImgArgumentException(_cimg_instance
                                    "draw_quiver(): Invalid dimensions of specified flow (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    flow._width,flow._height,flow._depth,flow._spectrum,flow._data);
      if (sampling<=0)
        throw CImgArgumentException(_cimg_instance
                                    "draw_quiver(): Invalid sampling value %g "
                                    "(should be >0)",
                                    cimg_instance,
                                    sampling);
      const bool colorfield = (color._width==flow._width && color._height==flow._height &&
                               color._depth==1 && color._spectrum==_spectrum);
      if (is_overlapped(flow)) return draw_quiver(+flow,color,opacity,sampling,factor,is_arrow,pattern);
      float vmax,fact;
      if (factor<=0) {
        float m, M = (float)flow.get_norm(2).max_min(m);
        vmax = (float)std::max(cimg::abs(m),cimg::abs(M));
        if (!vmax) vmax = 1;
        fact = -factor;
      } else { fact = factor; vmax = 1; }

      for (unsigned int y = sampling/2; y<_height; y+=sampling)
        for (unsigned int x = sampling/2; x<_width; x+=sampling) {
          const unsigned int X = x*flow._width/_width, Y = y*flow._height/_height;

View on GitHub (pinned to f788b534b4)