1 /* -*- C++ -*-
2 * File: mem_image.cpp
3 * Copyright 2008-2021 LibRaw LLC (info@libraw.org)
4 *
5 * LibRaw mem_image/mem_thumb API test. Results should be same (bitwise) to
6 dcraw [-4] [-6] [-e]
7 * Testing note: for ppm-thumbnails you should use dcraw -w -e for thumbnail
8 extraction
9
10 LibRaw is free software; you can redistribute it and/or modify
11 it under the terms of the one of two licenses as you choose:
12
13 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
14 (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
15
16 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
17 (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
18
19
20 */
21 #include <stdio.h>
22 #include <string.h>
23 #include <math.h>
24
25 #include "libraw/libraw.h"
26
27 #ifdef USE_JPEG
28 #include "jpeglib.h"
29 #endif
30
31 #ifdef LIBRAW_WIN32_CALLS
32 #define snprintf _snprintf
33 #include <winsock2.h>
34 #pragma comment(lib, "ws2_32.lib")
35 #else
36 #include <netinet/in.h>
37 #endif
38
39 #ifdef USE_JPEG
write_jpeg(libraw_processed_image_t * img,const char * basename,int quality)40 void write_jpeg(libraw_processed_image_t *img, const char *basename, int quality)
41 {
42 char fn[1024];
43 if(img->colors != 1 && img->colors != 3)
44 {
45 printf("Only BW and 3-color images supported for JPEG output\n");
46 return;
47 }
48 snprintf(fn, 1024, "%s.jpg", basename);
49 FILE *f = fopen(fn, "wb");
50 if (!f)
51 return;
52 struct jpeg_compress_struct cinfo;
53 struct jpeg_error_mgr jerr;
54 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
55 int row_stride; /* physical row width in image buffer */
56
57 cinfo.err = jpeg_std_error(&jerr);
58 jpeg_create_compress(&cinfo);
59 jpeg_stdio_dest(&cinfo, f);
60 cinfo.image_width = img->width; /* image width and height, in pixels */
61 cinfo.image_height = img->height;
62 cinfo.input_components = img->colors; /* # of color components per pixel */
63 cinfo.in_color_space = img->colors==3?JCS_RGB:JCS_GRAYSCALE; /* colorspace of input image */
64 jpeg_set_defaults(&cinfo);
65 jpeg_set_quality(&cinfo, quality, TRUE);
66 jpeg_start_compress(&cinfo, TRUE);
67 row_stride = img->width * img->colors; /* JSAMPLEs per row in image_buffer */
68 while (cinfo.next_scanline < cinfo.image_height) {
69 row_pointer[0] = &img->data[cinfo.next_scanline * row_stride];
70 (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
71 }
72 jpeg_finish_compress(&cinfo);
73 fclose(f);
74 jpeg_destroy_compress(&cinfo);
75 }
76
77 #endif
78
79 // no error reporting, only params check
write_ppm(libraw_processed_image_t * img,const char * basename)80 void write_ppm(libraw_processed_image_t *img, const char *basename)
81 {
82 if (!img)
83 return;
84 // type SHOULD be LIBRAW_IMAGE_BITMAP, but we'll check
85 if (img->type != LIBRAW_IMAGE_BITMAP)
86 return;
87 if (img->colors != 3 && img->colors != 1)
88 {
89 printf("Only monochrome and 3-color images supported for PPM output\n");
90 return;
91 }
92
93 char fn[1024];
94 snprintf(fn, 1024, "%s.p%cm", basename, img->colors==1?'g':'p');
95 FILE *f = fopen(fn, "wb");
96 if (!f)
97 return;
98 fprintf(f, "P%d\n%d %d\n%d\n", img->colors/2 + 5, img->width, img->height, (1 << img->bits) - 1);
99 /*
100 NOTE:
101 data in img->data is not converted to network byte order.
102 So, we should swap values on some architectures for dcraw compatibility
103 (unfortunately, xv cannot display 16-bit PPMs with network byte order data
104 */
105 #define SWAP(a, b) \
106 { \
107 a ^= b; \
108 a ^= (b ^= a); \
109 }
110 if (img->bits == 16 && htons(0x55aa) != 0x55aa)
111 for (unsigned i = 0; i < img->data_size-1; i += 2)
112 SWAP(img->data[i], img->data[i + 1]);
113 #undef SWAP
114
115 fwrite(img->data, img->data_size, 1, f);
116 fclose(f);
117 }
118
write_thumb(libraw_processed_image_t * img,const char * basename)119 void write_thumb(libraw_processed_image_t *img, const char *basename)
120 {
121 if (!img)
122 return;
123
124 if (img->type == LIBRAW_IMAGE_BITMAP)
125 {
126 char fnt[1024];
127 snprintf(fnt, 1024, "%s.thumb", basename);
128 write_ppm(img, fnt);
129 }
130 else if (img->type == LIBRAW_IMAGE_JPEG)
131 {
132 char fn[1024];
133 snprintf(fn, 1024, "%s.thumb.jpg", basename);
134 FILE *f = fopen(fn, "wb");
135 if (!f)
136 return;
137 fwrite(img->data, img->data_size, 1, f);
138 fclose(f);
139 }
140 }
141
main(int ac,char * av[])142 int main(int ac, char *av[])
143 {
144 int i, ret, output_thumbs = 0;
145 #ifdef USE_JPEG
146 int output_jpeg = 0, jpgqual = 90;
147 #endif
148 // don't use fixed size buffers in real apps!
149
150 LibRaw RawProcessor;
151
152 if (ac < 2)
153 {
154 printf("mem_image - LibRaw sample, to illustrate work for memory buffers.\n"
155 "Emulates dcraw [-4] [-1] [-e] [-h]\n"
156 #ifdef USE_JPEG
157 "Usage: %s [-D] [-j[nn]] [-T] [-v] [-e] raw-files....\n"
158 #else
159 "Usage: %s [-D] [-T] [-v] [-e] raw-files....\n"
160 #endif
161 "\t-6 - output 16-bit PPM\n"
162 "\t-4 - linear 16-bit data\n"
163 "\t-e - extract thumbnails (same as dcraw -e in separate run)\n"
164 #ifdef USE_JPEG
165 "\t-j[qual] - output JPEG with qual quality (e.g. -j90)\n"
166 #endif
167 "\t-h - use half_size\n", av[0]);
168 return 0;
169 }
170
171 putenv((char *)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field
172
173 #define P1 RawProcessor.imgdata.idata
174 #define S RawProcessor.imgdata.sizes
175 #define C RawProcessor.imgdata.color
176 #define T RawProcessor.imgdata.thumbnail
177 #define P2 RawProcessor.imgdata.other
178 #define OUT RawProcessor.imgdata.params
179
180 for (i = 1; i < ac; i++)
181 {
182 if (av[i][0] == '-')
183 {
184 if (av[i][1] == '6' && av[i][2] == 0)
185 OUT.output_bps = 16;
186 if (av[i][1] == '4' && av[i][2] == 0)
187 {
188 OUT.output_bps = 16;
189 OUT.gamm[0] = OUT.gamm[1] = OUT.no_auto_bright = 1;
190 }
191 if (av[i][1] == 'e' && av[i][2] == 0)
192 output_thumbs++;
193 if (av[i][1] == 'h' && av[i][2] == 0)
194 OUT.half_size = 1;
195 #ifdef USE_JPEG
196 if (av[i][1] == 'j')
197 {
198 output_jpeg = 1;
199 if(av[i][2] != 0)
200 jpgqual = atoi(av[i]+2);
201 }
202 #endif
203 continue;
204 }
205 #ifdef USE_JPEG
206 if(output_jpeg && OUT.output_bps>8)
207 {
208 printf("JPEG is limited to 8 bit\n");
209 OUT.output_bps = 8;
210 }
211 #endif
212 printf("Processing %s\n", av[i]);
213 if ((ret = RawProcessor.open_file(av[i])) != LIBRAW_SUCCESS)
214 {
215 fprintf(stderr, "Cannot open %s: %s\n", av[i], libraw_strerror(ret));
216 continue; // no recycle b/c open file will recycle itself
217 }
218
219 if ((ret = RawProcessor.unpack()) != LIBRAW_SUCCESS)
220 {
221 fprintf(stderr, "Cannot unpack %s: %s\n", av[i], libraw_strerror(ret));
222 continue;
223 }
224
225 // we should call dcraw_process before thumbnail extraction because for
226 // some cameras (i.e. Kodak ones) white balance for thumbnal should be set
227 // from main image settings
228
229 ret = RawProcessor.dcraw_process();
230
231 if (LIBRAW_SUCCESS != ret)
232 {
233 fprintf(stderr, "Cannot do postpocessing on %s: %s\n", av[i],
234 libraw_strerror(ret));
235 if (LIBRAW_FATAL_ERROR(ret))
236 continue;
237 }
238 libraw_processed_image_t *image = RawProcessor.dcraw_make_mem_image(&ret);
239 if (image)
240 {
241 #ifdef USE_JPEG
242 if(output_jpeg)
243 write_jpeg(image, av[i], jpgqual);
244 else
245 #endif
246 write_ppm(image, av[i]);
247 LibRaw::dcraw_clear_mem(image);
248 }
249 else
250 fprintf(stderr, "Cannot unpack %s to memory buffer: %s\n", av[i],
251 libraw_strerror(ret));
252
253 if (output_thumbs)
254 {
255
256 if ((ret = RawProcessor.unpack_thumb()) != LIBRAW_SUCCESS)
257 {
258 fprintf(stderr, "Cannot unpack_thumb %s: %s\n", av[i],
259 libraw_strerror(ret));
260 if (LIBRAW_FATAL_ERROR(ret))
261 continue; // skip to next file
262 }
263 else
264 {
265 libraw_processed_image_t *thumb =
266 RawProcessor.dcraw_make_mem_thumb(&ret);
267 if (thumb)
268 {
269 write_thumb(thumb, av[i]);
270 LibRaw::dcraw_clear_mem(thumb);
271 }
272 else
273 fprintf(stderr,
274 "Cannot unpack thumbnail of %s to memory buffer: %s\n", av[i],
275 libraw_strerror(ret));
276 }
277 }
278
279 RawProcessor.recycle(); // just for show this call
280 }
281 return 0;
282 }
283