TurboJPEG C API: Add BMP/PPM load/save functions

The main justification for this is to provide new libjpeg-turbo users
with a quick & easy way of developing a complete JPEG
compression/decompression program without requiring them to build
libjpeg-turbo from source (which was necessary in order to use the
project-private bmp API) or to use external libraries.  These new
functions build upon significant enhancements to rdbmp.c, wrbmp.c,
rdppm.c, and wrppm.c which allow those engines to convert directly
between the native pixel format of the file and a pixel format
("colorspace" in libjpeg parlance) specified by the calling program.
rdbmp.c and wrbmp.c have also been modified such that the calling
program can choose to read or write image rows in the native (bottom-up)
order of the file format, thus eliminating the need to use an inversion
array.  tjLoadImage() and tjSaveImage() leverage these new underlying
features in order to significantly improve upon the performance of the
old bmp API.

Because these new functions cannot work without the libjpeg-turbo
colorspace extensions, the libjpeg-compatible code in turbojpeg.c has
been removed.  That code was only there to serve as an example of how
to use the TurboJPEG API on top of libjpeg, but more specific, buildable
examples now exist in the https://github.com/libjpeg-turbo/ijg
repository.
This commit is contained in:
DRC
2017-11-16 18:09:07 -06:00
parent 087ec126c1
commit aa7459050d
24 changed files with 1653 additions and 906 deletions

View File

@@ -541,7 +541,8 @@ endif()
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)
@@ -549,6 +550,8 @@ if(WITH_TURBOJPEG)
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()
@@ -565,37 +568,35 @@ if(WITH_TURBOJPEG)
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()
@@ -864,6 +865,7 @@ foreach(libtype ${TEST_LIBTYPES})
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)

View File

@@ -102,6 +102,14 @@ program was used to decompress an existing JPEG image.
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
=====

341
bmp.c
View File

@@ -1,341 +0,0 @@
/*
* 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;
}

42
bmp.h
View File

@@ -1,42 +0,0 @@
/*
* 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

View File

@@ -96,9 +96,11 @@ typedef struct cdjpeg_progress_mgr *cd_progress_ptr;
/* 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);
@@ -151,3 +153,10 @@ EXTERN(FILE *) write_stdout (void);
#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))

View File

@@ -107,7 +107,7 @@ select_file_type (j_compress_ptr cinfo, FILE *infile)
switch (c) {
#ifdef BMP_SUPPORTED
case 'B':
return jinit_read_bmp(cinfo);
return jinit_read_bmp(cinfo, TRUE);
#endif
#ifdef GIF_SUPPORTED
case 'G':

64
cmyk.h Normal file
View File

@@ -0,0 +1,64 @@
/*
* 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 */

View File

@@ -642,10 +642,10 @@ main (int argc, char **argv)
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

View File

@@ -205,7 +205,9 @@ Enumerations</h2></td></tr>
&#160;&#160;<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/>
&#160;&#160;<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">&#160;</td><td class="mdescRight">Pixel formats. <a href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">More...</a><br/></td></tr>
@@ -312,6 +314,12 @@ Functions</h2></td></tr>
<tr class="memitem:ga5c9234bda6d993cdaffdd89bf81a00ff"><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned char *DLLCALL&#160;</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">&#160;</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">&#160;</td></tr>
<tr class="memitem:ga144b981d6b281ecca4cbb4709de75749"><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned char *DLLCALL&#160;</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">&#160;</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">&#160;</td></tr>
<tr class="memitem:ga2e78b7b79796e74584028da880a6a29c"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</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">&#160;</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">&#160;</td></tr>
<tr class="memitem:ga8c4a1231dc06a450514c835f6471f137"><td class="memItemLeft" align="right" valign="top">DLLEXPORT void DLLCALL&#160;</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">&#160;</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">&#160;</td></tr>
@@ -822,6 +830,10 @@ Variables</h2></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>&nbsp;</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>
@@ -2202,6 +2214,70 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
<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 *&#160;</td>
<td class="paramname"><em>filename</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">int *&#160;</td>
<td class="paramname"><em>width</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">int&#160;</td>
<td class="paramname"><em>align</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">int *&#160;</td>
<td class="paramname"><em>height</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">int *&#160;</td>
<td class="paramname"><em>pixelFormat</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">int&#160;</td>
<td class="paramname"><em>flags</em>&#160;</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 &amp; 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>
@@ -2347,6 +2423,77 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
</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 *&#160;</td>
<td class="paramname"><em>filename</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">unsigned char *&#160;</td>
<td class="paramname"><em>buffer</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">int&#160;</td>
<td class="paramname"><em>width</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">int&#160;</td>
<td class="paramname"><em>pitch</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">int&#160;</td>
<td class="paramname"><em>height</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">int&#160;</td>
<td class="paramname"><em>pixelFormat</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">int&#160;</td>
<td class="paramname"><em>flags</em>&#160;</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 &amp; 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>

View File

@@ -46,6 +46,7 @@ var searchData=
['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']]],
@@ -60,6 +61,7 @@ var searchData=
['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']]],
@@ -75,6 +77,7 @@ var searchData=
['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():&#160;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):&#160;turbojpeg.h']]],

View File

@@ -17,6 +17,7 @@ var searchData=
['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']]],

View File

@@ -22,8 +22,10 @@ var searchData=
['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']]]
];

View File

@@ -28,6 +28,8 @@ documentation and/or software.
#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)

View File

@@ -28,7 +28,6 @@
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include "./md5.h"
#include "../tjutil.h"

282
rdbmp.c
View File

@@ -6,7 +6,7 @@
* 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.
*
@@ -27,6 +27,7 @@
*/
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
#include "cmyk.h"
#ifdef BMP_SUPPORTED
@@ -49,6 +50,10 @@ typedef char U_CHAR;
#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 */
@@ -66,6 +71,17 @@ typedef struct _bmp_source_struct {
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;
@@ -131,20 +147,58 @@ get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
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;
@@ -160,22 +214,61 @@ get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
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;
@@ -191,22 +284,64 @@ get_32bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
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;
@@ -297,7 +432,7 @@ start_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
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))
@@ -415,33 +550,72 @@ start_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
}
/* Compute row width in file, including padding to 4-byte boundary */
if (source->bits_per_pixel == 24)
row_width = (JDIMENSION) (biWidth * 3);
else if (source->bits_per_pixel == 32)
row_width = (JDIMENSION) (biWidth * 4);
else
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);
break;
case 32:
if (cinfo->in_color_space == JCS_UNKNOWN)
cinfo->in_color_space = JCS_EXT_BGRA;
row_width = (JDIMENSION) (biWidth * 4);
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;
@@ -464,7 +638,7 @@ finish_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
*/
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;
@@ -477,6 +651,8 @@ jinit_read_bmp (j_compress_ptr cinfo)
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;
}

416
rdppm.c
View File

@@ -5,7 +5,7 @@
* 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.
*
@@ -23,6 +23,7 @@
*/
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
#include "cmyk.h"
#ifdef PPM_SUPPORTED
@@ -58,6 +59,10 @@ typedef char U_CHAR;
#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 */
@@ -155,6 +160,89 @@ get_text_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
}
#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 */
@@ -165,12 +253,91 @@ get_text_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
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;
}
@@ -198,7 +365,76 @@ get_scaled_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
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;
@@ -206,15 +442,99 @@ get_scaled_rgb_row (j_compress_ptr cinfo, cjpeg_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;
}
@@ -348,56 +668,100 @@ start_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
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);

View File

@@ -33,7 +33,6 @@
#include <math.h>
#include <errno.h>
#include <cdjpeg.h>
#include "./bmp.h"
#include "./tjutil.h"
#include "./turbojpeg.h"
@@ -48,6 +47,12 @@
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); \
@@ -76,8 +81,6 @@ int tjErrorLine=-1, tjErrorCode=-1;
} \
}
#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";
@@ -265,9 +268,8 @@ int decomp(unsigned char *srcbuf, unsigned char **jpegbuf,
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)
@@ -301,9 +303,8 @@ int decomp(unsigned char *srcbuf, unsigned char **jpegbuf,
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:
@@ -998,8 +999,8 @@ int main(int argc, char *argv[])
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';
}
@@ -1052,6 +1053,6 @@ int main(int argc, char *argv[])
}
bailout:
if(srcbuf) free(srcbuf);
if(srcbuf) tjFree(srcbuf);
return retval;
}

View File

@@ -34,11 +34,15 @@
#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
@@ -49,7 +53,8 @@ void usage(char *progName)
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);
}
@@ -58,6 +63,14 @@ void usage(char *progName)
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]=
{
@@ -686,6 +699,231 @@ void bufSizeTest(void)
}
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;
@@ -699,6 +937,7 @@ int main(int argc, char *argv[])
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]);
}
}

View File

@@ -60,4 +60,6 @@ TURBOJPEG_1.6
global:
tjGetErrorCode;
tjGetErrorStr2;
tjLoadImage;
tjSaveImage;
} TURBOJPEG_1.4;

View File

@@ -96,4 +96,6 @@ TURBOJPEG_1.6
global:
tjGetErrorCode;
tjGetErrorStr2;
tjLoadImage;
tjSaveImage;
} TURBOJPEG_1.4;

View File

@@ -37,10 +37,12 @@
#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);
@@ -132,8 +134,40 @@ static const tjscalingfactor sf[NUMSF]={
{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; \
@@ -188,45 +222,7 @@ static int setCompDefaults(struct jpeg_compress_struct *cinfo,
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);
@@ -285,62 +281,6 @@ static int setCompDefaults(struct jpeg_compress_struct *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)
{
@@ -409,149 +349,6 @@ 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)
@@ -792,9 +589,6 @@ DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, const unsigned char *srcBuf,
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;
@@ -808,16 +602,6 @@ DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, const unsigned char *srcBuf,
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");
@@ -858,9 +642,6 @@ DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, const unsigned char *srcBuf,
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;
@@ -901,9 +682,6 @@ DLLEXPORT int DLLCALL tjEncodeYUVPlanes(tjhandle handle,
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;
@@ -929,16 +707,6 @@ DLLEXPORT int DLLCALL tjEncodeYUVPlanes(tjhandle handle,
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. */
@@ -1042,9 +810,6 @@ DLLEXPORT int DLLCALL tjEncodeYUVPlanes(tjhandle handle,
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++)
{
@@ -1427,10 +1192,6 @@ DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle,
{
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;
@@ -1453,11 +1214,8 @@ DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle,
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;
@@ -1479,20 +1237,6 @@ DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle,
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");
@@ -1514,15 +1258,8 @@ DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle,
}
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;
@@ -1605,10 +1342,6 @@ DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle,
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);
@@ -1659,10 +1392,8 @@ DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle,
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);
@@ -1673,20 +1404,6 @@ DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle,
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++)
@@ -1743,15 +1460,8 @@ DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle,
}
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++)
{
@@ -2240,3 +1950,168 @@ DLLEXPORT int DLLCALL tjTransform(tjhandle handle,
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;
}

View File

@@ -249,7 +249,11 @@ enum TJPF
* 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
};
@@ -1514,6 +1518,86 @@ DLLEXPORT int DLLCALL tjDestroy(tjhandle handle);
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

211
wrbmp.c
View File

@@ -23,6 +23,7 @@
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
#include "jconfigint.h"
#include "cmyk.h"
#ifdef BMP_SUPPORTED
@@ -56,6 +57,18 @@ typedef struct {
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;
@@ -92,19 +105,26 @@ put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
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--) {
@@ -120,19 +140,35 @@ put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
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)
@@ -143,38 +179,31 @@ put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
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);
}
@@ -204,7 +233,7 @@ write_bmp_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
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;
@@ -214,7 +243,8 @@ write_bmp_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
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 {
@@ -272,7 +302,9 @@ write_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
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;
@@ -282,7 +314,8 @@ write_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
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 {
@@ -379,6 +412,25 @@ write_colormap (j_decompress_ptr cinfo, bmp_dest_ptr dest,
}
/*
* 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)
{
@@ -390,29 +442,31 @@ 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);
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++;
/* 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);
@@ -426,7 +480,8 @@ finish_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
*/
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;
@@ -442,12 +497,15 @@ jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2)
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);
@@ -460,28 +518,35 @@ jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2)
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++;
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 {
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 */
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)

95
wrppm.c
View File

@@ -20,6 +20,7 @@
*/
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
#include "cmyk.h"
#ifdef PPM_SUPPORTED
@@ -103,6 +104,63 @@ put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
METHODDEF(void)
copy_pixel_rows (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;
#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;
@@ -111,8 +169,12 @@ copy_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
ptr = dest->pub.buffer[0];
bufferptr = dest->iobuffer;
for (col = dest->samples_per_row; col > 0; col--) {
PUTPPMSAMPLE(bufferptr, GETJSAMPLE(*ptr++));
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);
}
@@ -185,6 +247,17 @@ start_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
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,
@@ -219,7 +292,10 @@ calc_buffer_dimensions_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
{
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));
}
@@ -250,7 +326,12 @@ jinit_write_ppm (j_decompress_ptr cinfo)
((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.
@@ -259,7 +340,11 @@ jinit_write_ppm (j_decompress_ptr cinfo)
((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;