diff --git a/ChangeLog.md b/ChangeLog.md index 5441bd4a..468bfda4 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -7,6 +7,9 @@ input files into full-color JPEG images unless the `-grayscale` option was used. +2. cjpeg now automatically compresses GIF and 8-bit BMP input files into +grayscale JPEG images if the input files contain only shades of gray. + 2.1.2 ===== diff --git a/cjpeg.1 b/cjpeg.1 index 75a9cce8..4bc4c8f9 100644 --- a/cjpeg.1 +++ b/cjpeg.1 @@ -1,4 +1,4 @@ -.TH CJPEG 1 "18 November 2021" +.TH CJPEG 1 "30 November 2021" .SH NAME cjpeg \- compress an image file to a JPEG file .SH SYNOPSIS @@ -40,11 +40,7 @@ Scale quantization tables to adjust image quality. Quality is 0 (worst) to 100 (best); default is 75. (See below for more info.) .TP .B \-grayscale -Create monochrome JPEG file from color input. Be sure to use this switch when -compressing a grayscale BMP or GIF file, because -.B cjpeg -isn't bright enough to notice whether a BMP or GIF file uses only shades of -gray. By saying +Create monochrome JPEG file from color input. By saying .BR \-grayscale, you'll get a smaller JPEG file that takes less time to process. .TP diff --git a/rdbmp.c b/rdbmp.c index 358a0267..99feb4b9 100644 --- a/rdbmp.c +++ b/rdbmp.c @@ -125,7 +125,8 @@ read_colormap(bmp_source_ptr sinfo, int cmaplen, int mapentrysize) break; } - if (sinfo->cinfo->in_color_space == JCS_UNKNOWN && gray) + if ((sinfo->cinfo->in_color_space == JCS_UNKNOWN || + sinfo->cinfo->in_color_space == JCS_RGB) && gray) sinfo->cinfo->in_color_space = JCS_GRAYSCALE; if (sinfo->cinfo->in_color_space == JCS_GRAYSCALE && !gray) diff --git a/rdgif.c b/rdgif.c index c814c6b0..36f0929f 100644 --- a/rdgif.c +++ b/rdgif.c @@ -345,7 +345,7 @@ LOCAL(void) ReadColorMap(gif_source_ptr sinfo, int cmaplen, JSAMPARRAY cmap) /* Read a GIF colormap */ { - int i; + int i, gray = 1; for (i = 0; i < cmaplen; i++) { #if BITS_IN_JSAMPLE == 8 @@ -356,6 +356,14 @@ ReadColorMap(gif_source_ptr sinfo, int cmaplen, JSAMPARRAY cmap) cmap[CM_RED][i] = (JSAMPLE)UPSCALE(ReadByte(sinfo)); cmap[CM_GREEN][i] = (JSAMPLE)UPSCALE(ReadByte(sinfo)); cmap[CM_BLUE][i] = (JSAMPLE)UPSCALE(ReadByte(sinfo)); + if (cmap[CM_RED][i] != cmap[CM_GREEN][i] || + cmap[CM_GREEN][i] != cmap[CM_BLUE][i]) + gray = 0; + } + + if (sinfo->cinfo->in_color_space == JCS_RGB && gray) { + sinfo->cinfo->in_color_space = JCS_GRAYSCALE; + sinfo->cinfo->input_components = 1; } } @@ -516,10 +524,15 @@ start_input_gif(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) source->pub.get_pixel_rows = get_pixel_rows; } + if (cinfo->in_color_space != JCS_GRAYSCALE) { + cinfo->in_color_space = JCS_RGB; + cinfo->input_components = NUMCOLORS; + } + /* Create compressor input buffer. */ source->pub.buffer = (*cinfo->mem->alloc_sarray) - ((j_common_ptr)cinfo, JPOOL_IMAGE, (JDIMENSION)width * NUMCOLORS, - (JDIMENSION)1); + ((j_common_ptr)cinfo, JPOOL_IMAGE, + (JDIMENSION)width * cinfo->input_components, (JDIMENSION)1); source->pub.buffer_height = 1; /* Pad colormap for safety. */ @@ -530,8 +543,6 @@ start_input_gif(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) } /* Return info about the image. */ - cinfo->in_color_space = JCS_RGB; - cinfo->input_components = NUMCOLORS; cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */ cinfo->image_width = width; cinfo->image_height = height; @@ -556,11 +567,18 @@ get_pixel_rows(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) register JSAMPARRAY colormap = source->colormap; ptr = source->pub.buffer[0]; - for (col = cinfo->image_width; col > 0; col--) { - c = LZWReadByte(source); - *ptr++ = colormap[CM_RED][c]; - *ptr++ = colormap[CM_GREEN][c]; - *ptr++ = colormap[CM_BLUE][c]; + if (cinfo->in_color_space == JCS_GRAYSCALE) { + for (col = cinfo->image_width; col > 0; col--) { + c = LZWReadByte(source); + *ptr++ = colormap[CM_RED][c]; + } + } else { + for (col = cinfo->image_width; col > 0; col--) { + c = LZWReadByte(source); + *ptr++ = colormap[CM_RED][c]; + *ptr++ = colormap[CM_GREEN][c]; + *ptr++ = colormap[CM_BLUE][c]; + } } return 1; } @@ -646,11 +664,18 @@ get_interlaced_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) FALSE); /* Scan the row, expand colormap, and output */ ptr = source->pub.buffer[0]; - for (col = cinfo->image_width; col > 0; col--) { - c = *sptr++; - *ptr++ = colormap[CM_RED][c]; - *ptr++ = colormap[CM_GREEN][c]; - *ptr++ = colormap[CM_BLUE][c]; + if (cinfo->in_color_space == JCS_GRAYSCALE) { + for (col = cinfo->image_width; col > 0; col--) { + c = *sptr++; + *ptr++ = colormap[CM_RED][c]; + } + } else { + for (col = cinfo->image_width; col > 0; col--) { + c = *sptr++; + *ptr++ = colormap[CM_RED][c]; + *ptr++ = colormap[CM_GREEN][c]; + *ptr++ = colormap[CM_BLUE][c]; + } } source->cur_row_number++; /* for next time */ return 1; diff --git a/usage.txt b/usage.txt index b60a593f..bc2253f1 100644 --- a/usage.txt +++ b/usage.txt @@ -72,12 +72,9 @@ The basic command line switches for cjpeg are: Quality is 0 (worst) to 100 (best); default is 75. (See below for more info.) - -grayscale Create monochrome JPEG file from color input. - Be sure to use this switch when compressing a grayscale - BMP or GIF file, because cjpeg isn't bright enough to - notice whether a BMP or GIF file uses only shades of - gray. By saying -grayscale, you'll get a smaller JPEG - file that takes less time to process. + -grayscale Create monochrome JPEG file from color input. By + saying -grayscale, you'll get a smaller JPEG file that + takes less time to process. -rgb Create RGB JPEG file. Using this switch suppresses the conversion from RGB