#include "libraw_wrapper.h"
#include "libraw/libraw.h"
#include "turbojpeg.h"
#include <string>
#include <vector>
#include <fstream>
#include <algorithm>
static std::string last_error;
extern "C" {
const char* get_last_error() {
return last_error.c_str();
}
int convert_ppm_to_jpeg(const std::vector<unsigned char>& ppm_data, int width, int height, const char* jpeg_path, int quality) {
tjhandle jpeg_compressor = tjInitCompress();
if (!jpeg_compressor) {
return RW_ERROR_PROCESS;
}
unsigned char* jpeg_buf = nullptr;
unsigned long jpeg_size = 0;
int result = tjCompress2(
jpeg_compressor,
ppm_data.data(), width,
0, height,
TJPF_RGB, &jpeg_buf, &jpeg_size, TJSAMP_444, quality,
TJFLAG_FASTDCT );
if (result != 0) {
tjDestroy(jpeg_compressor);
return RW_ERROR_PROCESS;
}
std::ofstream jpeg_file(jpeg_path, std::ios::binary);
if (!jpeg_file.is_open()) {
tjFree(jpeg_buf);
tjDestroy(jpeg_compressor);
return RW_ERROR_WRITE;
}
jpeg_file.write(reinterpret_cast<char*>(jpeg_buf), jpeg_size);
jpeg_file.close();
tjFree(jpeg_buf);
tjDestroy(jpeg_compressor);
return RW_SUCCESS;
}
int process_raw_to_jpeg(const char* input_path, const char* output_path, ExifData& exif_data) {
(void)exif_data;
last_error.clear();
LibRaw* processor = new LibRaw();
try {
processor->imgdata.params.output_bps = 8; processor->imgdata.params.output_color = 1; processor->imgdata.params.use_camera_wb = 1; processor->imgdata.params.no_auto_bright = 1; processor->imgdata.params.use_camera_matrix = 1; processor->imgdata.params.half_size = 1;
processor->imgdata.rawparams.options = 0; processor->imgdata.rawparams.options |= 0x2000; processor->imgdata.rawparams.options |= 0x8000; processor->imgdata.rawparams.options |= 0x10000; processor->imgdata.rawparams.options |= 0x40000;
int ret = processor->open_file(input_path);
if (ret != LIBRAW_SUCCESS) {
last_error = "Failed to open file: ";
last_error += libraw_strerror(ret);
delete processor;
return RW_ERROR_OPEN_FILE;
}
ret = processor->unpack();
if (ret != LIBRAW_SUCCESS) {
last_error = "Failed to unpack RAW data: ";
last_error += libraw_strerror(ret);
std::string input_str(input_path);
if (input_str.length() > 4) {
std::string ext = input_str.substr(input_str.length() - 4);
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
if (ext == ".dng") {
last_error += " (Note: This may be a non-standard DNG file from a mobile device or unsupported DNG variant)";
}
}
delete processor;
return RW_ERROR_UNPACK;
}
ret = processor->dcraw_process();
if (ret != LIBRAW_SUCCESS) {
last_error = "Failed to process image: ";
last_error += libraw_strerror(ret);
delete processor;
return RW_ERROR_PROCESS;
}
strncpy((char*)exif_data.camera_make, processor->imgdata.idata.make, 63);
((char*)exif_data.camera_make)[63] = '\0';
strncpy((char*)exif_data.camera_model, processor->imgdata.idata.model, 63);
((char*)exif_data.camera_model)[63] = '\0';
exif_data.software = processor->imgdata.idata.software;
exif_data.iso_speed = static_cast<int>(processor->imgdata.other.iso_speed);
exif_data.shutter = processor->imgdata.other.shutter;
exif_data.aperture = processor->imgdata.other.aperture;
exif_data.focal_length = processor->imgdata.other.focal_len;
exif_data.raw_width = processor->imgdata.sizes.raw_width;
exif_data.raw_height = processor->imgdata.sizes.raw_height;
exif_data.output_width = processor->imgdata.sizes.width;
exif_data.output_height = processor->imgdata.sizes.height;
exif_data.colors = processor->imgdata.idata.colors;
exif_data.color_filter = static_cast<int>(processor->imgdata.idata.filters);
for (int i = 0; i < 4; i++) {
exif_data.cam_mul[i] = processor->imgdata.color.cam_mul[i];
}
exif_data.date_taken = processor->imgdata.other.desc;
exif_data.lens = processor->imgdata.lens.Lens;
exif_data.max_aperture = processor->imgdata.lens.EXIF_MaxAp;
exif_data.focal_length_35mm = processor->imgdata.lens.FocalLengthIn35mmFormat;
exif_data.description = processor->imgdata.other.desc;
exif_data.artist = processor->imgdata.other.artist;
libraw_processed_image_t* image = processor->dcraw_make_mem_image();
if (!image) {
last_error = "Failed to generate image data: ";
last_error += libraw_strerror(LIBRAW_UNSPECIFIED_ERROR);
delete processor;
return RW_ERROR_WRITE;
}
if (image->type != LIBRAW_IMAGE_BITMAP || image->colors != 3 || image->bits != 8) {
last_error = "Unsupported image format";
LibRaw::dcraw_clear_mem(image);
delete processor;
return RW_ERROR_PROCESS;
}
int width = image->width;
int height = image->height;
std::vector<unsigned char> ppm_data(image->data, image->data + (width * height * 3));
LibRaw::dcraw_clear_mem(image);
ret = convert_ppm_to_jpeg(ppm_data, width, height, output_path, 75); if (ret != RW_SUCCESS) {
last_error = "Failed to convert to JPEG";
delete processor;
return ret;
}
delete processor;
return RW_SUCCESS;
} catch (const std::exception& e) {
last_error = "Exception occurred: ";
last_error += e.what();
delete processor;
return RW_ERROR_UNKNOWN;
} catch (...) {
last_error = "Unknown exception occurred";
delete processor;
return RW_ERROR_UNKNOWN;
}
}
}