Tachyon (current)  Current Main Branch
jpeg.c
Go to the documentation of this file.
1 /*
2  * jpeg.c - This file deals with JPEG format image files (reading/writing)
3  *
4  * (C) Copyright 1994-2022 John E. Stone
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * $Id: jpeg.c,v 1.10 2022/02/18 17:55:28 johns Exp $
8  *
9  */
10 
11 /*
12  * This code requires support from the Independent JPEG Group's libjpeg.
13  * For our purposes, we're interested only in the 3 byte per pixel 24 bit
14  * RGB output. Probably won't implement any decent checking at this point.
15  */
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <math.h>
20 
21 #define TACHYON_INTERNAL 1
22 #include "tachyon.h"
23 #include "util.h"
24 #include "imageio.h" /* error codes etc */
25 #include "jpeg.h" /* the protos for this file */
26 
27 #if !defined(USEJPEG)
28 
29 int readjpeg(const char *name, int *xres, int *yres, unsigned char **imgdata) {
30  return IMAGEUNSUP;
31 }
32 
33 int writejpeg(const char *name, int xres, int yres, unsigned char *imgdata) {
34  return IMAGEUNSUP;
35 }
36 
37 #else
38 
39 #include "jpeglib.h" /* the IJG jpeg library headers */
40 
41 int readjpeg(const char *name, int *xres, int *yres, unsigned char **imgdata) {
42  FILE * ifp;
43  struct jpeg_decompress_struct cinfo; /* JPEG decompression struct */
44  struct jpeg_error_mgr jerr; /* JPEG Error handler */
45  JSAMPROW row_pointer[1]; /* output row buffer */
46  int row_stride; /* physical row width in output buf */
47 
48  /* open input file before doing any JPEG decompression setup */
49  if ((ifp = fopen(name, "rb")) == NULL)
50  return IMAGEBADFILE; /* Could not open image, return error */
51 
52  /*
53  * Note: The Independent JPEG Group's library does not have a way
54  * of returning errors without the use of setjmp/longjmp.
55  * This is a problem in multi-threaded environment, since setjmp
56  * and longjmp are declared thread-unsafe by many vendors currently.
57  * For now, JPEG decompression errors will result in the "default"
58  * error handling provided by the JPEG library, which is an error
59  * message and a fatal call to exit(). I'll have to work around this
60  * or find a reasonably thread-safe way of doing setjmp/longjmp..
61  */
62 
63  cinfo.err = jpeg_std_error(&jerr); /* Set JPEG error handler to default */
64 
65  jpeg_create_decompress(&cinfo); /* Create decompression context */
66  jpeg_stdio_src(&cinfo, ifp); /* Set input mechanism to stdio type */
67  jpeg_read_header(&cinfo, TRUE); /* Read the JPEG header for info */
68  jpeg_start_decompress(&cinfo); /* Prepare for actual decompression */
69 
70  *xres = cinfo.output_width; /* set returned image width */
71  *yres = cinfo.output_height; /* set returned image height */
72 
73  /* Calculate the size of a row in the image */
74  row_stride = cinfo.output_width * cinfo.output_components;
75 
76  /* Allocate the image buffer which will be returned to the caller */
77  *imgdata = (unsigned char *) malloc(row_stride * cinfo.output_height);
78 
79  /* decompress the JPEG, one scanline at a time into the buffer */
80  while (cinfo.output_scanline < cinfo.output_height) {
81  row_pointer[0] = &((*imgdata)[(cinfo.output_scanline)*row_stride]);
82  jpeg_read_scanlines(&cinfo, row_pointer, 1);
83  }
84 
85  jpeg_finish_decompress(&cinfo); /* Tell the JPEG library to cleanup */
86  jpeg_destroy_decompress(&cinfo); /* Destroy JPEG decompression context */
87 
88  fclose(ifp); /* Close the input file */
89 
90  return IMAGENOERR; /* No fatal errors */
91 }
92 
93 
94 int writejpeg(const char *name, int xres, int yres, unsigned char *imgdata) {
95  FILE *ofp;
96  struct jpeg_compress_struct cinfo; /* JPEG compression struct */
97  struct jpeg_error_mgr jerr; /* JPEG error handler */
98  JSAMPROW row_pointer[1]; /* output row buffer */
99  int row_stride; /* physical row width in output buf */
100 
101  if ((ofp = fopen(name, "wb")) == NULL) {
102  return IMAGEBADFILE;
103  }
104 
105  cinfo.err = jpeg_std_error(&jerr);
106  jpeg_create_compress(&cinfo);
107  jpeg_stdio_dest(&cinfo, ofp);
108 
109  cinfo.image_width = xres;
110  cinfo.image_height = yres;
111  cinfo.input_components = 3;
112  cinfo.in_color_space = JCS_RGB;
113 
114  jpeg_set_defaults(&cinfo);
115  jpeg_set_quality(&cinfo, 95, 0);
116 
117  jpeg_start_compress(&cinfo, TRUE);
118 
119  /* Calculate the size of a row in the image */
120  row_stride = cinfo.image_width * cinfo.input_components;
121 
122  /* compress the JPEG, one scanline at a time into the buffer */
123  while (cinfo.next_scanline < cinfo.image_height) {
124  row_pointer[0] = &(imgdata[(yres - cinfo.next_scanline - 1)*row_stride]);
125  jpeg_write_scanlines(&cinfo, row_pointer, 1);
126  }
127 
128  jpeg_finish_compress(&cinfo);
129  jpeg_destroy_compress(&cinfo);
130 
131  fclose(ofp);
132 
133  return IMAGENOERR; /* No fatal errors */
134 }
135 
136 #endif
#define IMAGEUNSUP
the image file is an unsupported format
Definition: imageio.h:18
int readjpeg(const char *name, int *xres, int *yres, unsigned char **imgdata)
Definition: jpeg.c:29
int writejpeg(const char *name, int xres, int yres, unsigned char *imgdata)
Definition: jpeg.c:33
Tachyon cross-platform timers, special math function wrappers, and RNGs.
#define IMAGENOERR
no error
Definition: imageio.h:16
Tachyon public API function prototypes and declarations used to drive the ray tracing engine...
#define IMAGEBADFILE
can&#39;t find or can&#39;t open the file
Definition: imageio.h:17