Back to index

texmacs  1.0.7.15
jpegimage.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/jpegimage.c,v 1.11 2009/05/10 17:04:54 matthias Exp $
00002 
00003     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
00004 
00005     Copyright (C) 2007 by Jin-Hwan Cho and Shunsaku Hirata,
00006     the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
00007     
00008     Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014     
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU General Public License for more details.
00019     
00020     You should have received a copy of the GNU General Public License
00021     along with this program; if not, write to the Free Software
00022     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00023 */
00024 
00025 
00026 #if HAVE_CONFIG_H
00027 #include "config.h"
00028 #endif
00029 
00030 /*
00031  * JPEG SUPPORT
00032  *
00033  * Accroding to Libjpeg document:
00034  *
00035  *  CAUTION: it appears that Adobe Photoshop writes inverted data in CMYK
00036  *  JPEG files: 0 represents 100% ink coverage, rather than 0% ink as you'd
00037  *  expect....
00038  *
00039  * To wrok with this problem, we must detect whether CMYK JPEG file is
00040  * created by Photoshop. But there are no reliable way to determine this.
00041  *
00042  * According to Adobe Technical Note #5516,
00043  * "Supporting the DCT Filters in PostScript Level 2", Section 18, p.27.
00044  *
00045  *  DCTDecode ignores and skips any APPE marker segment does not begin with
00046  *  the `Adobe' 5-character string.
00047  *
00048  * PDF Reference Manual 4th ed., p.61-62.
00049  *
00050  *  The JPEG filter implementation in Adobe Acrobat products does not
00051  *  support features of the JPEG standard that are irrelevant to images.
00052  *  In addition, certain choices have been made regarding reserved marker
00053  *  codes and other optional features of the standard. For details, see
00054  *  Adobe Technical Note #5116, Supporting the DCT Filters in PostScript
00055  *  Level 2.
00056  */
00057 
00058 #include "system.h"
00059 #include "error.h"
00060 #include "mem.h"
00061 
00062 #include "mfileio.h"
00063 #include "numbers.h"
00064 
00065 #include "dvipdfmx.h"
00066 
00067 #include "pdfobj.h"
00068 
00069 #include "jpegimage.h"
00070 #include "pdfcolor.h"
00071 
00072 #include "pdfximage.h"
00073 
00074 #define JPEG_DEBUG_STR "JPEG"
00075 #define JPEG_DEBUG     3
00076 
00077 #ifdef    HAVE_LIBJPEG
00078 #include <jpeglib.h>
00079 #endif /* HAVE_LIBJPEG */
00080 
00081 /* JPEG Markers */
00082 typedef enum {
00083   JM_SOF0  = 0xc0,
00084   JM_SOF1  = 0xc1,
00085   JM_SOF2  = 0xc2,
00086   JM_SOF3  = 0xc3,
00087   JM_SOF5  = 0xc5,
00088   JM_DHT   = 0xc4,
00089   JM_SOF6  = 0xc6,
00090   JM_SOF7  = 0xc7,
00091   JM_SOF9  = 0xc9,
00092   JM_SOF10 = 0xca,
00093   JM_SOF11 = 0xcb,
00094   JM_DAC   = 0xcc,
00095   JM_SOF13 = 0xcd,
00096   JM_SOF14 = 0xce,
00097   JM_SOF15 = 0xcf,
00098 
00099   JM_RST0  = 0xd0,
00100   JM_RST1  = 0xd1,
00101   JM_RST2  = 0xd2,
00102   JM_RST3  = 0xd3,
00103   JM_RST4  = 0xd4,
00104   JM_RST5  = 0xd5,
00105   JM_RST6  = 0xd6,
00106   JM_RST7  = 0xd7,
00107 
00108   JM_SOI   = 0xd8,
00109   JM_EOI   = 0xd9,
00110   JM_SOS   = 0xda,
00111   JM_DQT   = 0xdb,
00112   JM_DNL   = 0xdc,
00113   JM_DRI   = 0xdd,
00114   JM_DHP   = 0xde,
00115   JM_EXP   = 0xdf,
00116 
00117   JM_APP0  = 0xe0,
00118   JM_APP2  = 0xe2,
00119   JM_APP14 = 0xee,
00120   JM_APP15 = 0xef,
00121 
00122   JM_COM   = 0xfe
00123 } JPEG_marker;
00124 
00125 typedef enum {
00126   JS_APPn_JFIF,
00127   JS_APPn_ADOBE,
00128   JS_APPn_ICC
00129 } JPEG_APPn_sig;
00130 
00131 struct JPEG_APPn_JFIF  /* APP0 */
00132 {
00133   unsigned short version;
00134   unsigned char  units;      /* 0: only aspect ratio
00135                            * 1: dots per inch
00136                            * 2: dots per cm
00137                            */
00138   unsigned short Xdensity;
00139   unsigned short Ydensity;
00140   unsigned char  Xthumbnail;
00141   unsigned char  Ythumbnail;
00142   unsigned char *thumbnail;  /* Thumbnail data. */
00143 };
00144 
00145 struct JPEG_APPn_ICC   /* APP2 */
00146 {
00147   unsigned char  seq_id;
00148   unsigned char  num_chunks;
00149   unsigned char *chunk;
00150 
00151   /* Length of ICC profile data in this chunk. */
00152   unsigned short length;
00153 };
00154 
00155 struct JPEG_APPn_Adobe /* APP14 */
00156 {
00157   unsigned short version;
00158   unsigned short flag0;
00159   unsigned short flag1;
00160   unsigned char  transform; /* color transform code */
00161 };
00162 
00163 struct JPEG_ext
00164 {
00165   JPEG_marker   marker;
00166   JPEG_APPn_sig app_sig;
00167   void         *app_data;
00168 };
00169 
00170 #define MAX_COUNT 1024
00171 struct  JPEG_info
00172 {
00173   unsigned short height;
00174   unsigned short width;
00175 
00176   unsigned char  bits_per_component;
00177   unsigned char  num_components;
00178 
00179   /* Application specific extensions */
00180   int flags;
00181   int num_appn, max_appn;
00182   struct JPEG_ext *appn;
00183 
00184   /* Skip chunks not necessary. */
00185   char skipbits[MAX_COUNT / 8 + 1];
00186 };
00187 
00188 #define HAVE_APPn_JFIF  (1 << 0)
00189 #define HAVE_APPn_ADOBE (1 << 1)
00190 #define HAVE_APPn_ICC   (1 << 2)
00191 
00192 static int      JPEG_scan_file   (struct JPEG_info *j_info, FILE *fp);
00193 static int      JPEG_copy_stream (struct JPEG_info *j_info,
00194                               pdf_obj *stream, FILE *fp, int flags); /* flags unused yet */
00195 
00196 static void     JPEG_info_init   (struct JPEG_info *j_info);
00197 static void     JPEG_info_clear  (struct JPEG_info *j_info);
00198 static pdf_obj *JPEG_get_iccp    (struct JPEG_info *j_info);
00199 static void     jpeg_get_density (struct JPEG_info *j_info,
00200                               double *xdensity, double *ydensity);
00201 
00202 int
00203 check_for_jpeg (FILE *fp)
00204 {
00205   unsigned char jpeg_sig[2];
00206 
00207   rewind(fp);
00208   if (fread(jpeg_sig, sizeof(unsigned char), 2, fp) != 2)
00209     return 0;
00210   else if (jpeg_sig[0] != 0xff || jpeg_sig[1] != JM_SOI)
00211     return 0;
00212 
00213   return 1;
00214 }
00215 
00216 int
00217 jpeg_include_image (pdf_ximage *ximage, FILE *fp)
00218 {
00219   pdf_obj    *stream;
00220   pdf_obj    *stream_dict;
00221   pdf_obj    *colorspace;
00222   int         colortype;
00223   ximage_info info;
00224   struct JPEG_info j_info;
00225 
00226   if (!check_for_jpeg(fp)) {
00227     WARN("%s: Not a JPEG file?", JPEG_DEBUG_STR);
00228     rewind(fp);
00229     return -1;
00230   }
00231   /* File position is 2 here... */
00232 
00233   pdf_ximage_init_image_info(&info);
00234 
00235   JPEG_info_init(&j_info);
00236 
00237   if (JPEG_scan_file(&j_info, fp) < 0) {
00238     WARN("%s: Not a JPEG file?", JPEG_DEBUG_STR);
00239     JPEG_info_clear(&j_info);
00240     return -1;
00241   }
00242 
00243   switch (j_info.num_components) {
00244   case 1:
00245     colortype = PDF_COLORSPACE_TYPE_GRAY;
00246     break;
00247   case 3:
00248     colortype = PDF_COLORSPACE_TYPE_RGB;
00249     break;
00250   case 4:
00251     colortype = PDF_COLORSPACE_TYPE_CMYK;
00252     break;
00253   default:
00254     WARN("%s: Unknown color space (num components: %d)",
00255         JPEG_DEBUG_STR, info.num_components);
00256     JPEG_info_clear(&j_info);
00257     return -1;
00258   }
00259 
00260   /* JPEG image use DCTDecode. */
00261   stream      = pdf_new_stream (0);
00262   stream_dict = pdf_stream_dict(stream);
00263   pdf_add_dict(stream_dict,
00264               pdf_new_name("Filter"), pdf_new_name("DCTDecode"));
00265 
00266   colorspace  = NULL;
00267   if (j_info.flags & HAVE_APPn_ICC) {
00268     pdf_obj *icc_stream, *intent;
00269 
00270     icc_stream = JPEG_get_iccp(&j_info);
00271 
00272     if (!icc_stream)
00273       colorspace = NULL;
00274     else {
00275       int   cspc_id;
00276 
00277       if (iccp_check_colorspace(colortype,
00278                             pdf_stream_dataptr(icc_stream),
00279                             pdf_stream_length (icc_stream)) < 0)
00280        colorspace = NULL;
00281       else {
00282        cspc_id = iccp_load_profile(NULL, /* noname */
00283                                 pdf_stream_dataptr(icc_stream),
00284                                 pdf_stream_length (icc_stream));
00285        if (cspc_id < 0)
00286          colorspace = NULL;
00287        else {
00288          colorspace = pdf_get_colorspace_reference(cspc_id);
00289          intent     = iccp_get_rendering_intent(pdf_stream_dataptr(icc_stream),
00290                                            pdf_stream_length (icc_stream));
00291          if (intent)
00292            pdf_add_dict(stream_dict, pdf_new_name("Intent"), intent);
00293        }
00294       }
00295       pdf_release_obj(icc_stream);
00296     }
00297   }
00298 
00299   /* No ICC or invalid ICC profile. */
00300   if (!colorspace) {
00301     switch (colortype) {
00302     case PDF_COLORSPACE_TYPE_GRAY:
00303       colorspace = pdf_new_name("DeviceGray");
00304       break;
00305     case PDF_COLORSPACE_TYPE_RGB:
00306       colorspace = pdf_new_name("DeviceRGB");
00307       break;
00308     case PDF_COLORSPACE_TYPE_CMYK:
00309       colorspace = pdf_new_name("DeviceCMYK");
00310       break;
00311     }
00312   }
00313   pdf_add_dict(stream_dict, pdf_new_name("ColorSpace"), colorspace);
00314 
00315 #define IS_ADOBE_CMYK(j) (((j).flags & HAVE_APPn_ADOBE) && (j).num_components == 4)
00316 
00317   if (IS_ADOBE_CMYK(j_info)) {
00318     pdf_obj *decode;
00319     int      i;
00320 
00321     WARN("Adobe CMYK JPEG: Inverted color assumed.");
00322     decode = pdf_new_array();
00323     for (i = 0; i < j_info.num_components; i++) {
00324       pdf_add_array(decode, pdf_new_number(1.0));
00325       pdf_add_array(decode, pdf_new_number(0.0));
00326     }
00327     pdf_add_dict(stream_dict, pdf_new_name("Decode"), decode);
00328   }
00329 
00330   /* Copy file */
00331   JPEG_copy_stream(&j_info, stream, fp, 0);
00332 
00333   info.width              = j_info.width;
00334   info.height             = j_info.height;
00335   info.bits_per_component = j_info.bits_per_component;
00336   info.num_components     = j_info.num_components;
00337 
00338   jpeg_get_density(&j_info, &info.xdensity, &info.ydensity);
00339 
00340   pdf_ximage_set_image(ximage, &info, stream);
00341   JPEG_info_clear(&j_info);
00342 
00343   return 0;
00344 }
00345 
00346 #define IS_JFIF(j) ((j)->flags & HAVE_APPn_JFIF)
00347 
00348 static void
00349 jpeg_get_density (struct JPEG_info *j_info,
00350                 double *xdensity, double *ydensity)
00351 {
00352   if (compat_mode) {
00353     *xdensity = *ydensity = 72.0 / 100.0;
00354     return;
00355   }
00356 
00357   *xdensity = *ydensity = 1.0;
00358 
00359   if (IS_JFIF(j_info)) {
00360     struct JPEG_APPn_JFIF *app_data;
00361     int i;
00362     for (i = 0; i < j_info->num_appn; i++) {
00363       if (j_info->appn[i].marker  == JM_APP0 ||
00364          j_info->appn[i].app_sig == JS_APPn_JFIF)
00365         break;
00366     }
00367     if (i < j_info->num_appn) {
00368       app_data = (struct JPEG_APPn_JFIF *)j_info->appn[i].app_data;
00369       switch (app_data->units) {
00370       case 1: /* pixels per inch */
00371         *xdensity = 72.0 / app_data->Xdensity;
00372         *ydensity = 72.0 / app_data->Ydensity;
00373         break;
00374       case 2: /* pixels per centimeter */
00375         *xdensity = 72.0 / 2.54 / app_data->Xdensity;
00376         *ydensity = 72.0 / 2.54 / app_data->Ydensity;
00377         break;
00378       default:
00379         break;
00380       }
00381     }
00382   }
00383 }
00384 
00385 static void
00386 JPEG_info_init (struct JPEG_info *j_info)
00387 {
00388   j_info->width  = 0;
00389   j_info->height = 0;
00390   j_info->bits_per_component = 0;
00391   j_info->num_components = 0;
00392 
00393   j_info->flags    = 0;
00394   j_info->num_appn = 0;
00395   j_info->max_appn = 0;
00396   j_info->appn     = NULL;
00397 
00398   memset(j_info->skipbits, 0, MAX_COUNT / 8 + 1);
00399 }
00400 
00401 static void
00402 JPEG_release_APPn_data (JPEG_marker marker, JPEG_APPn_sig app_sig, void *app_data)
00403 {
00404   if (marker  == JM_APP0 &&
00405       app_sig == JS_APPn_JFIF) {
00406     struct JPEG_APPn_JFIF *data;
00407 
00408     data = (struct JPEG_APPn_JFIF *) app_data;
00409     if (data->thumbnail)
00410       RELEASE(data->thumbnail);
00411     data->thumbnail = NULL;
00412 
00413     RELEASE(data);
00414   } else if (marker  == JM_APP2 &&
00415             app_sig == JS_APPn_ICC) {
00416     struct JPEG_APPn_ICC *data;
00417 
00418     data = (struct JPEG_APPn_ICC *) app_data;
00419     if (data->chunk)
00420       RELEASE(data->chunk);
00421     data->chunk = NULL;
00422 
00423     RELEASE(data);
00424   } else if (marker  == JM_APP14 &&
00425             app_sig == JS_APPn_ADOBE) {
00426     struct JPEG_APPn_Adobe *data;
00427 
00428     data = (struct JPEG_APPn_Adobe *) app_data;
00429 
00430     RELEASE(data);
00431   }
00432 }
00433 
00434 static void
00435 JPEG_info_clear (struct JPEG_info *j_info)
00436 {
00437   if (j_info->num_appn > 0 &&
00438       j_info->appn    != NULL) {
00439     int i;
00440 
00441     for (i = 0; i < j_info->num_appn; i++)
00442       JPEG_release_APPn_data(j_info->appn[i].marker,
00443                           j_info->appn[i].app_sig, j_info->appn[i].app_data);
00444     RELEASE(j_info->appn);
00445   }
00446   j_info->appn     = NULL;
00447   j_info->num_appn = 0;
00448   j_info->max_appn = 0;
00449   j_info->flags    = 0;
00450 }
00451 
00452 static pdf_obj *
00453 JPEG_get_iccp (struct JPEG_info *j_info)
00454 {
00455   pdf_obj *icc_stream;
00456   struct JPEG_APPn_ICC *icc;
00457   int i, prev_id = 0, num_icc_seg = -1;
00458 
00459   icc_stream = pdf_new_stream(STREAM_COMPRESS);
00460   for (i = 0; i < j_info->num_appn; i++) {
00461     if (j_info->appn[i].marker  != JM_APP2 ||
00462        j_info->appn[i].app_sig != JS_APPn_ICC)
00463       continue;
00464     icc = (struct JPEG_APPn_ICC *) j_info->appn[i].app_data;
00465     if (num_icc_seg < 0 && prev_id == 0) {
00466       num_icc_seg = icc->num_chunks;
00467       /* ICC chunks are sorted? */
00468     } else if (icc->seq_id != prev_id + 1 ||
00469               num_icc_seg != icc->num_chunks ||
00470               icc->seq_id  > icc->num_chunks) {
00471       WARN("Invalid JPEG ICC chunk: %d (p:%d, n:%d)",
00472           icc->seq_id, prev_id, icc->num_chunks);
00473       pdf_release_obj(icc_stream);
00474       icc_stream = NULL;
00475       break;
00476     }
00477     pdf_add_stream(icc_stream, icc->chunk, icc->length);
00478     prev_id = icc->seq_id;
00479     num_icc_seg = icc->num_chunks;
00480   }
00481 
00482   return icc_stream;
00483 }
00484 
00485 static JPEG_marker
00486 JPEG_get_marker (FILE *fp)
00487 {
00488   int c;
00489 
00490   c = fgetc(fp);
00491   if (c != 255)
00492     return -1;
00493 
00494   for (;;) {
00495     c = fgetc(fp);
00496     if (c < 0)
00497       return -1;
00498     else if (c > 0 && c < 255) {
00499       return c;
00500     }
00501   }
00502 
00503   return -1;
00504 }
00505 
00506 static int
00507 add_APPn_marker (struct JPEG_info *j_info,
00508                JPEG_marker marker, int app_sig, void *app_data)
00509 {
00510   int n;
00511 
00512   if (j_info->num_appn >= j_info->max_appn) {
00513     j_info->max_appn += 16;
00514     j_info->appn = RENEW(j_info->appn, j_info->max_appn, struct JPEG_ext);
00515   }
00516   n = j_info->num_appn;
00517 
00518   j_info->appn[n].marker   = marker;
00519   j_info->appn[n].app_sig  = app_sig;
00520   j_info->appn[n].app_data = app_data;
00521 
00522   j_info->num_appn += 1;
00523 
00524   return n;
00525 }
00526 
00527 static unsigned short
00528 read_APP14_Adobe (struct JPEG_info *j_info, FILE *fp, unsigned short length)
00529 {
00530   struct JPEG_APPn_Adobe *app_data;
00531 
00532   app_data = NEW(1, struct JPEG_APPn_Adobe);
00533   app_data->version   = get_unsigned_pair(fp);
00534   app_data->flag0     = get_unsigned_pair(fp);
00535   app_data->flag1     = get_unsigned_pair(fp);
00536   app_data->transform = get_unsigned_byte(fp);
00537 
00538   add_APPn_marker(j_info, JM_APP14, JS_APPn_ADOBE, app_data);
00539 
00540   return 7;
00541 }
00542 
00543 static unsigned short
00544 read_APP0_JFIF (struct JPEG_info *j_info, FILE *fp, unsigned short length)
00545 {
00546   struct JPEG_APPn_JFIF *app_data;
00547   unsigned short thumb_data_len;
00548 
00549   app_data = NEW(1, struct JPEG_APPn_JFIF);
00550   app_data->version  = get_unsigned_pair(fp);
00551   app_data->units    = get_unsigned_byte(fp);
00552   app_data->Xdensity = get_unsigned_pair(fp);
00553   app_data->Ydensity = get_unsigned_pair(fp);
00554   app_data->Xthumbnail = get_unsigned_byte(fp);
00555   app_data->Ythumbnail = get_unsigned_byte(fp);
00556   thumb_data_len = 3 * app_data->Xthumbnail * app_data->Ythumbnail;
00557   if (thumb_data_len > 0) {
00558     app_data->thumbnail = NEW(thumb_data_len, unsigned char);
00559     fread(app_data->thumbnail, 1, thumb_data_len, fp);
00560   } else {
00561     app_data->thumbnail = NULL;
00562   }
00563 
00564   add_APPn_marker(j_info, JM_APP0, JS_APPn_JFIF, app_data);
00565 
00566   return (9 + thumb_data_len);
00567 }
00568 
00569 static unsigned short
00570 read_APP0_JFXX (struct JPEG_info *j_info, FILE *fp, unsigned short length)
00571 {
00572   unsigned char extension_code;
00573 
00574   extension_code = get_unsigned_byte(fp);
00575   /* Extension Code:
00576    *
00577    * 0x10: Thumbnail coded using JPEG
00578    * 0x11: Thumbnail stored using 1 byte/pixel
00579    * 0x13: Thumbnail stored using 3 bytes/pixel
00580    */
00581   seek_relative(fp, length-1); /* Thunbnail image */
00582 
00583   /* Ignore */
00584 
00585   return length;
00586 }
00587 
00588 static unsigned short
00589 read_APP2_ICC (struct JPEG_info *j_info, FILE *fp, unsigned short length)
00590 {
00591   struct JPEG_APPn_ICC *app_data;
00592 
00593   app_data = NEW(1, struct JPEG_APPn_ICC);
00594   app_data->seq_id      = get_unsigned_byte(fp); /* Starting at 1 */
00595   app_data->num_chunks  = get_unsigned_byte(fp);
00596   app_data->length = length - 2;
00597   app_data->chunk  = NEW(app_data->length, unsigned char);
00598   fread(app_data->chunk, 1, app_data->length, fp);
00599 
00600   add_APPn_marker(j_info, JM_APP2, JS_APPn_ICC, app_data);
00601 
00602   return length;
00603 }
00604 
00605 static int
00606 JPEG_copy_stream (struct JPEG_info *j_info,
00607                 pdf_obj *stream, FILE *fp, int flags) /* flags unused yet */
00608 {
00609   JPEG_marker marker;
00610   long length, nb_read;
00611   int  found_SOFn, count;
00612 
00613   rewind(fp);
00614   count      = 0;
00615   found_SOFn = 0;
00616   while (!found_SOFn &&
00617         count < MAX_COUNT &&
00618         (marker = JPEG_get_marker(fp)) >= 0) {
00619     if (marker == JM_SOI  ||
00620        (marker >= JM_RST0 && marker <= JM_RST7)) {
00621       work_buffer[0] = (char) 0xff;
00622       work_buffer[1] = (char) marker;
00623       pdf_add_stream(stream, work_buffer, 2);
00624       count++;
00625       continue;
00626     }
00627     length = get_unsigned_pair(fp) - 2;
00628     switch (marker) {
00629     case JM_SOF0:  case JM_SOF1:  case JM_SOF2:  case JM_SOF3:
00630     case JM_SOF5:  case JM_SOF6:  case JM_SOF7:  case JM_SOF9:
00631     case JM_SOF10: case JM_SOF11: case JM_SOF13: case JM_SOF14:
00632     case JM_SOF15:
00633       work_buffer[0] = (char) 0xff;
00634       work_buffer[1] = (char) marker;
00635       work_buffer[2] = ((length + 2) >> 8) & 0xff;
00636       work_buffer[3] =  (length + 2) & 0xff;
00637       pdf_add_stream(stream, work_buffer, 4);
00638       while (length > 0) {
00639        nb_read = fread(work_buffer, sizeof(char),
00640                      MIN(length, WORK_BUFFER_SIZE), fp);
00641        if (nb_read > 0)
00642          pdf_add_stream(stream, work_buffer, nb_read);
00643        length -= nb_read;
00644       }
00645       found_SOFn = 1;
00646       break;
00647     default:
00648       if (j_info->skipbits[count / 8] & (1 << (7 - (count % 8)))) {
00649        /* skip */
00650        while (length > 0) {
00651          nb_read = fread(work_buffer, sizeof(char),
00652                        MIN(length, WORK_BUFFER_SIZE), fp);
00653          length -= nb_read;
00654        }
00655       } else {
00656        work_buffer[0] = (char) 0xff;
00657        work_buffer[1] = (char) marker;
00658        work_buffer[2] = ((length + 2) >> 8) & 0xff;
00659        work_buffer[3] =  (length + 2) & 0xff;
00660        pdf_add_stream(stream, work_buffer, 4);
00661        while (length > 0) {
00662          nb_read = fread(work_buffer, sizeof(char),
00663                        MIN(length, WORK_BUFFER_SIZE), fp);
00664          if (nb_read > 0)
00665            pdf_add_stream(stream, work_buffer, nb_read);
00666          length -= nb_read;
00667        }
00668       }
00669     }
00670     count++;
00671   }
00672 
00673   while ((length = fread(work_buffer,
00674                       sizeof(char), WORK_BUFFER_SIZE, fp)) > 0) {
00675     pdf_add_stream(stream, work_buffer, length);
00676   }
00677 
00678   return (found_SOFn ? 0 : -1);
00679 }
00680 
00681 static int
00682 JPEG_scan_file (struct JPEG_info *j_info, FILE *fp)
00683 {
00684   JPEG_marker marker;
00685   unsigned short length;
00686   int  found_SOFn, count;
00687   char app_sig[128];
00688 
00689   rewind(fp);
00690   count      = 0;
00691   found_SOFn = 0;
00692   while (!found_SOFn &&
00693         (marker = JPEG_get_marker(fp)) >= 0) {
00694     if (marker == JM_SOI  ||
00695        (marker >= JM_RST0 && marker <= JM_RST7)) {
00696       count++;
00697       continue;
00698     }
00699     length = get_unsigned_pair(fp) - 2;
00700     switch (marker) {
00701     case JM_SOF0:  case JM_SOF1:  case JM_SOF2:  case JM_SOF3:
00702     case JM_SOF5:  case JM_SOF6:  case JM_SOF7:  case JM_SOF9:
00703     case JM_SOF10: case JM_SOF11: case JM_SOF13: case JM_SOF14:
00704     case JM_SOF15:
00705       j_info->bits_per_component = get_unsigned_byte(fp);
00706       j_info->height = get_unsigned_pair(fp);
00707       j_info->width  = get_unsigned_pair(fp);
00708       j_info->num_components = get_unsigned_byte(fp);
00709       found_SOFn = 1;
00710       break;
00711     case JM_APP0:
00712       if (length > 5) {
00713        if (fread(app_sig, sizeof(char), 5, fp) != 5)
00714          return -1;
00715        length -= 5;
00716        if (!memcmp(app_sig, "JFIF\000", 5)) {
00717          j_info->flags |= HAVE_APPn_JFIF;
00718          length -= read_APP0_JFIF(j_info, fp, length);
00719        } else if (!memcmp(app_sig, "JFXX", 5)) {
00720          length -= read_APP0_JFXX(j_info, fp, length);
00721        }
00722       }
00723       seek_relative(fp, length);
00724       break;
00725     case JM_APP2:
00726       if (length >= 14) {
00727        if (fread(app_sig, sizeof(char), 12, fp) != 12)
00728          return -1;
00729        length -= 12;
00730        if (!memcmp(app_sig, "ICC_PROFILE\000", 12)) {
00731          j_info->flags |= HAVE_APPn_ICC;
00732          length -= read_APP2_ICC(j_info, fp, length);
00733          if (count < MAX_COUNT) {
00734            j_info->skipbits[count / 8] |= (1 << (7 - (count % 8)));
00735          }
00736        }
00737       }
00738       seek_relative(fp, length);
00739       break;
00740     case JM_APP14:
00741       if (length > 5) {
00742        if (fread(app_sig, sizeof(char), 5, fp) != 5)
00743          return -1;
00744        length -= 5;
00745        if (!memcmp(app_sig, "Adobe", 5)) {
00746          j_info->flags |= HAVE_APPn_ADOBE;
00747          length -= read_APP14_Adobe(j_info, fp, length);
00748        } else {
00749          if (count < MAX_COUNT) {
00750            j_info->skipbits[count/8] |= (1 << (7 - (count % 8)));
00751          }
00752        }
00753       }
00754       seek_relative(fp, length);
00755       break;
00756     default:
00757       seek_relative(fp, length);
00758       if (marker >= JM_APP0 &&
00759          marker <= JM_APP15) {
00760        if (count < MAX_COUNT) {
00761          j_info->skipbits[count / 8] |= (1 << (7 - (count % 8)));
00762        }
00763       }
00764       break;
00765     }
00766     count++;
00767   }
00768 
00769   return (found_SOFn ? 0 : -1);
00770 }
00771 
00772 int
00773 jpeg_get_bbox (FILE *fp, long *width, long *height,
00774               double *xdensity, double *ydensity)
00775 {
00776   struct JPEG_info j_info;
00777 
00778   JPEG_info_init(&j_info);
00779 
00780   if (JPEG_scan_file(&j_info, fp) < 0) {
00781     WARN("%s: Not a JPEG file?", JPEG_DEBUG_STR);
00782     JPEG_info_clear(&j_info);
00783     return -1;
00784   }
00785 
00786   *width  = j_info.width;
00787   *height = j_info.height;
00788 
00789   jpeg_get_density(&j_info, xdensity, ydensity);
00790 
00791   JPEG_info_clear(&j_info);
00792 
00793   return 0;
00794 }