| /* -*- C++ -*- |
| * File: mem_image.cpp |
| * Copyright 2008-2025 LibRaw LLC (info@libraw.org) |
| * |
| * LibRaw mem_image/mem_thumb API test. Results should be same (bitwise) to |
| dcraw [-4] [-6] [-e] |
| * Testing note: for ppm-thumbnails you should use dcraw -w -e for thumbnail |
| extraction |
| |
| LibRaw is free software; you can redistribute it and/or modify |
| it under the terms of the one of two licenses as you choose: |
| |
| 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 |
| (See file LICENSE.LGPL provided in LibRaw distribution archive for details). |
| |
| 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 |
| (See file LICENSE.CDDL provided in LibRaw distribution archive for details). |
| |
| |
| */ |
| #include <stdio.h> |
| #include <string.h> |
| #include <math.h> |
| |
| #include "third_party/libraw/libraw/libraw.h" |
| |
| #ifdef USE_JPEG |
| #include "jpeglib.h" |
| #endif |
| |
| #ifdef LIBRAW_WIN32_CALLS |
| #define snprintf _snprintf |
| #include <winsock2.h> |
| #pragma comment(lib, "ws2_32.lib") |
| #else |
| #include <netinet/in.h> |
| #endif |
| |
| #ifdef USE_JPEG |
| void write_jpeg(libraw_processed_image_t *img, const char *basename, int quality) |
| { |
| char fn[1024]; |
| if(img->colors != 1 && img->colors != 3) |
| { |
| printf("Only BW and 3-color images supported for JPEG output\n"); |
| return; |
| } |
| snprintf(fn, 1024, "%s.jpg", basename); |
| FILE *f = fopen(fn, "wb"); |
| if (!f) |
| return; |
| struct jpeg_compress_struct cinfo; |
| struct jpeg_error_mgr jerr; |
| JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ |
| int row_stride; /* physical row width in image buffer */ |
| |
| cinfo.err = jpeg_std_error(&jerr); |
| jpeg_create_compress(&cinfo); |
| jpeg_stdio_dest(&cinfo, f); |
| cinfo.image_width = img->width; /* image width and height, in pixels */ |
| cinfo.image_height = img->height; |
| cinfo.input_components = img->colors; /* # of color components per pixel */ |
| cinfo.in_color_space = img->colors==3?JCS_RGB:JCS_GRAYSCALE; /* colorspace of input image */ |
| jpeg_set_defaults(&cinfo); |
| jpeg_set_quality(&cinfo, quality, TRUE); |
| jpeg_start_compress(&cinfo, TRUE); |
| row_stride = img->width * img->colors; /* JSAMPLEs per row in image_buffer */ |
| while (cinfo.next_scanline < cinfo.image_height) { |
| row_pointer[0] = &img->data[cinfo.next_scanline * row_stride]; |
| (void)jpeg_write_scanlines(&cinfo, row_pointer, 1); |
| } |
| jpeg_finish_compress(&cinfo); |
| fclose(f); |
| jpeg_destroy_compress(&cinfo); |
| } |
| |
| #endif |
| |
| // no error reporting, only params check |
| void write_ppm(libraw_processed_image_t *img, const char *basename) |
| { |
| if (!img) |
| return; |
| // type SHOULD be LIBRAW_IMAGE_BITMAP, but we'll check |
| if (img->type != LIBRAW_IMAGE_BITMAP) |
| return; |
| if (img->colors != 3 && img->colors != 1) |
| { |
| printf("Only monochrome and 3-color images supported for PPM output\n"); |
| return; |
| } |
| |
| char fn[1024]; |
| snprintf(fn, 1024, "%s.p%cm", basename, img->colors==1?'g':'p'); |
| FILE *f = fopen(fn, "wb"); |
| if (!f) |
| return; |
| fprintf(f, "P%d\n%d %d\n%d\n", img->colors/2 + 5, img->width, img->height, (1 << img->bits) - 1); |
| /* |
| NOTE: |
| data in img->data is not converted to network byte order. |
| So, we should swap values on some architectures for dcraw compatibility |
| (unfortunately, xv cannot display 16-bit PPMs with network byte order data |
| */ |
| #define SWAP(a, b) \ |
| { \ |
| a ^= b; \ |
| a ^= (b ^= a); \ |
| } |
| if (img->bits == 16 && htons(0x55aa) != 0x55aa) |
| for (unsigned i = 0; i < img->data_size-1; i += 2) |
| SWAP(img->data[i], img->data[i + 1]); |
| #undef SWAP |
| |
| fwrite(img->data, img->data_size, 1, f); |
| fclose(f); |
| } |
| |
| void write_thumb(libraw_processed_image_t *img, const char *basename) |
| { |
| if (!img) |
| return; |
| |
| if (img->type == LIBRAW_IMAGE_BITMAP) |
| { |
| char fnt[1024]; |
| snprintf(fnt, 1024, "%s.thumb", basename); |
| write_ppm(img, fnt); |
| } |
| else if (img->type == LIBRAW_IMAGE_JPEG) |
| { |
| char fn[1024]; |
| snprintf(fn, 1024, "%s.thumb.jpg", basename); |
| FILE *f = fopen(fn, "wb"); |
| if (!f) |
| return; |
| fwrite(img->data, img->data_size, 1, f); |
| fclose(f); |
| } |
| } |
| |
| int main(int ac, char *av[]) |
| { |
| int i, ret, output_thumbs = 0; |
| #ifdef USE_JPEG |
| int output_jpeg = 0, jpgqual = 90; |
| #endif |
| // don't use fixed size buffers in real apps! |
| |
| LibRaw RawProcessor; |
| |
| if (ac < 2) |
| { |
| printf("mem_image - LibRaw sample, to illustrate work for memory buffers.\n" |
| "Emulates dcraw [-4] [-1] [-e] [-h]\n" |
| #ifdef USE_JPEG |
| "Usage: %s [-D] [-j[nn]] [-T] [-v] [-e] raw-files....\n" |
| #else |
| "Usage: %s [-D] [-T] [-v] [-e] raw-files....\n" |
| #endif |
| "\t-6 - output 16-bit PPM\n" |
| "\t-4 - linear 16-bit data\n" |
| "\t-e - extract thumbnails (same as dcraw -e in separate run)\n" |
| #ifdef USE_JPEG |
| "\t-j[qual] - output JPEG with qual quality (e.g. -j90)\n" |
| #endif |
| "\t-h - use half_size\n", av[0]); |
| return 0; |
| } |
| |
| putenv((char *)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field |
| |
| #define P1 RawProcessor.imgdata.idata |
| #define S RawProcessor.imgdata.sizes |
| #define C RawProcessor.imgdata.color |
| #define T RawProcessor.imgdata.thumbnail |
| #define P2 RawProcessor.imgdata.other |
| #define OUT RawProcessor.imgdata.params |
| |
| for (i = 1; i < ac; i++) |
| { |
| if (av[i][0] == '-') |
| { |
| if (av[i][1] == '6' && av[i][2] == 0) |
| OUT.output_bps = 16; |
| if (av[i][1] == '4' && av[i][2] == 0) |
| { |
| OUT.output_bps = 16; |
| OUT.gamm[0] = OUT.gamm[1] = OUT.no_auto_bright = 1; |
| } |
| if (av[i][1] == 'e' && av[i][2] == 0) |
| output_thumbs++; |
| if (av[i][1] == 'h' && av[i][2] == 0) |
| OUT.half_size = 1; |
| #ifdef USE_JPEG |
| if (av[i][1] == 'j') |
| { |
| output_jpeg = 1; |
| if(av[i][2] != 0) |
| jpgqual = atoi(av[i]+2); |
| } |
| #endif |
| continue; |
| } |
| #ifdef USE_JPEG |
| if(output_jpeg && OUT.output_bps>8) |
| { |
| printf("JPEG is limited to 8 bit\n"); |
| OUT.output_bps = 8; |
| } |
| #endif |
| printf("Processing %s\n", av[i]); |
| if ((ret = RawProcessor.open_file(av[i])) != LIBRAW_SUCCESS) |
| { |
| fprintf(stderr, "Cannot open %s: %s\n", av[i], libraw_strerror(ret)); |
| continue; // no recycle b/c open file will recycle itself |
| } |
| |
| if ((ret = RawProcessor.unpack()) != LIBRAW_SUCCESS) |
| { |
| fprintf(stderr, "Cannot unpack %s: %s\n", av[i], libraw_strerror(ret)); |
| continue; |
| } |
| |
| // we should call dcraw_process before thumbnail extraction because for |
| // some cameras (i.e. Kodak ones) white balance for thumbnail should be set |
| // from main image settings |
| |
| ret = RawProcessor.dcraw_process(); |
| |
| if (LIBRAW_SUCCESS != ret) |
| { |
| fprintf(stderr, "Cannot do postprocessing on %s: %s\n", av[i], |
| libraw_strerror(ret)); |
| if (LIBRAW_FATAL_ERROR(ret)) |
| continue; |
| } |
| libraw_processed_image_t *image = RawProcessor.dcraw_make_mem_image(&ret); |
| if (image) |
| { |
| #ifdef USE_JPEG |
| if(output_jpeg) |
| write_jpeg(image, av[i], jpgqual); |
| else |
| #endif |
| write_ppm(image, av[i]); |
| LibRaw::dcraw_clear_mem(image); |
| } |
| else |
| fprintf(stderr, "Cannot unpack %s to memory buffer: %s\n", av[i], |
| libraw_strerror(ret)); |
| |
| if (output_thumbs) |
| { |
| |
| if ((ret = RawProcessor.unpack_thumb()) != LIBRAW_SUCCESS) |
| { |
| fprintf(stderr, "Cannot unpack_thumb %s: %s\n", av[i], |
| libraw_strerror(ret)); |
| if (LIBRAW_FATAL_ERROR(ret)) |
| continue; // skip to next file |
| } |
| else |
| { |
| libraw_processed_image_t *thumb = |
| RawProcessor.dcraw_make_mem_thumb(&ret); |
| if (thumb) |
| { |
| write_thumb(thumb, av[i]); |
| LibRaw::dcraw_clear_mem(thumb); |
| } |
| else |
| fprintf(stderr, |
| "Cannot unpack thumbnail of %s to memory buffer: %s\n", av[i], |
| libraw_strerror(ret)); |
| } |
| } |
| |
| RawProcessor.recycle(); // just for show this call |
| } |
| return 0; |
| } |