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
- Define cimg_use_jpeg and link against libjpeg (and its headers) before including CImg.h.
- Pass a filename instead of a FILE* so CImg can fall back to save_other() (slower, but works without libjpeg).
- 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
- Define cimg_use_jpeg and link libjpeg in build configs (CMake/NDK).
- Detect codec support at startup rather than at first save.
- Prefer filename overloads in builds with optional codecs so save_other() can kick in.
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
- load_gif_external(): Failed to open file
- load_jpeg(): Error message returned by libjpeg
- load_jpeg(): Failed to load JPEG data from file
- load_jpeg(): Incomplete data in file
- load_jpeg(): Specified filename is (null).
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)