if(WITH_TURBOJPEG)
if(ENABLE_SHARED)
set(TURBOJPEG_SOURCES ${JPEG_SOURCES} $<TARGET_OBJECTS:simd> ${SIMD_OBJS}
- turbojpeg.c transupp.c jdatadst-tj.c jdatasrc-tj.c)
+ turbojpeg.c transupp.c jdatadst-tj.c jdatasrc-tj.c rdbmp.c rdppm.c
+ wrbmp.c wrppm.c)
set(TJMAPFILE ${CMAKE_CURRENT_SOURCE_DIR}/turbojpeg-mapfile)
if(WITH_JAVA)
set(TURBOJPEG_SOURCES ${TURBOJPEG_SOURCES} turbojpeg-jni.c)
set(TJMAPFILE ${CMAKE_CURRENT_SOURCE_DIR}/turbojpeg-mapfile.jni)
endif()
add_library(turbojpeg SHARED ${TURBOJPEG_SOURCES})
+ set_property(TARGET turbojpeg PROPERTY COMPILE_FLAGS
+ "-DBMP_SUPPORTED -DPPM_SUPPORTED")
if(WIN32)
set_target_properties(turbojpeg PROPERTIES DEFINE_SYMBOL DLLDEFINE)
endif()
LINK_FLAGS "${TJMAPFLAG}${TJMAPFILE}")
endif()
- add_executable(tjunittest tjunittest.c tjutil.c)
+ add_executable(tjunittest tjunittest.c tjutil.c md5/md5.c md5/md5hl.c)
target_link_libraries(tjunittest turbojpeg)
- add_executable(tjbench tjbench.c bmp.c tjutil.c rdbmp.c rdppm.c wrbmp.c
- wrppm.c)
- target_link_libraries(tjbench turbojpeg jpeg)
+ add_executable(tjbench tjbench.c tjutil.c)
+ target_link_libraries(tjbench turbojpeg)
if(UNIX)
target_link_libraries(tjbench m)
endif()
- set_property(TARGET tjbench PROPERTY COMPILE_FLAGS
- "-DBMP_SUPPORTED -DPPM_SUPPORTED")
endif()
if(ENABLE_STATIC)
add_library(turbojpeg-static STATIC ${JPEG_SOURCES} $<TARGET_OBJECTS:simd>
- ${SIMD_OBJS} turbojpeg.c transupp.c jdatadst-tj.c jdatasrc-tj.c)
+ ${SIMD_OBJS} turbojpeg.c transupp.c jdatadst-tj.c jdatasrc-tj.c rdbmp.c
+ rdppm.c wrbmp.c wrppm.c)
+ set_property(TARGET turbojpeg-static PROPERTY COMPILE_FLAGS
+ "-DBMP_SUPPORTED -DPPM_SUPPORTED")
if(NOT MSVC)
set_target_properties(turbojpeg-static PROPERTIES OUTPUT_NAME turbojpeg)
endif()
- add_executable(tjunittest-static tjunittest.c tjutil.c)
+ add_executable(tjunittest-static tjunittest.c tjutil.c md5/md5.c
+ md5/md5hl.c)
target_link_libraries(tjunittest-static turbojpeg-static)
- add_executable(tjbench-static tjbench.c bmp.c tjutil.c rdbmp.c rdppm.c
- wrbmp.c wrppm.c)
- target_link_libraries(tjbench-static turbojpeg-static jpeg-static)
+ add_executable(tjbench-static tjbench.c tjutil.c)
+ target_link_libraries(tjbench-static turbojpeg-static)
if(UNIX)
target_link_libraries(tjbench-static m)
endif()
- set_property(TARGET tjbench-static PROPERTY COMPILE_FLAGS
- "-DBMP_SUPPORTED -DPPM_SUPPORTED")
endif()
endif()
add_test(tjunittest-${libtype}-yuv tjunittest${suffix} -yuv)
add_test(tjunittest-${libtype}-yuv-alloc tjunittest${suffix} -yuv -alloc)
add_test(tjunittest-${libtype}-yuv-nopad tjunittest${suffix} -yuv -noyuvpad)
+ add_test(tjunittest-${libtype}-bmp tjunittest${suffix} -bmp)
set(MD5_PPM_GRAY_TILE 89d3ca21213d9d864b50b4e4e7de4ca6)
set(MD5_PPM_420_8x8_TILE 847fceab15c5b7b911cb986cf0f71de3)
occurred when attempting to decompress a JPEG image that had been compressed
with 4:1:1 chrominance subsampling.
+14. Added two functions to the TurboJPEG C API (`tjLoadImage()` and
+`tjSaveImage()`) that can be used to load/save a BMP or PPM/PGM image to/from a
+memory buffer with a specified pixel format and layout. These functions
+replace the project-private (and slow) bmp API, which was previously used by
+TJBench, and they also provide a convenient way for first-time users of
+libjpeg-turbo to quickly develop a complete JPEG compression/decompression
+program.
+
1.5.2
=====
+++ /dev/null
-/*
- * Copyright (C)2011, 2015 D. R. Commander. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * - Neither the name of the libjpeg-turbo Project nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <setjmp.h>
-#include <errno.h>
-#include "cdjpeg.h"
-#include <jpeglib.h>
-#include <jpegint.h>
-#include "tjutil.h"
-#include "bmp.h"
-
-
-/* This duplicates the functionality of the VirtualGL bitmap library using
- the components from cjpeg and djpeg */
-
-
-/* Error handling (based on example in example.c) */
-
-static char errStr[JMSG_LENGTH_MAX]="No error";
-
-struct my_error_mgr
-{
- struct jpeg_error_mgr pub;
- jmp_buf setjmp_buffer;
-};
-typedef struct my_error_mgr *my_error_ptr;
-
-static void my_error_exit(j_common_ptr cinfo)
-{
- my_error_ptr myerr=(my_error_ptr)cinfo->err;
- (*cinfo->err->output_message)(cinfo);
- longjmp(myerr->setjmp_buffer, 1);
-}
-
-/* Based on output_message() in jerror.c */
-
-static void my_output_message(j_common_ptr cinfo)
-{
- (*cinfo->err->format_message)(cinfo, errStr);
-}
-
-#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
- retval=-1; goto bailout;}
-#define _throwunix(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, \
- strerror(errno)); retval=-1; goto bailout;}
-
-
-static void pixelconvert(unsigned char *srcbuf, int srcpf, int srcbottomup,
- unsigned char *dstbuf, int dstpf, int dstbottomup, int w, int h)
-{
- unsigned char *srcrowptr=srcbuf, *srccolptr;
- int srcps=tjPixelSize[srcpf];
- int srcstride=srcbottomup? -w*srcps:w*srcps;
- unsigned char *dstrowptr=dstbuf, *dstcolptr;
- int dstps=tjPixelSize[dstpf];
- int dststride=dstbottomup? -w*dstps:w*dstps;
- int row, col;
-
- if(srcbottomup) srcrowptr=&srcbuf[w*srcps*(h-1)];
- if(dstbottomup) dstrowptr=&dstbuf[w*dstps*(h-1)];
-
- /* NOTE: These quick & dirty CMYK<->RGB conversion routines are for testing
- purposes only. Properly converting between CMYK and RGB requires a color
- management system. */
-
- if(dstpf==TJPF_CMYK)
- {
- for(row=0; row<h; row++, srcrowptr+=srcstride, dstrowptr+=dststride)
- {
- for(col=0, srccolptr=srcrowptr, dstcolptr=dstrowptr;
- col<w; col++, srccolptr+=srcps)
- {
- double c=1.0-((double)(srccolptr[tjRedOffset[srcpf]])/255.);
- double m=1.0-((double)(srccolptr[tjGreenOffset[srcpf]])/255.);
- double y=1.0-((double)(srccolptr[tjBlueOffset[srcpf]])/255.);
- double k=min(min(c,m),min(y,1.0));
- if(k==1.0) c=m=y=0.0;
- else
- {
- c=(c-k)/(1.0-k);
- m=(m-k)/(1.0-k);
- y=(y-k)/(1.0-k);
- }
- if(c>1.0) c=1.0;
- if(c<0.) c=0.;
- if(m>1.0) m=1.0;
- if(m<0.) m=0.;
- if(y>1.0) y=1.0;
- if(y<0.) y=0.;
- if(k>1.0) k=1.0;
- if(k<0.) k=0.;
- *dstcolptr++=(unsigned char)(255.0-c*255.0+0.5);
- *dstcolptr++=(unsigned char)(255.0-m*255.0+0.5);
- *dstcolptr++=(unsigned char)(255.0-y*255.0+0.5);
- *dstcolptr++=(unsigned char)(255.0-k*255.0+0.5);
- }
- }
- }
- else if(srcpf==TJPF_CMYK)
- {
- for(row=0; row<h; row++, srcrowptr+=srcstride, dstrowptr+=dststride)
- {
- for(col=0, srccolptr=srcrowptr, dstcolptr=dstrowptr;
- col<w; col++, dstcolptr+=dstps)
- {
- double c=(double)(*srccolptr++);
- double m=(double)(*srccolptr++);
- double y=(double)(*srccolptr++);
- double k=(double)(*srccolptr++);
- double r=c*k/255.;
- double g=m*k/255.;
- double b=y*k/255.;
- if(r>255.0) r=255.0;
- if(r<0.) r=0.;
- if(g>255.0) g=255.0;
- if(g<0.) g=0.;
- if(b>255.0) b=255.0;
- if(b<0.) b=0.;
- dstcolptr[tjRedOffset[dstpf]]=(unsigned char)(r+0.5);
- dstcolptr[tjGreenOffset[dstpf]]=(unsigned char)(g+0.5);
- dstcolptr[tjBlueOffset[dstpf]]=(unsigned char)(b+0.5);
- }
- }
- }
- else
- {
- for(row=0; row<h; row++, srcrowptr+=srcstride, dstrowptr+=dststride)
- {
- for(col=0, srccolptr=srcrowptr, dstcolptr=dstrowptr;
- col<w; col++, srccolptr+=srcps, dstcolptr+=dstps)
- {
- dstcolptr[tjRedOffset[dstpf]]=srccolptr[tjRedOffset[srcpf]];
- dstcolptr[tjGreenOffset[dstpf]]=srccolptr[tjGreenOffset[srcpf]];
- dstcolptr[tjBlueOffset[dstpf]]=srccolptr[tjBlueOffset[srcpf]];
- }
- }
- }
-}
-
-
-int loadbmp(char *filename, unsigned char **buf, int *w, int *h,
- int dstpf, int bottomup)
-{
- int retval=0, dstps, srcpf, tempc;
- struct jpeg_compress_struct cinfo;
- struct my_error_mgr jerr;
- cjpeg_source_ptr src;
- FILE *file=NULL;
-
- memset(&cinfo, 0, sizeof(struct jpeg_compress_struct));
-
- if(!filename || !buf || !w || !h || dstpf<0 || dstpf>=TJ_NUMPF)
- _throw("loadbmp(): Invalid argument");
-
- if((file=fopen(filename, "rb"))==NULL)
- _throwunix("loadbmp(): Cannot open input file");
-
- cinfo.err=jpeg_std_error(&jerr.pub);
- jerr.pub.error_exit=my_error_exit;
- jerr.pub.output_message=my_output_message;
-
- if(setjmp(jerr.setjmp_buffer))
- {
- /* If we get here, the JPEG code has signaled an error. */
- retval=-1; goto bailout;
- }
-
- jpeg_create_compress(&cinfo);
- if((tempc=getc(file))<0 || ungetc(tempc, file)==EOF)
- _throwunix("loadbmp(): Could not read input file")
- else if(tempc==EOF) _throw("loadbmp(): Input file contains no data");
-
- if(tempc=='B')
- {
- if((src=jinit_read_bmp(&cinfo))==NULL)
- _throw("loadbmp(): Could not initialize bitmap loader");
- }
- else if(tempc=='P')
- {
- if((src=jinit_read_ppm(&cinfo))==NULL)
- _throw("loadbmp(): Could not initialize bitmap loader");
- }
- else _throw("loadbmp(): Unsupported file type");
-
- src->input_file=file;
- (*src->start_input)(&cinfo, src);
- (*cinfo.mem->realize_virt_arrays)((j_common_ptr)&cinfo);
-
- *w=cinfo.image_width; *h=cinfo.image_height;
-
- if(cinfo.input_components==1 && cinfo.in_color_space==JCS_RGB)
- srcpf=TJPF_GRAY;
- else srcpf=TJPF_RGB;
-
- dstps=tjPixelSize[dstpf];
- if((*buf=(unsigned char *)malloc((*w)*(*h)*dstps))==NULL)
- _throw("loadbmp(): Memory allocation failure");
-
- while(cinfo.next_scanline<cinfo.image_height)
- {
- int i, nlines=(*src->get_pixel_rows)(&cinfo, src);
- for(i=0; i<nlines; i++)
- {
- unsigned char *outbuf; int row;
- row=cinfo.next_scanline+i;
- if(bottomup) outbuf=&(*buf)[((*h)-row-1)*(*w)*dstps];
- else outbuf=&(*buf)[row*(*w)*dstps];
- pixelconvert(src->buffer[i], srcpf, 0, outbuf, dstpf, bottomup, *w,
- nlines);
- }
- cinfo.next_scanline+=nlines;
- }
-
- (*src->finish_input)(&cinfo, src);
-
- bailout:
- jpeg_destroy_compress(&cinfo);
- if(file) fclose(file);
- if(retval<0 && buf && *buf) {free(*buf); *buf=NULL;}
- return retval;
-}
-
-
-int savebmp(char *filename, unsigned char *buf, int w, int h, int srcpf,
- int bottomup)
-{
- int retval=0, srcps, dstpf;
- struct jpeg_decompress_struct dinfo;
- struct my_error_mgr jerr;
- djpeg_dest_ptr dst;
- FILE *file=NULL;
- char *ptr=NULL;
-
- memset(&dinfo, 0, sizeof(struct jpeg_decompress_struct));
-
- if(!filename || !buf || w<1 || h<1 || srcpf<0 || srcpf>=TJ_NUMPF)
- _throw("savebmp(): Invalid argument");
-
- if((file=fopen(filename, "wb"))==NULL)
- _throwunix("savebmp(): Cannot open output file");
-
- dinfo.err=jpeg_std_error(&jerr.pub);
- jerr.pub.error_exit=my_error_exit;
- jerr.pub.output_message=my_output_message;
-
- if(setjmp(jerr.setjmp_buffer))
- {
- /* If we get here, the JPEG code has signaled an error. */
- retval=-1; goto bailout;
- }
-
- jpeg_create_decompress(&dinfo);
- if(srcpf==TJPF_GRAY)
- {
- dinfo.out_color_components=dinfo.output_components=1;
- dinfo.out_color_space=JCS_GRAYSCALE;
- }
- else
- {
- dinfo.out_color_components=dinfo.output_components=3;
- dinfo.out_color_space=JCS_RGB;
- }
- dinfo.image_width=w; dinfo.image_height=h;
- dinfo.global_state=DSTATE_READY;
- dinfo.scale_num=dinfo.scale_denom=1;
-
- ptr=strrchr(filename, '.');
- if(ptr && !strcasecmp(ptr, ".bmp"))
- {
- if((dst=jinit_write_bmp(&dinfo, 0))==NULL)
- _throw("savebmp(): Could not initialize bitmap writer");
- }
- else
- {
- if((dst=jinit_write_ppm(&dinfo))==NULL)
- _throw("savebmp(): Could not initialize PPM writer");
- }
-
- dst->output_file=file;
- (*dst->start_output)(&dinfo, dst);
- (*dinfo.mem->realize_virt_arrays)((j_common_ptr)&dinfo);
-
- if(srcpf==TJPF_GRAY) dstpf=srcpf;
- else dstpf=TJPF_RGB;
- srcps=tjPixelSize[srcpf];
-
- while(dinfo.output_scanline<dinfo.output_height)
- {
- int i, nlines=dst->buffer_height;
- for(i=0; i<nlines; i++)
- {
- unsigned char *inbuf; int row;
- row=dinfo.output_scanline+i;
- if(bottomup) inbuf=&buf[(h-row-1)*w*srcps];
- else inbuf=&buf[row*w*srcps];
- pixelconvert(inbuf, srcpf, bottomup, dst->buffer[i], dstpf, 0, w,
- nlines);
- }
- (*dst->put_pixel_rows)(&dinfo, dst, nlines);
- dinfo.output_scanline+=nlines;
- }
-
- (*dst->finish_output)(&dinfo, dst);
-
- bailout:
- jpeg_destroy_decompress(&dinfo);
- if(file) fclose(file);
- return retval;
-}
-
-const char *bmpgeterr(void)
-{
- return errStr;
-}
+++ /dev/null
-/*
- * Copyright (C)2011 D. R. Commander. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * - Neither the name of the libjpeg-turbo Project nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __BMP_H__
-#define __BMP_H__
-
-#include "./turbojpeg.h"
-
-int loadbmp(char *filename, unsigned char **buf, int *w, int *h, int pf,
- int bottomup);
-
-int savebmp(char *filename, unsigned char *buf, int w, int h, int pf,
- int bottomup);
-
-const char *bmpgeterr(void);
-
-#endif
/* Module selection routines for I/O modules. */
-EXTERN(cjpeg_source_ptr) jinit_read_bmp (j_compress_ptr cinfo);
+EXTERN(cjpeg_source_ptr) jinit_read_bmp (j_compress_ptr cinfo,
+ boolean use_inversion_array);
EXTERN(djpeg_dest_ptr) jinit_write_bmp (j_decompress_ptr cinfo,
- boolean is_os2);
+ boolean is_os2,
+ boolean use_inversion_array);
EXTERN(cjpeg_source_ptr) jinit_read_gif (j_compress_ptr cinfo);
EXTERN(djpeg_dest_ptr) jinit_write_gif (j_decompress_ptr cinfo);
EXTERN(cjpeg_source_ptr) jinit_read_ppm (j_compress_ptr cinfo);
#ifndef EXIT_WARNING
#define EXIT_WARNING 2
#endif
+
+#define RGB2GRAY(r, g, b) \
+ (JSAMPLE)((double)(r) * 0.299 + (double)(g) * 0.587 + \
+ (double)(b) * 0.114 + 0.5)
+
+#define IsExtRGB(cs) \
+ (cs == JCS_RGB || (cs >= JCS_EXT_RGB && cs <= JCS_EXT_ARGB))
switch (c) {
#ifdef BMP_SUPPORTED
case 'B':
- return jinit_read_bmp(cinfo);
+ return jinit_read_bmp(cinfo, TRUE);
#endif
#ifdef GIF_SUPPORTED
case 'G':
--- /dev/null
+/*
+ * cmyk.h
+ *
+ * Copyright (C) 2017, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains convenience functions for performing quick & dirty
+ * CMYK<->RGB conversion. This algorithm is suitable for testing purposes
+ * only. Properly converting between CMYK and RGB requires a color management
+ * system.
+ */
+
+#include <jpeglib.h>
+#include "jconfigint.h"
+
+#ifndef CMYK_H
+#define CMYK_H
+
+
+#ifndef min
+ #define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+
+/* Fully reversible */
+
+INLINE
+LOCAL(void)
+rgb_to_cmyk(JSAMPLE r, JSAMPLE g, JSAMPLE b, JSAMPLE *c, JSAMPLE *m,
+ JSAMPLE *y, JSAMPLE *k)
+{
+ double ctmp = 1.0 - ((double)r / 255.0);
+ double mtmp = 1.0 - ((double)g / 255.0);
+ double ytmp = 1.0 - ((double)b / 255.0);
+ double ktmp = min(min(ctmp, mtmp), ytmp);
+
+ if (ktmp == 1.0) ctmp = mtmp = ytmp = 0.0;
+ else {
+ ctmp = (ctmp - ktmp) / (1.0 - ktmp);
+ mtmp = (mtmp - ktmp) / (1.0 - ktmp);
+ ytmp = (ytmp - ktmp) / (1.0 - ktmp);
+ }
+ *c = (JSAMPLE)(255.0 - ctmp * 255.0 + 0.5);
+ *m = (JSAMPLE)(255.0 - mtmp * 255.0 + 0.5);
+ *y = (JSAMPLE)(255.0 - ytmp * 255.0 + 0.5);
+ *k = (JSAMPLE)(255.0 - ktmp * 255.0 + 0.5);
+}
+
+
+/* Fully reversible only for C/M/Y/K values generated with rgb_to_cmyk() */
+
+INLINE
+LOCAL(void)
+cmyk_to_rgb(JSAMPLE c, JSAMPLE m, JSAMPLE y, JSAMPLE k, JSAMPLE *r, JSAMPLE *g,
+ JSAMPLE *b)
+{
+ *r = (JSAMPLE)((double)c * (double)k / 255.0 + 0.5);
+ *g = (JSAMPLE)((double)m * (double)k / 255.0 + 0.5);
+ *b = (JSAMPLE)((double)y * (double)k / 255.0 + 0.5);
+}
+
+
+#endif /* CMYK_H */
switch (requested_fmt) {
#ifdef BMP_SUPPORTED
case FMT_BMP:
- dest_mgr = jinit_write_bmp(&cinfo, FALSE);
+ dest_mgr = jinit_write_bmp(&cinfo, FALSE, TRUE);
break;
case FMT_OS2:
- dest_mgr = jinit_write_bmp(&cinfo, TRUE);
+ dest_mgr = jinit_write_bmp(&cinfo, TRUE, TRUE);
break;
#endif
#ifdef GIF_SUPPORTED
  <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aac037ff1845cf9b74bb81a3659c2b9fb4">TJPF_BGRA</a>,
<a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa1ba1a7f1631dbeaa49a0a85fc4a40081">TJPF_ABGR</a>,
<a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aae8f846ed9d9de99b6e1dfe448848765c">TJPF_ARGB</a>,
-<a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b">TJPF_CMYK</a>
+<a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b">TJPF_CMYK</a>,
+<br/>
+  <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa84c1a6cead7952998e2fb895844a21ed">TJPF_UNKNOWN</a>
<br/>
}</td></tr>
<tr class="memdesc:gac916144e26c3817ac514e64ae5d12e2a"><td class="mdescLeft"> </td><td class="mdescRight">Pixel formats. <a href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">More...</a><br/></td></tr>
<tr class="memitem:ga5c9234bda6d993cdaffdd89bf81a00ff"><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned char *DLLCALL </td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga5c9234bda6d993cdaffdd89bf81a00ff">tjAlloc</a> (int bytes)</td></tr>
<tr class="memdesc:ga5c9234bda6d993cdaffdd89bf81a00ff"><td class="mdescLeft"> </td><td class="mdescRight">Allocate an image buffer for use with TurboJPEG. <a href="#ga5c9234bda6d993cdaffdd89bf81a00ff">More...</a><br/></td></tr>
<tr class="separator:ga5c9234bda6d993cdaffdd89bf81a00ff"><td class="memSeparator" colspan="2"> </td></tr>
+<tr class="memitem:ga144b981d6b281ecca4cbb4709de75749"><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned char *DLLCALL </td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga144b981d6b281ecca4cbb4709de75749">tjLoadImage</a> (const char *filename, int *width, int align, int *height, int *pixelFormat, int flags)</td></tr>
+<tr class="memdesc:ga144b981d6b281ecca4cbb4709de75749"><td class="mdescLeft"> </td><td class="mdescRight">Load an uncompressed image from disk into memory. <a href="#ga144b981d6b281ecca4cbb4709de75749">More...</a><br/></td></tr>
+<tr class="separator:ga144b981d6b281ecca4cbb4709de75749"><td class="memSeparator" colspan="2"> </td></tr>
+<tr class="memitem:ga2e78b7b79796e74584028da880a6a29c"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL </td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga2e78b7b79796e74584028da880a6a29c">tjSaveImage</a> (const char *filename, unsigned char *buffer, int width, int pitch, int height, int pixelFormat, int flags)</td></tr>
+<tr class="memdesc:ga2e78b7b79796e74584028da880a6a29c"><td class="mdescLeft"> </td><td class="mdescRight">Save an uncompressed image from memory to disk. <a href="#ga2e78b7b79796e74584028da880a6a29c">More...</a><br/></td></tr>
+<tr class="separator:ga2e78b7b79796e74584028da880a6a29c"><td class="memSeparator" colspan="2"> </td></tr>
<tr class="memitem:ga8c4a1231dc06a450514c835f6471f137"><td class="memItemLeft" align="right" valign="top">DLLEXPORT void DLLCALL </td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga8c4a1231dc06a450514c835f6471f137">tjFree</a> (unsigned char *buffer)</td></tr>
<tr class="memdesc:ga8c4a1231dc06a450514c835f6471f137"><td class="mdescLeft"> </td><td class="mdescRight">Free an image buffer previously allocated by TurboJPEG. <a href="#ga8c4a1231dc06a450514c835f6471f137">More...</a><br/></td></tr>
<tr class="separator:ga8c4a1231dc06a450514c835f6471f137"><td class="memSeparator" colspan="2"> </td></tr>
<p>CMYK pixel format. </p>
<p>Unlike RGB, which is an additive color model used primarily for display, CMYK (Cyan/Magenta/Yellow/Key) is a subtractive color model used primarily for printing. In the CMYK color model, the value of each color component typically corresponds to an amount of cyan, magenta, yellow, or black ink that is applied to a white background. In order to convert between CMYK and RGB, it is necessary to use a color management system (CMS.) A CMS will attempt to map colors within the printer's gamut to perceptually similar colors in the display's gamut and vice versa, but the mapping is typically not 1:1 or reversible, nor can it be defined with a simple formula. Thus, such a conversion is out of scope for a codec library. However, the TurboJPEG API allows for compressing CMYK pixels into a YCCK JPEG image (see <a class="el" href="group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a53839e0fe867b76b58d16b0a1a7c598e" title="YCCK colorspace.">TJCS_YCCK</a>) and decompressing YCCK JPEG images into CMYK pixels. </p>
</td></tr>
+<tr><td class="fieldname"><em><a class="anchor" id="ggac916144e26c3817ac514e64ae5d12e2aa84c1a6cead7952998e2fb895844a21ed"></a>TJPF_UNKNOWN</em> </td><td class="fielddoc">
+<p>Unknown pixel format. </p>
+<p>Currently this is only used by <a class="el" href="group___turbo_j_p_e_g.html#ga144b981d6b281ecca4cbb4709de75749" title="Load an uncompressed image from disk into memory.">tjLoadImage()</a>. </p>
+</td></tr>
</table>
</div>
<p>Create a new TurboJPEG transformer instance. </p>
<dl class="section return"><dt>Returns</dt><dd>a handle to the newly-created instance, or NULL if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga94a235bd4f1088f61ad87b4eadb64c9c" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a>.) </dd></dl>
+</div>
+</div>
+<a class="anchor" id="ga144b981d6b281ecca4cbb4709de75749"></a>
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">DLLEXPORT unsigned char* DLLCALL tjLoadImage </td>
+ <td>(</td>
+ <td class="paramtype">const char * </td>
+ <td class="paramname"><em>filename</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int * </td>
+ <td class="paramname"><em>width</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int </td>
+ <td class="paramname"><em>align</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int * </td>
+ <td class="paramname"><em>height</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int * </td>
+ <td class="paramname"><em>pixelFormat</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int </td>
+ <td class="paramname"><em>flags</em> </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td>
+ </tr>
+ </table>
+</div><div class="memdoc">
+
+<p>Load an uncompressed image from disk into memory. </p>
+<dl class="params"><dt>Parameters</dt><dd>
+ <table class="params">
+ <tr><td class="paramname">filename</td><td>name of a file containing an uncompressed image in Windows BMP or PBMPLUS (PPM/PGM) format</td></tr>
+ <tr><td class="paramname">width</td><td>pointer to an integer variable that will receive the width (in pixels) of the uncompressed image</td></tr>
+ <tr><td class="paramname">align</td><td>row alignment of the image buffer to be returned (must be a power of 2.) For instance, setting this parameter to 4 will cause all rows in the image buffer to be padded to the nearest 32-bit boundary, and setting this parameter to 1 will cause all rows in the image buffer to be unpadded.</td></tr>
+ <tr><td class="paramname">height</td><td>pointer to an integer variable that will receive the height (in pixels) of the uncompressed image</td></tr>
+ <tr><td class="paramname">pixelFormat</td><td>pointer to an integer variable that specifies or will receive the pixel format of the uncompressed image buffer. If <code>*pixelFormat</code> is set to <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa84c1a6cead7952998e2fb895844a21ed">TJPF_UNKNOWN</a> prior to calling this function, then the uncompressed image buffer returned by the function will use the most optimal pixel format for the file type, and <code>*pixelFormat</code> will contain the ID of this pixel format upon successful return from the function. Otherwise, the uncompressed image buffer will use the <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">pixel format</a> specified in <code>*pixelFormat</code>, and pixel format conversion will be performed if necessary. If <code>*pixelFormat</code> is set to <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b">TJPF_CMYK</a>, then the RGB or grayscale pixels stored in the file will be converted using a quick & dirty algorithm that is suitable only for testing purposes (proper conversion between CMYK and other formats requires a color management system.)</td></tr>
+ <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#ga72ecf4ebe6eb702d3c6f5ca27455e1ec">flags</a>.</td></tr>
+ </table>
+ </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>a pointer to a newly-allocated buffer containing the uncompressed image, converted to the chosen pixel format and with the chosen row alignment, or NULL if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga94a235bd4f1088f61ad87b4eadb64c9c" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a>.) This buffer should be freed using <a class="el" href="group___turbo_j_p_e_g.html#ga8c4a1231dc06a450514c835f6471f137" title="Free an image buffer previously allocated by TurboJPEG.">tjFree()</a>. </dd></dl>
+
</div>
</div>
<a class="anchor" id="ga1a209696c6a80748f20e134b3c64789f"></a>
</dl>
<dl class="section return"><dt>Returns</dt><dd>the plane width of a YUV image plane with the given parameters, or -1 if the arguments are out of bounds. </dd></dl>
+</div>
+</div>
+<a class="anchor" id="ga2e78b7b79796e74584028da880a6a29c"></a>
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">DLLEXPORT int DLLCALL tjSaveImage </td>
+ <td>(</td>
+ <td class="paramtype">const char * </td>
+ <td class="paramname"><em>filename</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">unsigned char * </td>
+ <td class="paramname"><em>buffer</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int </td>
+ <td class="paramname"><em>width</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int </td>
+ <td class="paramname"><em>pitch</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int </td>
+ <td class="paramname"><em>height</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int </td>
+ <td class="paramname"><em>pixelFormat</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int </td>
+ <td class="paramname"><em>flags</em> </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td>
+ </tr>
+ </table>
+</div><div class="memdoc">
+
+<p>Save an uncompressed image from memory to disk. </p>
+<dl class="params"><dt>Parameters</dt><dd>
+ <table class="params">
+ <tr><td class="paramname">filename</td><td>name of a file to which to save the uncompressed image. The image will be stored in Windows BMP or PBMPLUS (PPM/PGM) format, depending on the file extension.</td></tr>
+ <tr><td class="paramname">buffer</td><td>pointer to an image buffer containing RGB, grayscale, or CMYK pixels to be saved</td></tr>
+ <tr><td class="paramname">width</td><td>width (in pixels) of the uncompressed image</td></tr>
+ <tr><td class="paramname">pitch</td><td>bytes per line in the image buffer. Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.</td></tr>
+ <tr><td class="paramname">height</td><td>height (in pixels) of the uncompressed image</td></tr>
+ <tr><td class="paramname">pixelFormat</td><td>pixel format of the image buffer (see <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">Pixel formats</a>.) If this parameter is set to <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa5431b54b015337705f13118073711a1a">TJPF_GRAY</a>, then the image will be stored in PGM or 8-bit (indexed color) BMP format. Otherwise, the image will be stored in PPM or 24-bit BMP format. If this parameter is set to <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b">TJPF_CMYK</a>, then the CMYK pixels will be converted to RGB using a quick & dirty algorithm that is suitable only for testing (proper conversion between CMYK and other formats requires a color management system.)</td></tr>
+ <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#ga72ecf4ebe6eb702d3c6f5ca27455e1ec">flags</a>.</td></tr>
+ </table>
+ </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga94a235bd4f1088f61ad87b4eadb64c9c" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a>.) </dd></dl>
+
</div>
</div>
<a class="anchor" id="gad02cd42b69f193a0623a9c801788df3a"></a>
['tjinitcompress',['tjInitCompress',['../group___turbo_j_p_e_g.html#ga3d10c47fbe4a2489a2b30c931551d01a',1,'turbojpeg.h']]],
['tjinitdecompress',['tjInitDecompress',['../group___turbo_j_p_e_g.html#gae5408179d041e2a2f7199c8283cf649e',1,'turbojpeg.h']]],
['tjinittransform',['tjInitTransform',['../group___turbo_j_p_e_g.html#ga3155b775bfbac9dbba869b95a0367902',1,'turbojpeg.h']]],
+ ['tjloadimage',['tjLoadImage',['../group___turbo_j_p_e_g.html#ga144b981d6b281ecca4cbb4709de75749',1,'turbojpeg.h']]],
['tjmcuheight',['tjMCUHeight',['../group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf',1,'turbojpeg.h']]],
['tjmcuwidth',['tjMCUWidth',['../group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c',1,'turbojpeg.h']]],
['tjpad',['TJPAD',['../group___turbo_j_p_e_g.html#ga0aba955473315e405295d978f0c16511',1,'turbojpeg.h']]],
['tjpf_5frgb',['TJPF_RGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7ce93230bff449518ce387c17e6ed37c',1,'turbojpeg.h']]],
['tjpf_5frgba',['TJPF_RGBA',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa88d2e88fab67f6503cf972e14851cc12',1,'turbojpeg.h']]],
['tjpf_5frgbx',['TJPF_RGBX',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa83973bebb7e2dc6fa8bae89ff3f42e01',1,'turbojpeg.h']]],
+ ['tjpf_5funknown',['TJPF_UNKNOWN',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa84c1a6cead7952998e2fb895844a21ed',1,'turbojpeg.h']]],
['tjpf_5fxbgr',['TJPF_XBGR',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aaf6603b27147de47e212e75dac027b2af',1,'turbojpeg.h']]],
['tjpf_5fxrgb',['TJPF_XRGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aadae996905efcfa3b42a0bb3bea7f9d84',1,'turbojpeg.h']]],
['tjpixelsize',['tjPixelSize',['../group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c',1,'turbojpeg.h']]],
['tjsamp_5f440',['TJSAMP_440',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074accf740e6f3aa6ba20ba922cad13cb974',1,'turbojpeg.h']]],
['tjsamp_5f444',['TJSAMP_444',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074afb8da4f44197837bdec0a4f593dacae3',1,'turbojpeg.h']]],
['tjsamp_5fgray',['TJSAMP_GRAY',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a3f1c9504842ddc7a48d0f690754b6248',1,'turbojpeg.h']]],
+ ['tjsaveimage',['tjSaveImage',['../group___turbo_j_p_e_g.html#ga2e78b7b79796e74584028da880a6a29c',1,'turbojpeg.h']]],
['tjscaled',['TJSCALED',['../group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df',1,'turbojpeg.h']]],
['tjscalingfactor',['tjscalingfactor',['../structtjscalingfactor.html',1,'']]],
['tjtransform',['tjtransform',['../structtjtransform.html',1,'tjtransform'],['../group___turbo_j_p_e_g.html#gaa29f3189c41be12ec5dee7caec318a31',1,'tjtransform(): turbojpeg.h'],['../group___turbo_j_p_e_g.html#gad02cd42b69f193a0623a9c801788df3a',1,'tjTransform(tjhandle handle, const unsigned char *jpegBuf, unsigned long jpegSize, int n, unsigned char **dstBufs, unsigned long *dstSizes, tjtransform *transforms, int flags): turbojpeg.h']]],
['tjpf_5frgb',['TJPF_RGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7ce93230bff449518ce387c17e6ed37c',1,'turbojpeg.h']]],
['tjpf_5frgba',['TJPF_RGBA',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa88d2e88fab67f6503cf972e14851cc12',1,'turbojpeg.h']]],
['tjpf_5frgbx',['TJPF_RGBX',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa83973bebb7e2dc6fa8bae89ff3f42e01',1,'turbojpeg.h']]],
+ ['tjpf_5funknown',['TJPF_UNKNOWN',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa84c1a6cead7952998e2fb895844a21ed',1,'turbojpeg.h']]],
['tjpf_5fxbgr',['TJPF_XBGR',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aaf6603b27147de47e212e75dac027b2af',1,'turbojpeg.h']]],
['tjpf_5fxrgb',['TJPF_XRGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aadae996905efcfa3b42a0bb3bea7f9d84',1,'turbojpeg.h']]],
['tjsamp_5f411',['TJSAMP_411',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a28ec62575e5ea295c3fde3001dc628e2',1,'turbojpeg.h']]],
['tjinitcompress',['tjInitCompress',['../group___turbo_j_p_e_g.html#ga3d10c47fbe4a2489a2b30c931551d01a',1,'turbojpeg.h']]],
['tjinitdecompress',['tjInitDecompress',['../group___turbo_j_p_e_g.html#gae5408179d041e2a2f7199c8283cf649e',1,'turbojpeg.h']]],
['tjinittransform',['tjInitTransform',['../group___turbo_j_p_e_g.html#ga3155b775bfbac9dbba869b95a0367902',1,'turbojpeg.h']]],
+ ['tjloadimage',['tjLoadImage',['../group___turbo_j_p_e_g.html#ga144b981d6b281ecca4cbb4709de75749',1,'turbojpeg.h']]],
['tjplaneheight',['tjPlaneHeight',['../group___turbo_j_p_e_g.html#ga1a209696c6a80748f20e134b3c64789f',1,'turbojpeg.h']]],
['tjplanesizeyuv',['tjPlaneSizeYUV',['../group___turbo_j_p_e_g.html#ga6f98d977bfa9d167c97172e876ba61e2',1,'turbojpeg.h']]],
['tjplanewidth',['tjPlaneWidth',['../group___turbo_j_p_e_g.html#ga63fb66bb1e36c74008c4634360becbb1',1,'turbojpeg.h']]],
+ ['tjsaveimage',['tjSaveImage',['../group___turbo_j_p_e_g.html#ga2e78b7b79796e74584028da880a6a29c',1,'turbojpeg.h']]],
['tjtransform',['tjTransform',['../group___turbo_j_p_e_g.html#gad02cd42b69f193a0623a9c801788df3a',1,'turbojpeg.h']]]
];
#ifndef _SYS_MD5_H_
#define _SYS_MD5_H_
+#include <sys/types.h>
+
#define MD5_BLOCK_LENGTH 64
#define MD5_DIGEST_LENGTH 16
#define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_LENGTH * 2 + 1)
#include <stdio.h>
#include <string.h>
-#include <sys/types.h>
#include "./md5.h"
#include "../tjutil.h"
* Modified 2009-2010 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Modified 2011 by Siarhei Siamashka.
- * Copyright (C) 2015, D. R. Commander.
+ * Copyright (C) 2015, 2017, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
*/
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+#include "cmyk.h"
#ifdef BMP_SUPPORTED
#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
+static int alpha_index[JPEG_NUMCS] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1
+};
+
/* Private version of data source object */
JDIMENSION row_width; /* Physical width of scanlines in file */
int bits_per_pixel; /* remembers 8- or 24-bit format */
+
+ boolean use_inversion_array; /* TRUE = preload the whole image, which is
+ stored in bottom-up order, and feed it to
+ the calling program in top-down order
+
+ FALSE = the calling program will maintain
+ its own image buffer and read the rows in
+ bottom-up order */
+
+ U_CHAR *iobuffer; /* I/O buffer (used to buffer a single row from
+ disk if use_inversion_array == FALSE) */
} bmp_source_struct;
register JSAMPROW inptr, outptr;
register JDIMENSION col;
- /* Fetch next row from virtual array */
- source->source_row--;
- image_ptr = (*cinfo->mem->access_virt_sarray)
- ((j_common_ptr) cinfo, source->whole_image,
- source->source_row, (JDIMENSION) 1, FALSE);
+ if (source->use_inversion_array) {
+ /* Fetch next row from virtual array */
+ source->source_row--;
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->whole_image,
+ source->source_row, (JDIMENSION) 1, FALSE);
+ inptr = image_ptr[0];
+ } else {
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->row_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ inptr = source->iobuffer;
+ }
/* Expand the colormap indexes to real data */
- inptr = image_ptr[0];
outptr = source->pub.buffer[0];
- for (col = cinfo->image_width; col > 0; col--) {
- t = GETJSAMPLE(*inptr++);
- *outptr++ = colormap[0][t]; /* can omit GETJSAMPLE() safely */
- *outptr++ = colormap[1][t];
- *outptr++ = colormap[2][t];
+ if (cinfo->in_color_space == JCS_GRAYSCALE) {
+ for (col = cinfo->image_width; col > 0; col--) {
+ t = GETJSAMPLE(*inptr++);
+ *outptr++ = RGB2GRAY(colormap[0][t], colormap[1][t], colormap[2][t]);
+ }
+ } else if (cinfo->in_color_space == JCS_CMYK) {
+ for (col = cinfo->image_width; col > 0; col--) {
+ t = GETJSAMPLE(*inptr++);
+ rgb_to_cmyk(colormap[0][t], colormap[1][t], colormap[2][t], outptr,
+ outptr + 1, outptr + 2, outptr + 3);
+ outptr += 4;
+ }
+ } else {
+ register int rindex = rgb_red[cinfo->in_color_space];
+ register int gindex = rgb_green[cinfo->in_color_space];
+ register int bindex = rgb_blue[cinfo->in_color_space];
+ register int aindex = alpha_index[cinfo->in_color_space];
+ register int ps = rgb_pixelsize[cinfo->in_color_space];
+
+ if (aindex >= 0) {
+ for (col = cinfo->image_width; col > 0; col--) {
+ t = GETJSAMPLE(*inptr++);
+ outptr[rindex] = colormap[0][t];
+ outptr[gindex] = colormap[1][t];
+ outptr[bindex] = colormap[2][t];
+ outptr[aindex] = 0xFF;
+ outptr += ps;
+ }
+ } else {
+ for (col = cinfo->image_width; col > 0; col--) {
+ t = GETJSAMPLE(*inptr++);
+ outptr[rindex] = colormap[0][t];
+ outptr[gindex] = colormap[1][t];
+ outptr[bindex] = colormap[2][t];
+ outptr += ps;
+ }
+ }
}
return 1;
register JSAMPROW inptr, outptr;
register JDIMENSION col;
- /* Fetch next row from virtual array */
- source->source_row--;
- image_ptr = (*cinfo->mem->access_virt_sarray)
- ((j_common_ptr) cinfo, source->whole_image,
- source->source_row, (JDIMENSION) 1, FALSE);
+ if (source->use_inversion_array) {
+ /* Fetch next row from virtual array */
+ source->source_row--;
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->whole_image,
+ source->source_row, (JDIMENSION) 1, FALSE);
+ inptr = image_ptr[0];
+ } else {
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->row_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ inptr = source->iobuffer;
+ }
/* Transfer data. Note source values are in BGR order
* (even though Microsoft's own documents say the opposite).
*/
- inptr = image_ptr[0];
outptr = source->pub.buffer[0];
- for (col = cinfo->image_width; col > 0; col--) {
- outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
- outptr[1] = *inptr++;
- outptr[0] = *inptr++;
- outptr += 3;
+ if (cinfo->in_color_space == JCS_EXT_BGR) {
+ MEMCOPY(outptr, inptr, source->row_width);
+ } else if (cinfo->in_color_space == JCS_GRAYSCALE) {
+ for (col = cinfo->image_width; col > 0; col--) {
+ /* can omit GETJSAMPLE() safely */
+ JSAMPLE b = *inptr++, g = *inptr++, r = *inptr++;
+ *outptr++ = RGB2GRAY(r, g, b);
+ }
+ } else if (cinfo->in_color_space == JCS_CMYK) {
+ for (col = cinfo->image_width; col > 0; col--) {
+ /* can omit GETJSAMPLE() safely */
+ JSAMPLE b = *inptr++, g = *inptr++, r = *inptr++;
+ rgb_to_cmyk(r, g, b, outptr, outptr + 1, outptr + 2, outptr + 3);
+ outptr += 4;
+ }
+ } else {
+ register int rindex = rgb_red[cinfo->in_color_space];
+ register int gindex = rgb_green[cinfo->in_color_space];
+ register int bindex = rgb_blue[cinfo->in_color_space];
+ register int aindex = alpha_index[cinfo->in_color_space];
+ register int ps = rgb_pixelsize[cinfo->in_color_space];
+
+ if (aindex >= 0) {
+ for (col = cinfo->image_width; col > 0; col--) {
+ outptr[bindex] = *inptr++; /* can omit GETJSAMPLE() safely */
+ outptr[gindex] = *inptr++;
+ outptr[rindex] = *inptr++;
+ outptr[aindex] = 0xFF;
+ outptr += ps;
+ }
+ } else {
+ for (col = cinfo->image_width; col > 0; col--) {
+ outptr[bindex] = *inptr++; /* can omit GETJSAMPLE() safely */
+ outptr[gindex] = *inptr++;
+ outptr[rindex] = *inptr++;
+ outptr += ps;
+ }
+ }
}
return 1;
register JSAMPROW inptr, outptr;
register JDIMENSION col;
- /* Fetch next row from virtual array */
- source->source_row--;
- image_ptr = (*cinfo->mem->access_virt_sarray)
- ((j_common_ptr) cinfo, source->whole_image,
- source->source_row, (JDIMENSION) 1, FALSE);
+ if (source->use_inversion_array) {
+ /* Fetch next row from virtual array */
+ source->source_row--;
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->whole_image,
+ source->source_row, (JDIMENSION) 1, FALSE);
+ inptr = image_ptr[0];
+ } else {
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->row_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ inptr = source->iobuffer;
+ }
+
/* Transfer data. Note source values are in BGR order
* (even though Microsoft's own documents say the opposite).
*/
- inptr = image_ptr[0];
outptr = source->pub.buffer[0];
- for (col = cinfo->image_width; col > 0; col--) {
- outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
- outptr[1] = *inptr++;
- outptr[0] = *inptr++;
- inptr++; /* skip the 4th byte (Alpha channel) */
- outptr += 3;
+ if (cinfo->in_color_space == JCS_EXT_BGRX ||
+ cinfo->in_color_space == JCS_EXT_BGRA) {
+ MEMCOPY(outptr, inptr, source->row_width);
+ } else if (cinfo->in_color_space == JCS_GRAYSCALE) {
+ for (col = cinfo->image_width; col > 0; col--) {
+ /* can omit GETJSAMPLE() safely */
+ JSAMPLE b = *inptr++, g = *inptr++, r = *inptr++;
+ *outptr++ = RGB2GRAY(r, g, b);
+ }
+ } else if (cinfo->in_color_space == JCS_CMYK) {
+ for (col = cinfo->image_width; col > 0; col--) {
+ /* can omit GETJSAMPLE() safely */
+ JSAMPLE b = *inptr++, g = *inptr++, r = *inptr++;
+ rgb_to_cmyk(r, g, b, outptr, outptr + 1, outptr + 2, outptr + 3);
+ inptr++; /* skip the 4th byte (Alpha channel) */
+ outptr += 4;
+ }
+ } else {
+ register int rindex = rgb_red[cinfo->in_color_space];
+ register int gindex = rgb_green[cinfo->in_color_space];
+ register int bindex = rgb_blue[cinfo->in_color_space];
+ register int aindex = alpha_index[cinfo->in_color_space];
+ register int ps = rgb_pixelsize[cinfo->in_color_space];
+
+ if (aindex >= 0) {
+ for (col = cinfo->image_width; col > 0; col--) {
+ outptr[bindex] = *inptr++; /* can omit GETJSAMPLE() safely */
+ outptr[gindex] = *inptr++;
+ outptr[rindex] = *inptr++;
+ outptr[aindex] = *inptr++;
+ outptr += ps;
+ }
+ } else {
+ for (col = cinfo->image_width; col > 0; col--) {
+ outptr[bindex] = *inptr++; /* can omit GETJSAMPLE() safely */
+ outptr[gindex] = *inptr++;
+ outptr[rindex] = *inptr++;
+ inptr++; /* skip the 4th byte (Alpha channel) */
+ outptr += ps;
+ }
+ }
}
return 1;
unsigned int biClrUsed = 0;
int mapentrysize = 0; /* 0 indicates no colormap */
int bPad;
- JDIMENSION row_width;
+ JDIMENSION row_width = 0;
/* Read and verify the bitmap file header */
if (! ReadOK(source->pub.input_file, bmpfileheader, 14))
}
/* Compute row width in file, including padding to 4-byte boundary */
- if (source->bits_per_pixel == 24)
+ switch (source->bits_per_pixel) {
+ case 8:
+ if (cinfo->in_color_space == JCS_UNKNOWN)
+ cinfo->in_color_space = JCS_EXT_RGB;
+ row_width = (JDIMENSION) biWidth;
+ break;
+ case 24:
+ if (cinfo->in_color_space == JCS_UNKNOWN)
+ cinfo->in_color_space = JCS_EXT_BGR;
row_width = (JDIMENSION) (biWidth * 3);
- else if (source->bits_per_pixel == 32)
+ break;
+ case 32:
+ if (cinfo->in_color_space == JCS_UNKNOWN)
+ cinfo->in_color_space = JCS_EXT_BGRA;
row_width = (JDIMENSION) (biWidth * 4);
- else
- row_width = (JDIMENSION) biWidth;
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BMP_BADDEPTH);
+ }
while ((row_width & 3) != 0) row_width++;
source->row_width = row_width;
- /* Allocate space for inversion array, prepare for preload pass */
- source->whole_image = (*cinfo->mem->request_virt_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
- row_width, (JDIMENSION) biHeight, (JDIMENSION) 1);
- source->pub.get_pixel_rows = preload_image;
- if (cinfo->progress != NULL) {
- cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
- progress->total_extra_passes++; /* count file input as separate pass */
+ if (source->use_inversion_array) {
+ /* Allocate space for inversion array, prepare for preload pass */
+ source->whole_image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ row_width, (JDIMENSION) biHeight, (JDIMENSION) 1);
+ source->pub.get_pixel_rows = preload_image;
+ if (cinfo->progress != NULL) {
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+ progress->total_extra_passes++; /* count file input as separate pass */
+ }
+ } else {
+ source->iobuffer = (U_CHAR *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ row_width);
+ switch (source->bits_per_pixel) {
+ case 8:
+ source->pub.get_pixel_rows = get_8bit_row;
+ break;
+ case 24:
+ source->pub.get_pixel_rows = get_24bit_row;
+ break;
+ case 32:
+ source->pub.get_pixel_rows = get_32bit_row;
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BMP_BADDEPTH);
+ }
}
+ if (IsExtRGB(cinfo->in_color_space))
+ cinfo->input_components = rgb_pixelsize[cinfo->in_color_space];
+ else if (cinfo->in_color_space == JCS_GRAYSCALE)
+ cinfo->input_components = 1;
+ else if (cinfo->in_color_space == JCS_CMYK)
+ cinfo->input_components = 4;
+ else
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+
/* Allocate one-row buffer for returned data */
source->pub.buffer = (*cinfo->mem->alloc_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE,
- (JDIMENSION) (biWidth * 3), (JDIMENSION) 1);
+ (JDIMENSION) (biWidth * cinfo->input_components), (JDIMENSION) 1);
source->pub.buffer_height = 1;
- cinfo->in_color_space = JCS_RGB;
- cinfo->input_components = 3;
cinfo->data_precision = 8;
cinfo->image_width = (JDIMENSION) biWidth;
cinfo->image_height = (JDIMENSION) biHeight;
*/
GLOBAL(cjpeg_source_ptr)
-jinit_read_bmp (j_compress_ptr cinfo)
+jinit_read_bmp (j_compress_ptr cinfo, boolean use_inversion_array)
{
bmp_source_ptr source;
source->pub.start_input = start_input_bmp;
source->pub.finish_input = finish_input_bmp;
+ source->use_inversion_array = use_inversion_array;
+
return (cjpeg_source_ptr) source;
}
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2009 by Bill Allombert, Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2015, 2016, D. R. Commander.
+ * Copyright (C) 2015-2017, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
*/
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+#include "cmyk.h"
#ifdef PPM_SUPPORTED
#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
+static int alpha_index[JPEG_NUMCS] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1
+};
+
/* Private version of data source object */
}
+#define GRAY_RGB_READ_LOOP(read_op, alpha_set_op) { \
+ for (col = cinfo->image_width; col > 0; col--) { \
+ ptr[rindex] = ptr[gindex] = ptr[bindex] = read_op; \
+ alpha_set_op \
+ ptr += ps; \
+ } \
+}
+
+METHODDEF(JDIMENSION)
+get_text_gray_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading text-format PGM files with any maxval and
+ converting to extended RGB */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ FILE *infile = source->pub.input_file;
+ register JSAMPROW ptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+ unsigned int maxval = source->maxval;
+ register int rindex = rgb_red[cinfo->in_color_space];
+ register int gindex = rgb_green[cinfo->in_color_space];
+ register int bindex = rgb_blue[cinfo->in_color_space];
+ register int aindex = alpha_index[cinfo->in_color_space];
+ register int ps = rgb_pixelsize[cinfo->in_color_space];
+
+ ptr = source->pub.buffer[0];
+ if (maxval == MAXJSAMPLE) {
+ if (aindex >= 0)
+ GRAY_RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval),
+ ptr[aindex] = 0xFF;)
+ else
+ GRAY_RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval),)
+ } else {
+ if (aindex >= 0)
+ GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],
+ ptr[aindex] = 0xFF;)
+ else
+ GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],)
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_text_gray_cmyk_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading text-format PGM files with any maxval and
+ converting to CMYK */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ FILE *infile = source->pub.input_file;
+ register JSAMPROW ptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+ unsigned int maxval = source->maxval;
+
+ ptr = source->pub.buffer[0];
+ if (maxval == MAXJSAMPLE) {
+ for (col = cinfo->image_width; col > 0; col--) {
+ JSAMPLE gray = read_pbm_integer(cinfo, infile, maxval);
+ rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
+ ptr += 4;
+ }
+ } else {
+ for (col = cinfo->image_width; col > 0; col--) {
+ JSAMPLE gray = rescale[read_pbm_integer(cinfo, infile, maxval)];
+ rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
+ ptr += 4;
+ }
+ }
+ return 1;
+}
+
+
+#define RGB_READ_LOOP(read_op, alpha_set_op) { \
+ for (col = cinfo->image_width; col > 0; col--) { \
+ ptr[rindex] = read_op; \
+ ptr[gindex] = read_op; \
+ ptr[bindex] = read_op; \
+ alpha_set_op \
+ ptr += ps; \
+ } \
+}
+
METHODDEF(JDIMENSION)
get_text_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
/* This version is for reading text-format PPM files with any maxval */
register JSAMPLE *rescale = source->rescale;
JDIMENSION col;
unsigned int maxval = source->maxval;
+ register int rindex = rgb_red[cinfo->in_color_space];
+ register int gindex = rgb_green[cinfo->in_color_space];
+ register int bindex = rgb_blue[cinfo->in_color_space];
+ register int aindex = alpha_index[cinfo->in_color_space];
+ register int ps = rgb_pixelsize[cinfo->in_color_space];
ptr = source->pub.buffer[0];
- for (col = cinfo->image_width; col > 0; col--) {
- *ptr++ = rescale[read_pbm_integer(cinfo, infile, maxval)];
- *ptr++ = rescale[read_pbm_integer(cinfo, infile, maxval)];
- *ptr++ = rescale[read_pbm_integer(cinfo, infile, maxval)];
+ if (maxval == MAXJSAMPLE) {
+ if (aindex >= 0)
+ RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval),
+ ptr[aindex] = 0xFF;)
+ else
+ RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval),)
+ } else {
+ if (aindex >= 0)
+ RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],
+ ptr[aindex] = 0xFF;)
+ else
+ RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],)
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_text_rgb_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading text-format PPM files with any maxval and
+ converting to grayscale */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ FILE *infile = source->pub.input_file;
+ register JSAMPROW ptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+ unsigned int maxval = source->maxval;
+
+ ptr = source->pub.buffer[0];
+ if (maxval == MAXJSAMPLE) {
+ for (col = cinfo->image_width; col > 0; col--) {
+ JSAMPLE r = read_pbm_integer(cinfo, infile, maxval);
+ JSAMPLE g = read_pbm_integer(cinfo, infile, maxval);
+ JSAMPLE b = read_pbm_integer(cinfo, infile, maxval);
+ *ptr++ = RGB2GRAY(r, g, b);
+ }
+ } else {
+ for (col = cinfo->image_width; col > 0; col--) {
+ JSAMPLE r = rescale[read_pbm_integer(cinfo, infile, maxval)];
+ JSAMPLE g = rescale[read_pbm_integer(cinfo, infile, maxval)];
+ JSAMPLE b = rescale[read_pbm_integer(cinfo, infile, maxval)];
+ *ptr++ = RGB2GRAY(r, g, b);
+ }
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_text_rgb_cmyk_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading text-format PPM files with any maxval and
+ converting to CMYK */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ FILE *infile = source->pub.input_file;
+ register JSAMPROW ptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+ unsigned int maxval = source->maxval;
+
+ ptr = source->pub.buffer[0];
+ if (maxval == MAXJSAMPLE) {
+ for (col = cinfo->image_width; col > 0; col--) {
+ JSAMPLE r = read_pbm_integer(cinfo, infile, maxval);
+ JSAMPLE g = read_pbm_integer(cinfo, infile, maxval);
+ JSAMPLE b = read_pbm_integer(cinfo, infile, maxval);
+ rgb_to_cmyk(r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
+ ptr += 4;
+ }
+ } else {
+ for (col = cinfo->image_width; col > 0; col--) {
+ JSAMPLE r = rescale[read_pbm_integer(cinfo, infile, maxval)];
+ JSAMPLE g = rescale[read_pbm_integer(cinfo, infile, maxval)];
+ JSAMPLE b = rescale[read_pbm_integer(cinfo, infile, maxval)];
+ rgb_to_cmyk(r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
+ ptr += 4;
+ }
}
return 1;
}
METHODDEF(JDIMENSION)
-get_scaled_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+get_gray_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-byte-format PGM files with any maxval
+ and converting to extended RGB */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register U_CHAR *bufferptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+ unsigned int maxval = source->maxval;
+ register int rindex = rgb_red[cinfo->in_color_space];
+ register int gindex = rgb_green[cinfo->in_color_space];
+ register int bindex = rgb_blue[cinfo->in_color_space];
+ register int aindex = alpha_index[cinfo->in_color_space];
+ register int ps = rgb_pixelsize[cinfo->in_color_space];
+
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ ptr = source->pub.buffer[0];
+ bufferptr = source->iobuffer;
+ if (maxval == MAXJSAMPLE) {
+ if (aindex >= 0)
+ GRAY_RGB_READ_LOOP(*bufferptr++, ptr[aindex] = 0xFF;)
+ else
+ GRAY_RGB_READ_LOOP(*bufferptr++,)
+ } else {
+ if (aindex >= 0)
+ GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = 0xFF;)
+ else
+ GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)],)
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_gray_cmyk_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-byte-format PGM files with any maxval
+ and converting to CMYK */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register U_CHAR *bufferptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+ unsigned int maxval = source->maxval;
+
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ ptr = source->pub.buffer[0];
+ bufferptr = source->iobuffer;
+ if (maxval == MAXJSAMPLE) {
+ for (col = cinfo->image_width; col > 0; col--) {
+ JSAMPLE gray = *bufferptr++;
+ rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
+ ptr += 4;
+ }
+ } else {
+ for (col = cinfo->image_width; col > 0; col--) {
+ JSAMPLE gray = rescale[UCH(*bufferptr++)];
+ rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
+ ptr += 4;
+ }
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
/* This version is for reading raw-byte-format PPM files with any maxval */
{
ppm_source_ptr source = (ppm_source_ptr) sinfo;
register U_CHAR *bufferptr;
register JSAMPLE *rescale = source->rescale;
JDIMENSION col;
+ unsigned int maxval = source->maxval;
+ register int rindex = rgb_red[cinfo->in_color_space];
+ register int gindex = rgb_green[cinfo->in_color_space];
+ register int bindex = rgb_blue[cinfo->in_color_space];
+ register int aindex = alpha_index[cinfo->in_color_space];
+ register int ps = rgb_pixelsize[cinfo->in_color_space];
if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
ERREXIT(cinfo, JERR_INPUT_EOF);
ptr = source->pub.buffer[0];
bufferptr = source->iobuffer;
- for (col = cinfo->image_width; col > 0; col--) {
- *ptr++ = rescale[UCH(*bufferptr++)];
- *ptr++ = rescale[UCH(*bufferptr++)];
- *ptr++ = rescale[UCH(*bufferptr++)];
+ if (maxval == MAXJSAMPLE) {
+ if (aindex >= 0)
+ RGB_READ_LOOP(*bufferptr++, ptr[aindex] = 0xFF;)
+ else
+ RGB_READ_LOOP(*bufferptr++,)
+ } else {
+ if (aindex >= 0)
+ RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = 0xFF;)
+ else
+ RGB_READ_LOOP(rescale[UCH(*bufferptr++)],)
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_rgb_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-byte-format PPM files with any maxval and
+ converting to grayscale */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register U_CHAR *bufferptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+ unsigned int maxval = source->maxval;
+
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ ptr = source->pub.buffer[0];
+ bufferptr = source->iobuffer;
+ if (maxval == MAXJSAMPLE) {
+ for (col = cinfo->image_width; col > 0; col--) {
+ JSAMPLE r = *bufferptr++;
+ JSAMPLE g = *bufferptr++;
+ JSAMPLE b = *bufferptr++;
+ *ptr++ = RGB2GRAY(r, g, b);
+ }
+ } else {
+ for (col = cinfo->image_width; col > 0; col--) {
+ JSAMPLE r = rescale[UCH(*bufferptr++)];
+ JSAMPLE g = rescale[UCH(*bufferptr++)];
+ JSAMPLE b = rescale[UCH(*bufferptr++)];
+ *ptr++ = RGB2GRAY(r, g, b);
+ }
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_rgb_cmyk_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-byte-format PPM files with any maxval and
+ converting to CMYK */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register U_CHAR *bufferptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+ unsigned int maxval = source->maxval;
+
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ ptr = source->pub.buffer[0];
+ bufferptr = source->iobuffer;
+ if (maxval == MAXJSAMPLE) {
+ for (col = cinfo->image_width; col > 0; col--) {
+ JSAMPLE r = *bufferptr++;
+ JSAMPLE g = *bufferptr++;
+ JSAMPLE b = *bufferptr++;
+ rgb_to_cmyk(r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
+ ptr += 4;
+ }
+ } else {
+ for (col = cinfo->image_width; col > 0; col--) {
+ JSAMPLE r = rescale[UCH(*bufferptr++)];
+ JSAMPLE g = rescale[UCH(*bufferptr++)];
+ JSAMPLE b = rescale[UCH(*bufferptr++)];
+ rgb_to_cmyk(r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
+ ptr += 4;
+ }
}
return 1;
}
switch (c) {
case '2': /* it's a text-format PGM file */
- cinfo->input_components = 1;
- cinfo->in_color_space = JCS_GRAYSCALE;
+ if (cinfo->in_color_space == JCS_UNKNOWN)
+ cinfo->in_color_space = JCS_GRAYSCALE;
TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h);
- source->pub.get_pixel_rows = get_text_gray_row;
+ if (cinfo->in_color_space == JCS_GRAYSCALE)
+ source->pub.get_pixel_rows = get_text_gray_row;
+ else if (IsExtRGB(cinfo->in_color_space))
+ source->pub.get_pixel_rows = get_text_gray_rgb_row;
+ else if (cinfo->in_color_space == JCS_CMYK)
+ source->pub.get_pixel_rows = get_text_gray_cmyk_row;
+ else
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
need_iobuffer = FALSE;
break;
case '3': /* it's a text-format PPM file */
- cinfo->input_components = 3;
- cinfo->in_color_space = JCS_RGB;
+ if (cinfo->in_color_space == JCS_UNKNOWN)
+ cinfo->in_color_space = JCS_EXT_RGB;
TRACEMS2(cinfo, 1, JTRC_PPM_TEXT, w, h);
- source->pub.get_pixel_rows = get_text_rgb_row;
+ if (IsExtRGB(cinfo->in_color_space))
+ source->pub.get_pixel_rows = get_text_rgb_row;
+ else if (cinfo->in_color_space == JCS_CMYK)
+ source->pub.get_pixel_rows = get_text_rgb_cmyk_row;
+ else if (cinfo->in_color_space == JCS_GRAYSCALE)
+ source->pub.get_pixel_rows = get_text_rgb_gray_row;
+ else
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
need_iobuffer = FALSE;
break;
case '5': /* it's a raw-format PGM file */
- cinfo->input_components = 1;
- cinfo->in_color_space = JCS_GRAYSCALE;
+ if (cinfo->in_color_space == JCS_UNKNOWN)
+ cinfo->in_color_space = JCS_GRAYSCALE;
TRACEMS2(cinfo, 1, JTRC_PGM, w, h);
if (maxval > 255) {
source->pub.get_pixel_rows = get_word_gray_row;
- } else if (maxval == MAXJSAMPLE && sizeof(JSAMPLE) == sizeof(U_CHAR)) {
+ } else if (maxval == MAXJSAMPLE && sizeof(JSAMPLE) == sizeof(U_CHAR) &&
+ cinfo->in_color_space == JCS_GRAYSCALE) {
source->pub.get_pixel_rows = get_raw_row;
use_raw_buffer = TRUE;
need_rescale = FALSE;
} else {
- source->pub.get_pixel_rows = get_scaled_gray_row;
+ if (cinfo->in_color_space == JCS_GRAYSCALE)
+ source->pub.get_pixel_rows = get_scaled_gray_row;
+ else if (IsExtRGB(cinfo->in_color_space))
+ source->pub.get_pixel_rows = get_gray_rgb_row;
+ else if (cinfo->in_color_space == JCS_CMYK)
+ source->pub.get_pixel_rows = get_gray_cmyk_row;
+ else
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
}
break;
case '6': /* it's a raw-format PPM file */
- cinfo->input_components = 3;
- cinfo->in_color_space = JCS_RGB;
+ if (cinfo->in_color_space == JCS_UNKNOWN)
+ cinfo->in_color_space = JCS_EXT_RGB;
TRACEMS2(cinfo, 1, JTRC_PPM, w, h);
if (maxval > 255) {
source->pub.get_pixel_rows = get_word_rgb_row;
- } else if (maxval == MAXJSAMPLE && sizeof(JSAMPLE) == sizeof(U_CHAR)) {
+ } else if (maxval == MAXJSAMPLE && sizeof(JSAMPLE) == sizeof(U_CHAR) &&
+ (cinfo->in_color_space == JCS_EXT_RGB
+#if RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 3
+ || cinfo->in_color_space == JCS_RGB)) {
+#endif
source->pub.get_pixel_rows = get_raw_row;
use_raw_buffer = TRUE;
need_rescale = FALSE;
} else {
- source->pub.get_pixel_rows = get_scaled_rgb_row;
+ if (IsExtRGB(cinfo->in_color_space))
+ source->pub.get_pixel_rows = get_rgb_row;
+ else if (cinfo->in_color_space == JCS_CMYK)
+ source->pub.get_pixel_rows = get_rgb_cmyk_row;
+ else if (cinfo->in_color_space == JCS_GRAYSCALE)
+ source->pub.get_pixel_rows = get_rgb_gray_row;
+ else
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
}
break;
}
+ if (IsExtRGB(cinfo->in_color_space))
+ cinfo->input_components = rgb_pixelsize[cinfo->in_color_space];
+ else if (cinfo->in_color_space == JCS_GRAYSCALE)
+ cinfo->input_components = 1;
+ else if (cinfo->in_color_space == JCS_CMYK)
+ cinfo->input_components = 4;
+
/* Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. */
if (need_iobuffer) {
- source->buffer_width = (size_t) w * cinfo->input_components *
- ((maxval <= 255) ? sizeof(U_CHAR) : (2 * sizeof(U_CHAR)));
+ if (c == '6')
+ source->buffer_width = (size_t) w * 3 *
+ ((maxval <= 255) ? sizeof(U_CHAR) : (2 * sizeof(U_CHAR)));
+ else
+ source->buffer_width = (size_t) w *
+ ((maxval <= 255) ? sizeof(U_CHAR) : (2 * sizeof(U_CHAR)));
source->iobuffer = (U_CHAR *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
source->buffer_width);
#include <math.h>
#include <errno.h>
#include <cdjpeg.h>
-#include "./bmp.h"
#include "./tjutil.h"
#include "./turbojpeg.h"
char tjErrorStr[JMSG_LENGTH_MAX]="\0", tjErrorMsg[JMSG_LENGTH_MAX]="\0";
int tjErrorLine=-1, tjErrorCode=-1;
+#define _throwtjg(m) { \
+ printf("ERROR in line %d while %s:\n%s\n", __LINE__, m, \
+ tjGetErrorStr2(NULL)); \
+ retval=-1; goto bailout; \
+}
+
#define _throwtj(m) \
{ \
int _tjErrorCode=tjGetErrorCode(handle); \
} \
}
-#define _throwbmp(m) _throw(m, bmpgeterr())
-
int flags=TJFLAG_NOREALLOC, componly=0, decomponly=0, doyuv=0, quiet=0,
dotile=0, pf=TJPF_BGR, yuvpad=1, dowrite=1;
char *ext="ppm";
snprintf(tempstr, 1024, "%s_%s%s_%s.%s", filename, subName[subsamp],
qualstr, sizestr, ext);
- if(savebmp(tempstr, dstbuf, scaledw, scaledh, pf,
- (flags&TJFLAG_BOTTOMUP)!=0)==-1)
- _throwbmp("saving bitmap");
+ if(tjSaveImage(tempstr, dstbuf, scaledw, 0, scaledh, pf, flags)==-1)
+ _throwtjg("saving bitmap");
ptr=strrchr(tempstr, '.');
snprintf(ptr, 1024-(ptr-tempstr), "-err.%s", ext);
if(srcbuf && sf.num==1 && sf.denom==1)
dstbuf[pitch*row+col]
=abs(dstbuf[pitch*row+col]-srcbuf[pitch*row+col]);
}
- if(savebmp(tempstr, dstbuf, w, h, pf,
- (flags&TJFLAG_BOTTOMUP)!=0)==-1)
- _throwbmp("saving bitmap");
+ if(tjSaveImage(tempstr, dstbuf, w, 0, h, pf, flags)==-1)
+ _throwtjg("saving bitmap");
}
bailout:
if(!decomponly)
{
- if(loadbmp(argv[1], &srcbuf, &w, &h, pf, (flags&TJFLAG_BOTTOMUP)!=0)==-1)
- _throwbmp("loading bitmap");
+ if((srcbuf=tjLoadImage(argv[1], &w, 1, &h, &pf, flags))==NULL)
+ _throwtjg("loading bitmap");
temp=strrchr(argv[1], '.');
if(temp!=NULL) *temp='\0';
}
}
bailout:
- if(srcbuf) free(srcbuf);
+ if(srcbuf) tjFree(srcbuf);
return retval;
}
#include <stdlib.h>
#include <string.h>
#include <errno.h>
-#include "./tjutil.h"
-#include "./turbojpeg.h"
+#include "tjutil.h"
+#include "turbojpeg.h"
+#include "md5/md5.h"
+#include "cmyk.h"
#ifdef _WIN32
#include <time.h>
#define random() rand()
+#else
+ #include <unistd.h>
#endif
printf("-yuv = test YUV encoding/decoding support\n");
printf("-noyuvpad = do not pad each line of each Y, U, and V plane to the nearest\n");
printf(" 4-byte boundary\n");
- printf("-alloc = test automatic buffer allocation\n\n");
+ printf("-alloc = test automatic buffer allocation\n");
+ printf("-bmp = tjLoadImage()/tjSaveImage() unit test\n\n");
exit(1);
}
bailout();}
#define _tj(f) {if((f)==-1) _throwtj();}
#define _throw(m) {printf("ERROR: %s\n", m); bailout();}
+#define _throwmd5(filename, md5sum, ref) { \
+ printf("\n%s has an MD5 sum of %s.\n Should be %s.\n", filename, \
+ md5sum, ref); \
+ bailout(); \
+}
+
+#define RGB2GRAY(r, g, b) \
+ (unsigned char)((double)(r)*0.299+(double)(g)*0.587+(double)(b)*0.114+0.5)
const char *subNameLong[TJ_NUMSAMP]=
{
}
+void initBitmap(unsigned char *buf, int width, int pitch, int height, int pf,
+ int flags)
+{
+ int roffset=tjRedOffset[pf];
+ int goffset=tjGreenOffset[pf];
+ int boffset=tjBlueOffset[pf];
+ int ps=tjPixelSize[pf];
+ int i, j;
+
+ for(j=0; j<height; j++)
+ {
+ int row=(flags&TJFLAG_BOTTOMUP)? height-j-1:j;
+ for(i=0; i<width; i++)
+ {
+ unsigned char r=(i*256/width)%256;
+ unsigned char g=(j*256/height)%256;
+ unsigned char b=(j*256/height+i*256/width)%256;
+ memset(&buf[row*pitch+i*ps], 0, ps);
+ if(pf==TJPF_GRAY) buf[row*pitch+i*ps]=RGB2GRAY(r, g, b);
+ else if(pf==TJPF_CMYK)
+ rgb_to_cmyk(r, g, b, &buf[row*pitch+i*ps+0], &buf[row*pitch+i*ps+1],
+ &buf[row*pitch+i*ps+2], &buf[row*pitch+i*ps+3]);
+ else
+ {
+ buf[row*pitch+i*ps+roffset]=r;
+ buf[row*pitch+i*ps+goffset]=g;
+ buf[row*pitch+i*ps+boffset]=b;
+ }
+ }
+ }
+}
+
+
+int cmpBitmap(unsigned char *buf, int width, int pitch, int height, int pf,
+ int flags, int gray2rgb)
+{
+ int roffset=tjRedOffset[pf];
+ int goffset=tjGreenOffset[pf];
+ int boffset=tjBlueOffset[pf];
+ int aoffset=alphaOffset[pf];
+ int ps=tjPixelSize[pf];
+ int i, j;
+
+ for(j=0; j<height; j++)
+ {
+ int row=(flags&TJFLAG_BOTTOMUP)? height-j-1:j;
+ for(i=0; i<width; i++)
+ {
+ unsigned char r=(i*256/width)%256;
+ unsigned char g=(j*256/height)%256;
+ unsigned char b=(j*256/height+i*256/width)%256;
+ if(pf==TJPF_GRAY)
+ {
+ if(buf[row*pitch+i*ps]!=RGB2GRAY(r, g, b))
+ return 0;
+ }
+ else if(pf==TJPF_CMYK)
+ {
+ unsigned char rf, gf, bf;
+ cmyk_to_rgb(buf[row*pitch+i*ps+0], buf[row*pitch+i*ps+1],
+ buf[row*pitch+i*ps+2], buf[row*pitch+i*ps+3], &rf, &gf,
+ &bf);
+ if(gray2rgb)
+ {
+ unsigned char gray=RGB2GRAY(r, g, b);
+ if(rf!=gray || gf!=gray || bf!=gray)
+ return 0;
+ }
+ else if(rf!=r || gf!=g || bf!=b) return 0;
+ }
+ else
+ {
+ if(gray2rgb)
+ {
+ unsigned char gray=RGB2GRAY(r, g, b);
+ if(buf[row*pitch+i*ps+roffset]!=gray ||
+ buf[row*pitch+i*ps+goffset]!=gray ||
+ buf[row*pitch+i*ps+boffset]!=gray)
+ return 0;
+ }
+ else if(buf[row*pitch+i*ps+roffset]!=r ||
+ buf[row*pitch+i*ps+goffset]!=g ||
+ buf[row*pitch+i*ps+boffset]!=b)
+ return 0;
+ if(aoffset>=0 && buf[row*pitch+i*ps+aoffset]!=0xFF)
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+
+int doBmpTest(const char *ext, int width, int align, int height, int pf,
+ int flags)
+{
+ char filename[80], *md5sum, md5buf[65];
+ int ps=tjPixelSize[pf], pitch=PAD(width*ps, align),
+ loadWidth=0, loadHeight=0, retval=0;
+ unsigned char *buf=NULL;
+ char *md5ref;
+
+ if(pf==TJPF_GRAY)
+ {
+ md5ref=!strcasecmp(ext, "ppm")? "bc77dea8eaf006aa187582b301f67e02":
+ "2670a3f8cf19d855183c02ccf18d2a35";
+ }
+ else
+ {
+ md5ref=!strcasecmp(ext, "ppm")? "c0c9f772b464d1896326883a5c79c545":
+ "6d659071b9bfcdee2def22cb58ddadca";
+ }
+
+ if((buf=(unsigned char *)tjAlloc(pitch*height))==NULL)
+ _throw("Could not allocate memory");
+ initBitmap(buf, width, pitch, height, pf, flags);
+
+ snprintf(filename, 80, "test_bmp_%s_%d_%s.%s", pixFormatStr[pf], align,
+ (flags&TJFLAG_BOTTOMUP)? "bu":"td", ext);
+ _tj(tjSaveImage(filename, buf, width, pitch, height, pf, flags));
+ md5sum=MD5File(filename, md5buf);
+ if(strcasecmp(md5sum, md5ref))
+ _throwmd5(filename, md5sum, md5ref);
+
+ tjFree(buf); buf=NULL;
+ if((buf=tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
+ flags))==NULL)
+ _throwtj();
+ if(width!=loadWidth || height!=loadHeight)
+ {
+ printf("\n Image dimensions of %s are bogus\n", filename);
+ retval=-1; goto bailout;
+ }
+ if(!cmpBitmap(buf, width, pitch, height, pf, flags, 0))
+ {
+ printf("\n Pixel data in %s is bogus\n", filename);
+ retval=-1; goto bailout;
+ }
+ if(pf==TJPF_GRAY)
+ {
+ tjFree(buf); buf=NULL;
+ pf=TJPF_XBGR;
+ if((buf=tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
+ flags))==NULL)
+ _throwtj();
+ pitch=PAD(width*tjPixelSize[pf], align);
+ if(!cmpBitmap(buf, width, pitch, height, pf, flags, 1))
+ {
+ printf("\n Converting %s to RGB failed\n", filename);
+ retval=-1; goto bailout;
+ }
+
+ tjFree(buf); buf=NULL;
+ pf=TJPF_CMYK;
+ if((buf=tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
+ flags))==NULL)
+ _throwtj();
+ pitch=PAD(width*tjPixelSize[pf], align);
+ if(!cmpBitmap(buf, width, pitch, height, pf, flags, 1))
+ {
+ printf("\n Converting %s to CMYK failed\n", filename);
+ retval=-1; goto bailout;
+ }
+ }
+ else if(pf!=TJPF_CMYK)
+ {
+ tjFree(buf); buf=NULL;
+ pf=TJPF_GRAY;
+ if((buf=tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
+ flags))==NULL)
+ _throwtj();
+ pitch=PAD(width, align);
+ if(!cmpBitmap(buf, width, pitch, height, pf, flags, 0))
+ {
+ printf("\n Converting %s to grayscale failed\n", filename);
+ retval=-1; goto bailout;
+ }
+ }
+ unlink(filename);
+
+ bailout:
+ if(buf) tjFree(buf);
+ if(exitStatus<0) return exitStatus;
+ return retval;
+}
+
+
+int bmpTest(void)
+{
+ int align, width=35, height=39, format;
+
+ for(align=1; align<=8; align*=2)
+ {
+ for(format=0; format<TJ_NUMPF; format++)
+ {
+ printf("%s Top-Down BMP (row alignment = %d bytes) ... ",
+ pixFormatStr[format], align);
+ if(doBmpTest("bmp", width, align, height, format, 0)==-1)
+ return -1;
+ printf("OK.\n");
+
+ printf("%s Top-Down PPM (row alignment = %d bytes) ... ",
+ pixFormatStr[format], align);
+ if(doBmpTest("ppm", width, align, height, format, TJFLAG_BOTTOMUP)==-1)
+ return -1;
+ printf("OK.\n");
+
+ printf("%s Bottom-Up BMP (row alignment = %d bytes) ... ",
+ pixFormatStr[format], align);
+ if(doBmpTest("bmp", width, align, height, format, 0)==-1)
+ return -1;
+ printf("OK.\n");
+
+ printf("%s Bottom-Up PPM (row alignment = %d bytes) ... ",
+ pixFormatStr[format], align);
+ if(doBmpTest("ppm", width, align, height, format, TJFLAG_BOTTOMUP)==-1)
+ return -1;
+ printf("OK.\n");
+ }
+ }
+
+ return 0;
+}
+
+
int main(int argc, char *argv[])
{
int i, num4bf=5;
if(!strcasecmp(argv[i], "-yuv")) doyuv=1;
else if(!strcasecmp(argv[i], "-noyuvpad")) pad=1;
else if(!strcasecmp(argv[i], "-alloc")) alloc=1;
+ else if(!strcasecmp(argv[i], "-bmp")) return bmpTest();
else usage(argv[0]);
}
}
global:
tjGetErrorCode;
tjGetErrorStr2;
+ tjLoadImage;
+ tjSaveImage;
} TURBOJPEG_1.4;
global:
tjGetErrorCode;
tjGetErrorStr2;
+ tjLoadImage;
+ tjSaveImage;
} TURBOJPEG_1.4;
#include <jpeglib.h>
#include <jerror.h>
#include <setjmp.h>
+#include <errno.h>
#include "./turbojpeg.h"
#include "./tjutil.h"
#include "transupp.h"
#include "./jpegcomp.h"
+#include "./cdjpeg.h"
extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
unsigned long *, boolean);
{1, 8}
};
+static J_COLOR_SPACE pf2cs[TJ_NUMPF] =
+{
+ JCS_EXT_RGB, JCS_EXT_BGR, JCS_EXT_RGBX, JCS_EXT_BGRX, JCS_EXT_XBGR,
+ JCS_EXT_XRGB, JCS_GRAYSCALE, JCS_EXT_RGBA, JCS_EXT_BGRA, JCS_EXT_ABGR,
+ JCS_EXT_ARGB, JCS_CMYK
+};
+
+static int cs2pf[JPEG_NUMCS] =
+{
+ TJPF_UNKNOWN, TJPF_GRAY,
+#if RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 3
+ TJPF_RGB,
+#elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 3
+ TJPF_BGR,
+#elif RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 4
+ TJPF_RGBX,
+#elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 4
+ TJPF_BGRX,
+#elif RGB_RED == 3 && RGB_GREEN == 2 && RGB_BLUE == 1 && RGB_PIXELSIZE == 4
+ TJPF_XBGR,
+#elif RGB_RED == 1 && RGB_GREEN == 2 && RGB_BLUE == 3 && RGB_PIXELSIZE == 4
+ TJPF_XRGB,
+#endif
+ TJPF_UNKNOWN, TJPF_CMYK, TJPF_UNKNOWN, TJPF_RGB, TJPF_RGBX, TJPF_BGR,
+ TJPF_BGRX, TJPF_XBGR, TJPF_XRGB, TJPF_RGBA, TJPF_BGRA, TJPF_ABGR, TJPF_ARGB,
+ TJPF_UNKNOWN
+};
+
#define _throwg(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
retval=-1; goto bailout;}
+#define _throwunix(m) { \
+ snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, strerror(errno)); \
+ retval=-1; goto bailout; \
+}
#define _throw(m) {snprintf(this->errStr, JMSG_LENGTH_MAX, "%s", m); \
this->isInstanceError=TRUE; _throwg(m);}
#define getinstance(handle) tjinstance *this=(tjinstance *)handle; \
int retval=0;
char *env=NULL;
- switch(pixelFormat)
- {
- case TJPF_GRAY:
- cinfo->in_color_space=JCS_GRAYSCALE; break;
- #if JCS_EXTENSIONS==1
- case TJPF_RGB:
- cinfo->in_color_space=JCS_EXT_RGB; break;
- case TJPF_BGR:
- cinfo->in_color_space=JCS_EXT_BGR; break;
- case TJPF_RGBX:
- case TJPF_RGBA:
- cinfo->in_color_space=JCS_EXT_RGBX; break;
- case TJPF_BGRX:
- case TJPF_BGRA:
- cinfo->in_color_space=JCS_EXT_BGRX; break;
- case TJPF_XRGB:
- case TJPF_ARGB:
- cinfo->in_color_space=JCS_EXT_XRGB; break;
- case TJPF_XBGR:
- case TJPF_ABGR:
- cinfo->in_color_space=JCS_EXT_XBGR; break;
- #else
- case TJPF_RGB:
- case TJPF_BGR:
- case TJPF_RGBX:
- case TJPF_BGRX:
- case TJPF_XRGB:
- case TJPF_XBGR:
- case TJPF_RGBA:
- case TJPF_BGRA:
- case TJPF_ARGB:
- case TJPF_ABGR:
- cinfo->in_color_space=JCS_RGB; pixelFormat=TJPF_RGB;
- break;
- #endif
- case TJPF_CMYK:
- cinfo->in_color_space=JCS_CMYK; break;
- }
-
+ cinfo->in_color_space=pf2cs[pixelFormat];
cinfo->input_components=tjPixelSize[pixelFormat];
jpeg_set_defaults(cinfo);
return retval;
}
-static int setDecompDefaults(tjinstance *this, int pixelFormat, int flags)
-{
- int retval=0;
-
- switch(pixelFormat)
- {
- case TJPF_GRAY:
- this->dinfo.out_color_space=JCS_GRAYSCALE; break;
- #if JCS_EXTENSIONS==1
- case TJPF_RGB:
- this->dinfo.out_color_space=JCS_EXT_RGB; break;
- case TJPF_BGR:
- this->dinfo.out_color_space=JCS_EXT_BGR; break;
- case TJPF_RGBX:
- this->dinfo.out_color_space=JCS_EXT_RGBX; break;
- case TJPF_BGRX:
- this->dinfo.out_color_space=JCS_EXT_BGRX; break;
- case TJPF_XRGB:
- this->dinfo.out_color_space=JCS_EXT_XRGB; break;
- case TJPF_XBGR:
- this->dinfo.out_color_space=JCS_EXT_XBGR; break;
- #if JCS_ALPHA_EXTENSIONS==1
- case TJPF_RGBA:
- this->dinfo.out_color_space=JCS_EXT_RGBA; break;
- case TJPF_BGRA:
- this->dinfo.out_color_space=JCS_EXT_BGRA; break;
- case TJPF_ARGB:
- this->dinfo.out_color_space=JCS_EXT_ARGB; break;
- case TJPF_ABGR:
- this->dinfo.out_color_space=JCS_EXT_ABGR; break;
- #endif
- #else
- case TJPF_RGB:
- case TJPF_BGR:
- case TJPF_RGBX:
- case TJPF_BGRX:
- case TJPF_XRGB:
- case TJPF_XBGR:
- case TJPF_RGBA:
- case TJPF_BGRA:
- case TJPF_ARGB:
- case TJPF_ABGR:
- this->dinfo.out_color_space=JCS_RGB; break;
- #endif
- case TJPF_CMYK:
- this->dinfo.out_color_space=JCS_CMYK; break;
- default:
- _throw("Unsupported pixel format");
- }
-
- if(flags&TJFLAG_FASTDCT) this->dinfo.dct_method=JDCT_FASTEST;
-
- bailout:
- return retval;
-}
-
static int getSubsamp(j_decompress_ptr dinfo)
{
}
-#ifndef JCS_EXTENSIONS
-
-/* Conversion functions to emulate the colorspace extensions. This allows the
- TurboJPEG wrapper to be used with libjpeg */
-
-#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) { \
- int rowPad=pitch-width*PS; \
- while(height--) \
- { \
- unsigned char *endOfRow=src+width*PS; \
- while(src<endOfRow) \
- { \
- dst[RGB_RED]=src[ROFFSET]; \
- dst[RGB_GREEN]=src[GOFFSET]; \
- dst[RGB_BLUE]=src[BOFFSET]; \
- dst+=RGB_PIXELSIZE; src+=PS; \
- } \
- src+=rowPad; \
- } \
-}
-
-static unsigned char *toRGB(unsigned char *src, int width, int pitch,
- int height, int pixelFormat, unsigned char *dst)
-{
- unsigned char *retval=src;
- switch(pixelFormat)
- {
- case TJPF_RGB:
- #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
- retval=dst; TORGB(3, 0, 1, 2);
- #endif
- break;
- case TJPF_BGR:
- #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
- retval=dst; TORGB(3, 2, 1, 0);
- #endif
- break;
- case TJPF_RGBX:
- case TJPF_RGBA:
- #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
- retval=dst; TORGB(4, 0, 1, 2);
- #endif
- break;
- case TJPF_BGRX:
- case TJPF_BGRA:
- #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
- retval=dst; TORGB(4, 2, 1, 0);
- #endif
- break;
- case TJPF_XRGB:
- case TJPF_ARGB:
- #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
- retval=dst; TORGB(4, 1, 2, 3);
- #endif
- break;
- case TJPF_XBGR:
- case TJPF_ABGR:
- #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
- retval=dst; TORGB(4, 3, 2, 1);
- #endif
- break;
- }
- return retval;
-}
-
-#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) { \
- int rowPad=pitch-width*PS; \
- while(height--) \
- { \
- unsigned char *endOfRow=dst+width*PS; \
- while(dst<endOfRow) \
- { \
- dst[ROFFSET]=src[RGB_RED]; \
- dst[GOFFSET]=src[RGB_GREEN]; \
- dst[BOFFSET]=src[RGB_BLUE]; \
- SETALPHA \
- dst+=PS; src+=RGB_PIXELSIZE; \
- } \
- dst+=rowPad; \
- } \
-}
-
-static void fromRGB(unsigned char *src, unsigned char *dst, int width,
- int pitch, int height, int pixelFormat)
-{
- switch(pixelFormat)
- {
- case TJPF_RGB:
- #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
- FROMRGB(3, 0, 1, 2,);
- #endif
- break;
- case TJPF_BGR:
- #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
- FROMRGB(3, 2, 1, 0,);
- #endif
- break;
- case TJPF_RGBX:
- #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
- FROMRGB(4, 0, 1, 2,);
- #endif
- break;
- case TJPF_RGBA:
- #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
- FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
- #endif
- break;
- case TJPF_BGRX:
- #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
- FROMRGB(4, 2, 1, 0,);
- #endif
- break;
- case TJPF_BGRA:
- #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
- FROMRGB(4, 2, 1, 0, dst[3]=0xFF;); return;
- #endif
- break;
- case TJPF_XRGB:
- #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
- FROMRGB(4, 1, 2, 3,); return;
- #endif
- break;
- case TJPF_ARGB:
- #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
- FROMRGB(4, 1, 2, 3, dst[0]=0xFF;); return;
- #endif
- break;
- case TJPF_XBGR:
- #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
- FROMRGB(4, 3, 2, 1,); return;
- #endif
- break;
- case TJPF_ABGR:
- #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
- FROMRGB(4, 3, 2, 1, dst[0]=0xFF;); return;
- #endif
- break;
- }
-}
-
-#endif
-
-
/* General API functions */
DLLEXPORT char* DLLCALL tjGetErrorStr2(tjhandle handle)
unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
{
int i, retval=0, alloc=1; JSAMPROW *row_pointer=NULL;
- #ifndef JCS_EXTENSIONS
- unsigned char *rgbBuf=NULL;
- #endif
getcinstance(handle)
this->jerr.stopOnWarning=(flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
- #ifndef JCS_EXTENSIONS
- if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
- {
- rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
- if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
- srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
- pitch=width*RGB_PIXELSIZE;
- }
- #endif
-
if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
_throw("tjCompress2(): Memory allocation failure");
bailout:
if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
- #ifndef JCS_EXTENSIONS
- if(rgbBuf) free(rgbBuf);
- #endif
if(row_pointer) free(row_pointer);
if(this->jerr.warning) retval=-1;
this->jerr.stopOnWarning=FALSE;
int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
JSAMPLE *ptr;
jpeg_component_info *compptr;
- #ifndef JCS_EXTENSIONS
- unsigned char *rgbBuf=NULL;
- #endif
getcinstance(handle);
this->jerr.stopOnWarning=(flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
- #ifndef JCS_EXTENSIONS
- if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
- {
- rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
- if(!rgbBuf) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
- srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
- pitch=width*RGB_PIXELSIZE;
- }
- #endif
-
if(setjmp(this->jerr.setjmp_buffer))
{
/* If we get here, the JPEG code has signaled an error. */
bailout:
if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
- #ifndef JCS_EXTENSIONS
- if(rgbBuf) free(rgbBuf);
- #endif
if(row_pointer) free(row_pointer);
for(i=0; i<MAX_COMPONENTS; i++)
{
{
int i, retval=0; JSAMPROW *row_pointer=NULL;
int jpegwidth, jpegheight, scaledw, scaledh;
- #ifndef JCS_EXTENSIONS
- unsigned char *rgbBuf=NULL;
- unsigned char *_dstBuf=NULL; int _pitch=0;
- #endif
getdinstance(handle);
this->jerr.stopOnWarning=(flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
jpeg_read_header(dinfo, TRUE);
- if(setDecompDefaults(this, pixelFormat, flags)==-1)
- {
- retval=-1; goto bailout;
- }
-
+ this->dinfo.out_color_space=pf2cs[pixelFormat];
+ if(flags&TJFLAG_FASTDCT) this->dinfo.dct_method=JDCT_FASTEST;
if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
jpeg_start_decompress(dinfo);
if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
- #ifndef JCS_EXTENSIONS
- if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
- (RGB_RED!=tjRedOffset[pixelFormat] ||
- RGB_GREEN!=tjGreenOffset[pixelFormat] ||
- RGB_BLUE!=tjBlueOffset[pixelFormat] ||
- RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
- {
- rgbBuf=(unsigned char *)malloc(width*height*3);
- if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
- _pitch=pitch; pitch=width*3;
- _dstBuf=dstBuf; dstBuf=rgbBuf;
- }
- #endif
-
if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
*dinfo->output_height))==NULL)
_throw("tjDecompress2(): Memory allocation failure");
}
jpeg_finish_decompress(dinfo);
- #ifndef JCS_EXTENSIONS
- fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
- #endif
-
bailout:
if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
- #ifndef JCS_EXTENSIONS
- if(rgbBuf) free(rgbBuf);
- #endif
if(row_pointer) free(row_pointer);
if(this->jerr.warning) retval=-1;
this->jerr.stopOnWarning=FALSE;
int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
JSAMPLE *ptr;
jpeg_component_info *compptr;
- #ifndef JCS_EXTENSIONS
- unsigned char *rgbBuf=NULL;
- unsigned char *_dstBuf=NULL; int _pitch=0;
- #endif
int (*old_read_markers)(j_decompress_ptr);
void (*old_reset_marker_reader)(j_decompress_ptr);
dinfo->marker->read_markers=old_read_markers;
dinfo->marker->reset_marker_reader=old_reset_marker_reader;
- if(setDecompDefaults(this, pixelFormat, flags)==-1)
- {
- retval=-1; goto bailout;
- }
+ this->dinfo.out_color_space=pf2cs[pixelFormat];
+ if(flags&TJFLAG_FASTDCT) this->dinfo.dct_method=JDCT_FASTEST;
dinfo->do_fancy_upsampling=FALSE;
dinfo->Se=DCTSIZE2-1;
jinit_master_decompress(dinfo);
if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
- #ifndef JCS_EXTENSIONS
- if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
- (RGB_RED!=tjRedOffset[pixelFormat] ||
- RGB_GREEN!=tjGreenOffset[pixelFormat] ||
- RGB_BLUE!=tjBlueOffset[pixelFormat] ||
- RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
- {
- rgbBuf=(unsigned char *)malloc(width*height*3);
- if(!rgbBuf) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
- _pitch=pitch; pitch=width*3;
- _dstBuf=dstBuf; dstBuf=rgbBuf;
- }
- #endif
-
if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
_throw("tjDecodeYUVPlanes(): Memory allocation failure");
for(i=0; i<height; i++)
}
jpeg_abort_decompress(dinfo);
- #ifndef JCS_EXTENSIONS
- fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
- #endif
-
bailout:
if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
- #ifndef JCS_EXTENSIONS
- if(rgbBuf) free(rgbBuf);
- #endif
if(row_pointer) free(row_pointer);
for(i=0; i<MAX_COMPONENTS; i++)
{
this->jerr.stopOnWarning=FALSE;
return retval;
}
+
+
+DLLEXPORT unsigned char* DLLCALL tjLoadImage(const char *filename, int *width,
+ int align, int *height, int *pixelFormat, int flags)
+{
+ int retval=0, tempc, pitch;
+ tjhandle handle=NULL;
+ tjinstance *this;
+ j_compress_ptr cinfo=NULL;
+ cjpeg_source_ptr src;
+ unsigned char *dstBuf=NULL;
+ FILE *file=NULL;
+ boolean invert;
+
+ if(!filename || !width || align<1 || !height || !pixelFormat ||
+ *pixelFormat<TJPF_UNKNOWN || *pixelFormat>=TJ_NUMPF)
+ _throwg("tjLoadImage(): Invalid argument");
+ if((align&(align-1))!=0)
+ _throwg("tjLoadImage(): Alignment must be a power of 2");
+
+ if((handle=tjInitCompress())==NULL) return NULL;
+ this=(tjinstance *)handle;
+ cinfo=&this->cinfo;
+
+ if((file=fopen(filename, "rb"))==NULL)
+ _throwunix("tjLoadImage(): Cannot open input file");
+
+ if((tempc=getc(file))<0 || ungetc(tempc, file)==EOF)
+ _throwunix("tjLoadImage(): Could not read input file")
+ else if(tempc==EOF) _throwg("tjLoadImage(): Input file contains no data");
+
+ if(setjmp(this->jerr.setjmp_buffer))
+ {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval=-1; goto bailout;
+ }
+
+ cinfo->in_color_space=pf2cs[*pixelFormat];
+ if(tempc=='B')
+ {
+ if((src=jinit_read_bmp(cinfo, FALSE))==NULL)
+ _throwg("tjLoadImage(): Could not initialize bitmap loader");
+ invert=(flags&TJFLAG_BOTTOMUP)==0;
+ }
+ else if(tempc=='P')
+ {
+ if((src=jinit_read_ppm(cinfo))==NULL)
+ _throwg("tjLoadImage(): Could not initialize bitmap loader");
+ invert=(flags&TJFLAG_BOTTOMUP)!=0;
+ }
+ else _throwg("tjLoadImage(): Unsupported file type");
+
+ src->input_file=file;
+ (*src->start_input)(cinfo, src);
+ (*cinfo->mem->realize_virt_arrays)((j_common_ptr)cinfo);
+
+ *width=cinfo->image_width; *height=cinfo->image_height;
+ *pixelFormat=cs2pf[cinfo->in_color_space];
+
+ pitch=PAD((*width)*tjPixelSize[*pixelFormat], align);
+ if((dstBuf=(unsigned char *)malloc(pitch*(*height)))==NULL)
+ _throwg("tjLoadImage(): Memory allocation failure");
+
+ if(setjmp(this->jerr.setjmp_buffer))
+ {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval=-1; goto bailout;
+ }
+
+ while(cinfo->next_scanline<cinfo->image_height)
+ {
+ int i, nlines=(*src->get_pixel_rows)(cinfo, src);
+ for(i=0; i<nlines; i++)
+ {
+ unsigned char *dstptr; int row;
+ row=cinfo->next_scanline+i;
+ if(invert) dstptr=&dstBuf[((*height)-row-1)*pitch];
+ else dstptr=&dstBuf[row*pitch];
+ memcpy(dstptr, src->buffer[i], (*width)*tjPixelSize[*pixelFormat]);
+ }
+ cinfo->next_scanline+=nlines;
+ }
+
+ (*src->finish_input)(cinfo, src);
+
+ bailout:
+ if(handle) tjDestroy(handle);
+ if(file) fclose(file);
+ if(retval<0 && dstBuf) {free(dstBuf); dstBuf=NULL;}
+ return dstBuf;
+}
+
+
+DLLEXPORT int DLLCALL tjSaveImage(const char *filename, unsigned char *buffer,
+ int width, int pitch, int height, int pixelFormat, int flags)
+{
+ int retval=0;
+ tjhandle handle=NULL;
+ tjinstance *this;
+ j_decompress_ptr dinfo=NULL;
+ djpeg_dest_ptr dst;
+ FILE *file=NULL;
+ char *ptr=NULL;
+ boolean invert;
+
+ if(!filename || !buffer || width<1 || pitch<0 || height<1 || pixelFormat<0 ||
+ pixelFormat>=TJ_NUMPF)
+ _throwg("tjSaveImage(): Invalid argument");
+
+ if((handle=tjInitDecompress())==NULL)
+ return -1;
+ this=(tjinstance *)handle;
+ dinfo=&this->dinfo;
+
+ if((file=fopen(filename, "wb"))==NULL)
+ _throwunix("tjSaveImage(): Cannot open output file");
+
+ if(setjmp(this->jerr.setjmp_buffer))
+ {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval=-1; goto bailout;
+ }
+
+ this->dinfo.out_color_space=pf2cs[pixelFormat];
+ dinfo->image_width=width; dinfo->image_height=height;
+ dinfo->global_state=DSTATE_READY;
+ dinfo->scale_num=dinfo->scale_denom=1;
+
+ ptr=strrchr(filename, '.');
+ if(ptr && !strcasecmp(ptr, ".bmp"))
+ {
+ if((dst=jinit_write_bmp(dinfo, FALSE, FALSE))==NULL)
+ _throwg("tjSaveImage(): Could not initialize bitmap writer");
+ invert=(flags&TJFLAG_BOTTOMUP)==0;
+ }
+ else
+ {
+ if((dst=jinit_write_ppm(dinfo))==NULL)
+ _throwg("tjSaveImage(): Could not initialize PPM writer");
+ invert=(flags&TJFLAG_BOTTOMUP)!=0;
+ }
+
+ dst->output_file=file;
+ (*dst->start_output)(dinfo, dst);
+ (*dinfo->mem->realize_virt_arrays)((j_common_ptr)dinfo);
+
+ if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
+
+ while(dinfo->output_scanline<dinfo->output_height)
+ {
+ unsigned char *rowptr;
+ if(invert) rowptr=&buffer[(height-dinfo->output_scanline-1)*pitch];
+ else rowptr=&buffer[dinfo->output_scanline*pitch];
+ memcpy(dst->buffer[0], rowptr, width*tjPixelSize[pixelFormat]);
+ (*dst->put_pixel_rows)(dinfo, dst, 1);
+ dinfo->output_scanline++;
+ }
+
+ (*dst->finish_output)(dinfo, dst);
+
+ bailout:
+ if(handle) tjDestroy(handle);
+ if(file) fclose(file);
+ return retval;
+}
* CMYK pixels into a YCCK JPEG image (see #TJCS_YCCK) and decompressing YCCK
* JPEG images into CMYK pixels.
*/
- TJPF_CMYK
+ TJPF_CMYK,
+ /**
+ * Unknown pixel format. Currently this is only used by #tjLoadImage().
+ */
+ TJPF_UNKNOWN = -1
};
DLLEXPORT unsigned char* DLLCALL tjAlloc(int bytes);
+/**
+ * Load an uncompressed image from disk into memory.
+ *
+ * @param filename name of a file containing an uncompressed image in Windows
+ * BMP or PBMPLUS (PPM/PGM) format
+ *
+ * @param width pointer to an integer variable that will receive the width (in
+ * pixels) of the uncompressed image
+ *
+ * @param align row alignment of the image buffer to be returned (must be a
+ * power of 2.) For instance, setting this parameter to 4 will cause all rows
+ * in the image buffer to be padded to the nearest 32-bit boundary, and setting
+ * this parameter to 1 will cause all rows in the image buffer to be unpadded.
+ *
+ * @param height pointer to an integer variable that will receive the height
+ * (in pixels) of the uncompressed image
+ *
+ * @param pixelFormat pointer to an integer variable that specifies or will
+ * receive the pixel format of the uncompressed image buffer. If
+ * <tt>*pixelFormat</tt> is set to @ref TJPF_UNKNOWN prior to calling this
+ * function, then the uncompressed image buffer returned by the function will
+ * use the most optimal pixel format for the file type, and
+ * <tt>*pixelFormat</tt> will contain the ID of this pixel format upon
+ * successful return from the function. Otherwise, the uncompressed image
+ * buffer will use the @ref TJPF "pixel format" specified in
+ * <tt>*pixelFormat</tt>, and pixel format conversion will be performed if
+ * necessary. If <tt>*pixelFormat</tt> is set to @ref TJPF_CMYK, then the RGB
+ * or grayscale pixels stored in the file will be converted using a quick &
+ * dirty algorithm that is suitable only for testing purposes (proper
+ * conversion between CMYK and other formats requires a color management
+ * system.)
+ *
+ * @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP
+ * "flags".
+ *
+ * @return a pointer to a newly-allocated buffer containing the uncompressed
+ * image, converted to the chosen pixel format and with the chosen row
+ * alignment, or NULL if an error occurred (see #tjGetErrorStr2().) This
+ * buffer should be freed using #tjFree().
+ */
+DLLEXPORT unsigned char* DLLCALL tjLoadImage(const char *filename, int *width,
+ int align, int *height, int *pixelFormat, int flags);
+
+
+/**
+ * Save an uncompressed image from memory to disk.
+ *
+ * @param filename name of a file to which to save the uncompressed image.
+ * The image will be stored in Windows BMP or PBMPLUS (PPM/PGM) format,
+ * depending on the file extension.
+ *
+ * @param buffer pointer to an image buffer containing RGB, grayscale, or
+ * CMYK pixels to be saved
+ *
+ * @param width width (in pixels) of the uncompressed image
+ *
+ * @param pitch bytes per line in the image buffer. Setting this parameter to
+ * 0 is the equivalent of setting it to
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>.
+ *
+ * @param height height (in pixels) of the uncompressed image
+ *
+ * @param pixelFormat pixel format of the image buffer (see @ref TJPF
+ * "Pixel formats".) If this parameter is set to @ref TJPF_GRAY, then the
+ * image will be stored in PGM or 8-bit (indexed color) BMP format. Otherwise,
+ * the image will be stored in PPM or 24-bit BMP format. If this parameter
+ * is set to @ref TJPF_CMYK, then the CMYK pixels will be converted to RGB
+ * using a quick & dirty algorithm that is suitable only for testing (proper
+ * conversion between CMYK and other formats requires a color management
+ * system.)
+ *
+ * @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP
+ * "flags".
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2().)
+ */
+DLLEXPORT int DLLCALL tjSaveImage(const char *filename, unsigned char *buffer,
+ int width, int pitch, int height, int pixelFormat, int flags);
+
+
/**
* Free an image buffer previously allocated by TurboJPEG. You should always
* use this function to free JPEG destination buffer(s) that were automatically
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
#include "jconfigint.h"
+#include "cmyk.h"
#ifdef BMP_SUPPORTED
JDIMENSION row_width; /* physical width of one row in the BMP file */
int pad_bytes; /* number of padding bytes needed per row */
JDIMENSION cur_output_row; /* next row# to write to virtual array */
+
+ boolean use_inversion_array; /* TRUE = buffer the whole image, which is
+ stored to disk in bottom-up order, and
+ receive rows from the calling program in
+ top-down order
+
+ FALSE = the calling program will maintain
+ its own image buffer and write the rows in
+ bottom-up order */
+
+ JSAMPLE *iobuffer; /* I/O buffer (used to buffer a single row to
+ disk if use_inversion_array == FALSE) */
} bmp_dest_struct;
typedef bmp_dest_struct *bmp_dest_ptr;
register JDIMENSION col;
int pad;
- /* Access next row in virtual array */
- image_ptr = (*cinfo->mem->access_virt_sarray)
- ((j_common_ptr) cinfo, dest->whole_image,
- dest->cur_output_row, (JDIMENSION) 1, TRUE);
- dest->cur_output_row++;
+ if (dest->use_inversion_array) {
+ /* Access next row in virtual array */
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->whole_image,
+ dest->cur_output_row, (JDIMENSION) 1, TRUE);
+ dest->cur_output_row++;
+ outptr = image_ptr[0];
+ } else {
+ outptr = dest->iobuffer;
+ }
/* Transfer data. Note destination values must be in BGR order
* (even though Microsoft's own documents say the opposite).
*/
inptr = dest->pub.buffer[0];
- outptr = image_ptr[0];
- if (cinfo->out_color_space == JCS_RGB565) {
+ if (cinfo->out_color_space == JCS_EXT_BGR) {
+ MEMCOPY(outptr, inptr, dest->row_width);
+ outptr += cinfo->output_width * 3;
+ } else if (cinfo->out_color_space == JCS_RGB565) {
boolean big_endian = is_big_endian();
unsigned short *inptr2 = (unsigned short *)inptr;
for (col = cinfo->output_width; col > 0; col--) {
outptr += 3;
inptr2++;
}
- } else {
+ } else if (cinfo->out_color_space == JCS_CMYK) {
for (col = cinfo->output_width; col > 0; col--) {
- outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
- outptr[1] = *inptr++;
- outptr[0] = *inptr++;
+ /* can omit GETJSAMPLE() safely */
+ JSAMPLE c = *inptr++, m = *inptr++, y = *inptr++, k = *inptr++;
+ cmyk_to_rgb(c, m, y, k, outptr + 2, outptr + 1, outptr);
outptr += 3;
}
+ } else {
+ register int rindex = rgb_red[cinfo->out_color_space];
+ register int gindex = rgb_green[cinfo->out_color_space];
+ register int bindex = rgb_blue[cinfo->out_color_space];
+ register int ps = rgb_pixelsize[cinfo->out_color_space];
+
+ for (col = cinfo->output_width; col > 0; col--) {
+ /* can omit GETJSAMPLE() safely */
+ outptr[0] = inptr[bindex];
+ outptr[1] = inptr[gindex];
+ outptr[2] = inptr[rindex];
+ outptr += 3; inptr += ps;
+ }
}
/* Zero out the pad bytes. */
pad = dest->pad_bytes;
while (--pad >= 0)
*outptr++ = 0;
+
+ if (!dest->use_inversion_array)
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->row_width);
}
METHODDEF(void)
bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
JSAMPARRAY image_ptr;
register JSAMPROW inptr, outptr;
- register JDIMENSION col;
int pad;
- /* Access next row in virtual array */
- image_ptr = (*cinfo->mem->access_virt_sarray)
- ((j_common_ptr) cinfo, dest->whole_image,
- dest->cur_output_row, (JDIMENSION) 1, TRUE);
- dest->cur_output_row++;
+ if (dest->use_inversion_array) {
+ /* Access next row in virtual array */
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->whole_image,
+ dest->cur_output_row, (JDIMENSION) 1, TRUE);
+ dest->cur_output_row++;
+ outptr = image_ptr[0];
+ } else {
+ outptr = dest->iobuffer;
+ }
/* Transfer data. */
inptr = dest->pub.buffer[0];
- outptr = image_ptr[0];
- for (col = cinfo->output_width; col > 0; col--) {
- *outptr++ = *inptr++; /* can omit GETJSAMPLE() safely */
- }
+ MEMCOPY(outptr, inptr, cinfo->output_width);
+ outptr += cinfo->output_width;
/* Zero out the pad bytes. */
pad = dest->pad_bytes;
while (--pad >= 0)
*outptr++ = 0;
-}
-
-
-/*
- * Startup: normally writes the file header.
- * In this module we may as well postpone everything until finish_output.
- */
-METHODDEF(void)
-start_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
-{
- /* no work here */
+ if (!dest->use_inversion_array)
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->row_width);
}
int bits_per_pixel, cmap_entries;
/* Compute colormap size and total file size */
- if (cinfo->out_color_space == JCS_RGB) {
+ if (IsExtRGB(cinfo->out_color_space)) {
if (cinfo->quantize_colors) {
/* Colormapped RGB */
bits_per_pixel = 8;
bits_per_pixel = 24;
cmap_entries = 0;
}
- } else if (cinfo->out_color_space == JCS_RGB565) {
+ } else if (cinfo->out_color_space == JCS_RGB565 ||
+ cinfo->out_color_space == JCS_CMYK) {
bits_per_pixel = 24;
cmap_entries = 0;
} else {
int bits_per_pixel, cmap_entries;
/* Compute colormap size and total file size */
- if (cinfo->out_color_space == JCS_RGB) {
+ if (cinfo->out_color_space == JCS_RGB ||
+ (cinfo->out_color_space >= JCS_EXT_RGB &&
+ cinfo->out_color_space <= JCS_EXT_ARGB)) {
if (cinfo->quantize_colors) {
/* Colormapped RGB */
bits_per_pixel = 8;
bits_per_pixel = 24;
cmap_entries = 0;
}
- } else if (cinfo->out_color_space == JCS_RGB565) {
+ } else if (cinfo->out_color_space == JCS_RGB565 ||
+ cinfo->out_color_space == JCS_CMYK) {
bits_per_pixel = 24;
cmap_entries = 0;
} else {
}
+/*
+ * Startup: write the file header unless the inversion array is being used.
+ */
+
+METHODDEF(void)
+start_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
+
+ if (!dest->use_inversion_array) {
+ /* Write the header and colormap */
+ if (dest->is_os2)
+ write_os2_header(cinfo, dest);
+ else
+ write_bmp_header(cinfo, dest);
+ }
+}
+
+
METHODDEF(void)
finish_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
{
register JDIMENSION col;
cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
- /* Write the header and colormap */
- if (dest->is_os2)
- write_os2_header(cinfo, dest);
- else
- write_bmp_header(cinfo, dest);
-
- /* Write the file body from our virtual array */
- for (row = cinfo->output_height; row > 0; row--) {
- if (progress != NULL) {
- progress->pub.pass_counter = (long) (cinfo->output_height - row);
- progress->pub.pass_limit = (long) cinfo->output_height;
- (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
- }
- image_ptr = (*cinfo->mem->access_virt_sarray)
- ((j_common_ptr) cinfo, dest->whole_image, row-1, (JDIMENSION) 1, FALSE);
- data_ptr = image_ptr[0];
- for (col = dest->row_width; col > 0; col--) {
- putc(GETJSAMPLE(*data_ptr), outfile);
- data_ptr++;
+ if (dest->use_inversion_array) {
+ /* Write the header and colormap */
+ if (dest->is_os2)
+ write_os2_header(cinfo, dest);
+ else
+ write_bmp_header(cinfo, dest);
+
+ /* Write the file body from our virtual array */
+ for (row = cinfo->output_height; row > 0; row--) {
+ if (progress != NULL) {
+ progress->pub.pass_counter = (long) (cinfo->output_height - row);
+ progress->pub.pass_limit = (long) cinfo->output_height;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->whole_image, row-1, (JDIMENSION) 1, FALSE);
+ data_ptr = image_ptr[0];
+ for (col = dest->row_width; col > 0; col--) {
+ putc(GETJSAMPLE(*data_ptr), outfile);
+ data_ptr++;
+ }
}
+ if (progress != NULL)
+ progress->completed_extra_passes++;
}
- if (progress != NULL)
- progress->completed_extra_passes++;
/* Make sure we wrote the output file OK */
fflush(outfile);
*/
GLOBAL(djpeg_dest_ptr)
-jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2)
+jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2,
+ boolean use_inversion_array)
{
bmp_dest_ptr dest;
JDIMENSION row_width;
if (cinfo->out_color_space == JCS_GRAYSCALE) {
dest->pub.put_pixel_rows = put_gray_rows;
- } else if (cinfo->out_color_space == JCS_RGB) {
+ } else if (cinfo->out_color_space == JCS_RGB ||
+ (cinfo->out_color_space >= JCS_EXT_RGB &&
+ cinfo->out_color_space <= JCS_EXT_ARGB)) {
if (cinfo->quantize_colors)
dest->pub.put_pixel_rows = put_gray_rows;
else
dest->pub.put_pixel_rows = put_pixel_rows;
- } else if (cinfo->out_color_space == JCS_RGB565) {
+ } else if (cinfo->out_color_space == JCS_RGB565 ||
+ cinfo->out_color_space == JCS_CMYK) {
dest->pub.put_pixel_rows = put_pixel_rows;
} else {
ERREXIT(cinfo, JERR_BMP_COLORSPACE);
if (cinfo->out_color_space == JCS_RGB565) {
row_width = cinfo->output_width * 2;
dest->row_width = dest->data_width = cinfo->output_width * 3;
+ while ((row_width & 3) != 0) row_width++;
+ } else if (!cinfo->quantize_colors &&
+ (IsExtRGB(cinfo->out_color_space) ||
+ cinfo->out_color_space == JCS_CMYK)) {
+ row_width = cinfo->output_width * cinfo->output_components;
+ dest->row_width = dest->data_width = cinfo->output_width * 3;
} else {
row_width = cinfo->output_width * cinfo->output_components;
dest->row_width = dest->data_width = row_width;
}
while ((dest->row_width & 3) != 0) dest->row_width++;
dest->pad_bytes = (int) (dest->row_width - dest->data_width);
- if (cinfo->out_color_space == JCS_RGB565) {
- while ((row_width & 3) != 0) row_width++;
- } else {
- row_width = dest->row_width;
- }
- /* Allocate space for inversion array, prepare for write pass */
- dest->whole_image = (*cinfo->mem->request_virt_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
- dest->row_width, cinfo->output_height, (JDIMENSION) 1);
- dest->cur_output_row = 0;
- if (cinfo->progress != NULL) {
- cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
- progress->total_extra_passes++; /* count file input as separate pass */
+ if (use_inversion_array) {
+ /* Allocate space for inversion array, prepare for write pass */
+ dest->whole_image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ dest->row_width, cinfo->output_height, (JDIMENSION) 1);
+ dest->cur_output_row = 0;
+ if (cinfo->progress != NULL) {
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+ progress->total_extra_passes++; /* count file input as separate pass */
+ }
+ } else {
+ dest->iobuffer = (JSAMPLE *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, dest->row_width);
}
+ dest->use_inversion_array = use_inversion_array;
/* Create decompressor output buffer. */
dest->pub.buffer = (*cinfo->mem->alloc_sarray)
*/
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+#include "cmyk.h"
#ifdef PPM_SUPPORTED
ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
register char *bufferptr;
register JSAMPROW ptr;
+#if BITS_IN_JSAMPLE != 8 || (!defined(HAVE_UNSIGNED_CHAR) && !defined(__CHAR_UNSIGNED__))
register JDIMENSION col;
+#endif
ptr = dest->pub.buffer[0];
bufferptr = dest->iobuffer;
+#if BITS_IN_JSAMPLE == 8 && (defined(HAVE_UNSIGNED_CHAR) || defined(__CHAR_UNSIGNED__))
+ MEMCOPY(bufferptr, ptr, dest->samples_per_row);
+#else
for (col = dest->samples_per_row; col > 0; col--) {
PUTPPMSAMPLE(bufferptr, GETJSAMPLE(*ptr++));
}
+#endif
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+
+/*
+ * Convert extended RGB to RGB.
+ */
+
+METHODDEF(void)
+put_rgb (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
+ register char *bufferptr;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+ register int rindex = rgb_red[cinfo->out_color_space];
+ register int gindex = rgb_green[cinfo->out_color_space];
+ register int bindex = rgb_blue[cinfo->out_color_space];
+ register int ps = rgb_pixelsize[cinfo->out_color_space];
+
+ ptr = dest->pub.buffer[0];
+ bufferptr = dest->iobuffer;
+ for (col = cinfo->output_width; col > 0; col--) {
+ PUTPPMSAMPLE(bufferptr, ptr[rindex]);
+ PUTPPMSAMPLE(bufferptr, ptr[gindex]);
+ PUTPPMSAMPLE(bufferptr, ptr[bindex]);
+ ptr += ps;
+ }
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+
+/*
+ * Convert CMYK to RGB.
+ */
+
+METHODDEF(void)
+put_cmyk (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
+ register char *bufferptr;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+
+ ptr = dest->pub.buffer[0];
+ bufferptr = dest->iobuffer;
+ for (col = cinfo->output_width; col > 0; col--) {
+ JSAMPLE r, g, b, c = *ptr++, m = *ptr++, y = *ptr++, k = *ptr++;
+ cmyk_to_rgb(c, m, y, k, &r, &g, &b);
+ PUTPPMSAMPLE(bufferptr, r);
+ PUTPPMSAMPLE(bufferptr, g);
+ PUTPPMSAMPLE(bufferptr, b);
+ }
(void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
}
PPM_MAXVAL);
break;
case JCS_RGB:
+ case JCS_EXT_RGB:
+ case JCS_EXT_RGBX:
+ case JCS_EXT_BGR:
+ case JCS_EXT_BGRX:
+ case JCS_EXT_XBGR:
+ case JCS_EXT_XRGB:
+ case JCS_EXT_RGBA:
+ case JCS_EXT_BGRA:
+ case JCS_EXT_ABGR:
+ case JCS_EXT_ARGB:
+ case JCS_CMYK:
/* emit header for raw PPM format */
fprintf(dest->pub.output_file, "P6\n%ld %ld\n%d\n",
(long) cinfo->output_width, (long) cinfo->output_height,
{
ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
- dest->samples_per_row = cinfo->output_width * cinfo->out_color_components;
+ if (cinfo->out_color_space == JCS_GRAYSCALE)
+ dest->samples_per_row = cinfo->output_width * cinfo->out_color_components;
+ else
+ dest->samples_per_row = cinfo->output_width * 3;
dest->buffer_width = dest->samples_per_row * (BYTESPERSAMPLE * sizeof(char));
}
((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width);
if (cinfo->quantize_colors || BITS_IN_JSAMPLE != 8 ||
- sizeof(JSAMPLE) != sizeof(char)) {
+ sizeof(JSAMPLE) != sizeof(char) ||
+ (cinfo->out_color_space != JCS_EXT_RGB
+#if RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 3
+ && cinfo->out_color_space != JCS_RGB
+#endif
+ )) {
/* When quantizing, we need an output buffer for colormap indexes
* that's separate from the physical I/O buffer. We also need a
* separate buffer if pixel format translation must take place.
((j_common_ptr) cinfo, JPOOL_IMAGE,
cinfo->output_width * cinfo->output_components, (JDIMENSION) 1);
dest->pub.buffer_height = 1;
- if (! cinfo->quantize_colors)
+ if (IsExtRGB(cinfo->out_color_space))
+ dest->pub.put_pixel_rows = put_rgb;
+ else if (cinfo->out_color_space == JCS_CMYK)
+ dest->pub.put_pixel_rows = put_cmyk;
+ else if (! cinfo->quantize_colors)
dest->pub.put_pixel_rows = copy_pixel_rows;
else if (cinfo->out_color_space == JCS_GRAYSCALE)
dest->pub.put_pixel_rows = put_demapped_gray;