Yalantis/uCrop · error · CImgIOException

save_jpeg(): Unable to save data in '(*FILE)' unless…

Error message

save_jpeg(): Unable to save data in '(*FILE)' unless libjpeg is enabled.

What it means

When CImg is compiled without cimg_use_jpeg, JPEG encoding via libjpeg is unavailable. Saving to an already-open FILE* cannot fall back to format detection by extension (that path needs a filename), so CImg throws CImgIOException stating the data cannot be saved to a FILE* unless libjpeg support is enabled.

Solutions

  1. Define cimg_use_jpeg and link against libjpeg (and its headers) before including CImg.h.
  2. Pass a filename instead of a FILE* so CImg can fall back to save_other() (slower, but works without libjpeg).
  3. Save to a different format that is enabled (e.g. PNG via libpng) or serialize with save_raw/save_other by extension.

Example fix

// before (no cimg_use_jpeg)
std::FILE *f = fopen("out.jpg", "wb");
img.save_jpeg(f);
// after
#define cimg_use_jpeg 1
#include <jpeglib.h> // link -ljpeg
img.save_jpeg("out.jpg");
Defensive patterns

Strategy: fallback

Try / catch

try {
  img.save_jpeg(file, quality);
} catch (const cimg_library::CImgIOException &e) {
  // libjpeg not enabled in this build
  img.save_png("out.png"); // fallback to an enabled codec
}

Prevention

When it happens

Trigger: Calling img.save_jpeg(std::FILE*) (or _save_jpeg with a non-null file) in a build where cimg_use_jpeg is NOT defined. Saving via a filename instead falls back to save_other().

Common situations: Android NDK / uCrop JNI builds where libjpeg was not linked, plain builds with no cimg_use_jpeg define, or third-party prebuilt CImg.h without JPEG support compiled in.

Understand the failure class

Background: "X is not installed. Please install it with pip install Y": missing optional dependency errors — ImportError/ValueError raised when a library's optional extra was never installed — this error's family across 22 libraries.

Related errors


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

Appendix: source

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

    const CImg<T>& save_jpeg(std::FILE *const file, const unsigned int quality=100) const {
      return _save_jpeg(file,0,quality);
    }

    const CImg<T>& _save_jpeg(std::FILE *const file, const char *const filename, const unsigned int quality) const {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_jpeg(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(file,filename); return *this; }
      if (_depth>1)
        cimg::warn(_cimg_instance
                   "save_jpeg(): Instance is volumetric, only the first slice will be saved in file '%s'.",
                   cimg_instance,
                   filename?filename:"(FILE*)");

#ifndef cimg_use_jpeg
      if (!file) return save_other(filename,quality);
      else throw CImgIOException(_cimg_instance
                                 "save_jpeg(): Unable to save data in '(*FILE)' unless libjpeg is enabled.",
                                 cimg_instance);
#else
      unsigned int dimbuf = 0;
      J_COLOR_SPACE colortype = JCS_RGB;

      switch (_spectrum) {
      case 1 : dimbuf = 1; colortype = JCS_GRAYSCALE; break;
      case 2 : dimbuf = 3; colortype = JCS_RGB; break;
      case 3 : dimbuf = 3; colortype = JCS_RGB; break;
      default : dimbuf = 4; colortype = JCS_CMYK; break;
      }

      // Call libjpeg functions.
      struct jpeg_compress_struct cinfo;
      struct jpeg_error_mgr jerr;
      cinfo.err = jpeg_std_error(&jerr);
      jpeg_create_compress(&cinfo);

View on GitHub (pinned to f788b534b4)