File indexing completed on 2025-01-05 03:56:48

0001 /* -*- C++ -*-
0002  * File: mem_image.cpp
0003  * Copyright 2008-2021 LibRaw LLC (info@libraw.org)
0004  *
0005  * LibRaw mem_image/mem_thumb API test. Results should be same (bitwise) to
0006 dcraw [-4] [-6] [-e]
0007  * Testing note: for ppm-thumbnails you should use dcraw -w -e for thumbnail
0008 extraction
0009 
0010 LibRaw is free software; you can redistribute it and/or modify
0011 it under the terms of the one of two licenses as you choose:
0012 
0013 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
0014    (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
0015 
0016 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
0017    (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
0018 
0019 
0020  */
0021 #include <stdio.h>
0022 #include <string.h>
0023 #include <math.h>
0024 
0025 #include "libraw/libraw.h"
0026 
0027 #ifdef USE_JPEG
0028 #include "jpeglib.h"
0029 #endif
0030 
0031 #ifdef LIBRAW_WIN32_CALLS
0032 #define snprintf _snprintf
0033 #include <winsock2.h>
0034 #pragma comment(lib, "ws2_32.lib")
0035 #else
0036 #include <netinet/in.h>
0037 #endif
0038 
0039 #ifdef USE_JPEG
0040 void write_jpeg(libraw_processed_image_t *img, const char *basename, int quality)
0041 {
0042   char fn[1024];
0043   if(img->colors != 1 && img->colors != 3)
0044   {
0045     printf("Only BW and 3-color images supported for JPEG output\n");
0046     return;
0047   }
0048   snprintf(fn, 1024, "%s.jpg", basename);
0049   FILE *f = fopen(fn, "wb");
0050   if (!f)
0051     return;
0052   struct jpeg_compress_struct cinfo;
0053   struct jpeg_error_mgr jerr;
0054   JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
0055   int row_stride;          /* physical row width in image buffer */
0056 
0057   cinfo.err = jpeg_std_error(&jerr);
0058   jpeg_create_compress(&cinfo);
0059   jpeg_stdio_dest(&cinfo, f);
0060   cinfo.image_width = img->width;      /* image width and height, in pixels */
0061   cinfo.image_height = img->height;
0062   cinfo.input_components = img->colors;           /* # of color components per pixel */
0063   cinfo.in_color_space = img->colors==3?JCS_RGB:JCS_GRAYSCALE;       /* colorspace of input image */
0064   jpeg_set_defaults(&cinfo);
0065   jpeg_set_quality(&cinfo, quality, TRUE);
0066   jpeg_start_compress(&cinfo, TRUE);
0067   row_stride = img->width * img->colors; /* JSAMPLEs per row in image_buffer */
0068   while (cinfo.next_scanline < cinfo.image_height) {
0069     row_pointer[0] = &img->data[cinfo.next_scanline * row_stride];
0070     (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
0071   }
0072   jpeg_finish_compress(&cinfo);
0073   fclose(f);
0074   jpeg_destroy_compress(&cinfo);
0075 }
0076 
0077 #endif
0078 
0079 // no error reporting, only params check
0080 void write_ppm(libraw_processed_image_t *img, const char *basename)
0081 {
0082   if (!img)
0083     return;
0084   // type SHOULD be LIBRAW_IMAGE_BITMAP, but we'll check
0085   if (img->type != LIBRAW_IMAGE_BITMAP)
0086     return;
0087   if (img->colors != 3 && img->colors != 1)
0088   {
0089     printf("Only monochrome and 3-color images supported for PPM output\n");
0090     return;
0091    }
0092 
0093   char fn[1024];
0094   snprintf(fn, 1024, "%s.p%cm", basename, img->colors==1?'g':'p');
0095   FILE *f = fopen(fn, "wb");
0096   if (!f)
0097     return;
0098   fprintf(f, "P%d\n%d %d\n%d\n", img->colors/2 + 5, img->width, img->height, (1 << img->bits) - 1);
0099 /*
0100   NOTE:
0101   data in img->data is not converted to network byte order.
0102   So, we should swap values on some architectures for dcraw compatibility
0103   (unfortunately, xv cannot display 16-bit PPMs with network byte order data
0104 */
0105 #define SWAP(a, b)                                                             \
0106   {                                                                            \
0107     a ^= b;                                                                    \
0108     a ^= (b ^= a);                                                             \
0109   }
0110   if (img->bits == 16 && htons(0x55aa) != 0x55aa)
0111     for (unsigned i = 0; i < img->data_size-1; i += 2)
0112       SWAP(img->data[i], img->data[i + 1]);
0113 #undef SWAP
0114 
0115   fwrite(img->data, img->data_size, 1, f);
0116   fclose(f);
0117 }
0118 
0119 void write_thumb(libraw_processed_image_t *img, const char *basename)
0120 {
0121   if (!img)
0122     return;
0123 
0124   if (img->type == LIBRAW_IMAGE_BITMAP)
0125   {
0126     char fnt[1024];
0127     snprintf(fnt, 1024, "%s.thumb", basename);
0128     write_ppm(img, fnt);
0129   }
0130   else if (img->type == LIBRAW_IMAGE_JPEG)
0131   {
0132     char fn[1024];
0133     snprintf(fn, 1024, "%s.thumb.jpg", basename);
0134     FILE *f = fopen(fn, "wb");
0135     if (!f)
0136       return;
0137     fwrite(img->data, img->data_size, 1, f);
0138     fclose(f);
0139   }
0140 }
0141 
0142 int main(int ac, char *av[])
0143 {
0144   int i, ret, output_thumbs = 0;
0145 #ifdef USE_JPEG
0146   int output_jpeg = 0, jpgqual = 90;
0147 #endif
0148   // don't use fixed size buffers in real apps!
0149 
0150   LibRaw RawProcessor;
0151 
0152   if (ac < 2)
0153   {
0154     printf("mem_image - LibRaw sample, to illustrate work for memory buffers.\n"
0155            "Emulates dcraw [-4] [-1] [-e] [-h]\n"
0156 #ifdef USE_JPEG
0157            "Usage: %s [-D] [-j[nn]] [-T] [-v] [-e] raw-files....\n"
0158 #else
0159            "Usage: %s [-D] [-T] [-v] [-e] raw-files....\n"
0160 #endif
0161            "\t-6 - output 16-bit PPM\n"
0162            "\t-4 - linear 16-bit data\n"
0163            "\t-e - extract thumbnails (same as dcraw -e in separate run)\n"
0164 #ifdef USE_JPEG
0165            "\t-j[qual] - output JPEG with qual quality (e.g. -j90)\n"
0166 #endif
0167            "\t-h - use half_size\n", av[0]);
0168     return 0;
0169   }
0170 
0171   putenv((char *)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field
0172 
0173 #define P1 RawProcessor.imgdata.idata
0174 #define S RawProcessor.imgdata.sizes
0175 #define C RawProcessor.imgdata.color
0176 #define T RawProcessor.imgdata.thumbnail
0177 #define P2 RawProcessor.imgdata.other
0178 #define OUT RawProcessor.imgdata.params
0179 
0180   for (i = 1; i < ac; i++)
0181   {
0182     if (av[i][0] == '-')
0183     {
0184       if (av[i][1] == '6' && av[i][2] == 0)
0185         OUT.output_bps = 16;
0186       if (av[i][1] == '4' && av[i][2] == 0)
0187       {
0188         OUT.output_bps = 16;
0189         OUT.gamm[0] = OUT.gamm[1] = OUT.no_auto_bright = 1;
0190       }
0191       if (av[i][1] == 'e' && av[i][2] == 0)
0192         output_thumbs++;
0193       if (av[i][1] == 'h' && av[i][2] == 0)
0194         OUT.half_size = 1;
0195 #ifdef USE_JPEG
0196       if (av[i][1] == 'j')
0197       {
0198         output_jpeg = 1;
0199         if(av[i][2] != 0)
0200         jpgqual = atoi(av[i]+2);
0201       } 
0202 #endif
0203       continue;
0204     }
0205 #ifdef USE_JPEG
0206     if(output_jpeg && OUT.output_bps>8)
0207     {
0208       printf("JPEG is limited to 8 bit\n");
0209       OUT.output_bps = 8;
0210     }
0211 #endif
0212     printf("Processing %s\n", av[i]);
0213     if ((ret = RawProcessor.open_file(av[i])) != LIBRAW_SUCCESS)
0214     {
0215       fprintf(stderr, "Cannot open %s: %s\n", av[i], libraw_strerror(ret));
0216       continue; // no recycle b/c open file will recycle itself
0217     }
0218 
0219     if ((ret = RawProcessor.unpack()) != LIBRAW_SUCCESS)
0220     {
0221       fprintf(stderr, "Cannot unpack %s: %s\n", av[i], libraw_strerror(ret));
0222       continue;
0223     }
0224 
0225     // we should call dcraw_process before thumbnail extraction because for
0226     // some cameras (i.e. Kodak ones) white balance for thumbnail should be set
0227     // from main image settings
0228 
0229     ret = RawProcessor.dcraw_process();
0230 
0231     if (LIBRAW_SUCCESS != ret)
0232     {
0233       fprintf(stderr, "Cannot do postprocessing on %s: %s\n", av[i],
0234               libraw_strerror(ret));
0235       if (LIBRAW_FATAL_ERROR(ret))
0236         continue;
0237     }
0238     libraw_processed_image_t *image = RawProcessor.dcraw_make_mem_image(&ret);
0239     if (image)
0240     {
0241 #ifdef USE_JPEG
0242       if(output_jpeg)
0243         write_jpeg(image, av[i], jpgqual);
0244       else
0245 #endif
0246         write_ppm(image, av[i]);
0247       LibRaw::dcraw_clear_mem(image);
0248     }
0249     else
0250       fprintf(stderr, "Cannot unpack %s to memory buffer: %s\n", av[i],
0251               libraw_strerror(ret));
0252 
0253     if (output_thumbs)
0254     {
0255 
0256       if ((ret = RawProcessor.unpack_thumb()) != LIBRAW_SUCCESS)
0257       {
0258         fprintf(stderr, "Cannot unpack_thumb %s: %s\n", av[i],
0259                 libraw_strerror(ret));
0260         if (LIBRAW_FATAL_ERROR(ret))
0261           continue; // skip to next file
0262       }
0263       else
0264       {
0265         libraw_processed_image_t *thumb =
0266             RawProcessor.dcraw_make_mem_thumb(&ret);
0267         if (thumb)
0268         {
0269           write_thumb(thumb, av[i]);
0270           LibRaw::dcraw_clear_mem(thumb);
0271         }
0272         else
0273           fprintf(stderr,
0274                   "Cannot unpack thumbnail of %s to memory buffer: %s\n", av[i],
0275                   libraw_strerror(ret));
0276       }
0277     }
0278 
0279     RawProcessor.recycle(); // just for show this call
0280   }
0281   return 0;
0282 }