Back to index

scribus-ng  1.3.4.dfsg+svn20071115
scimgdataloader_jpeg.cpp
Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 #include <qfile.h>
00008 #include <qfileinfo.h>
00009 #include <qobject.h>
00010 #include <setjmp.h>
00011 #include "scconfig.h"
00012 #include "scimgdataloader_jpeg.h"
00013 #include "exif.h"
00014 
00015 #include CMS_INC
00016 
00017 typedef struct my_error_mgr
00018 {
00019        struct jpeg_error_mgr pub;            /* "public" fields */
00020        jmp_buf setjmp_buffer;  /* for return to caller */
00021 } *my_error_ptr;
00022 
00023 static void my_error_exit (j_common_ptr cinfo)
00024 {
00025        my_error_ptr myerr = (my_error_ptr) cinfo->err;
00026        (*cinfo->err->output_message) (cinfo);
00027        longjmp (myerr->setjmp_buffer, 1);
00028 }
00029 
00030 #define ICC_MARKER  (JPEG_APP0 + 2)       /* JPEG marker code for ICC */
00031 #define PHOTOSHOP_MARKER  (JPEG_APP0 + 13)       /* JPEG marker code for PHOTOSHOP */
00032 #define ICC_OVERHEAD_LEN  14              /* size of non-profile data in APP2 */
00033 #define MAX_BYTES_IN_MARKER  65533 /* maximum data len of a JPEG marker */
00034 #define MAX_DATA_BYTES_IN_MARKER  (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
00035 
00036 
00037 ScImgDataLoader_JPEG::ScImgDataLoader_JPEG(void)
00038 {
00039        initSupportedFormatList();
00040 }
00041 
00042 void ScImgDataLoader_JPEG::initSupportedFormatList(void)
00043 {
00044        m_supportedFormats.clear();
00045        m_supportedFormats.append( "jpg" );
00046        m_supportedFormats.append( "jpeg" );
00047 }
00048 
00049 void ScImgDataLoader_JPEG::loadEmbeddedProfile(const QString& fn)
00050 {
00051        m_embeddedProfile.resize(0);
00052        m_profileComponents = 0;
00053        if (!QFile::exists(fn))
00054               return;
00055        struct jpeg_decompress_struct cinfo;
00056        struct my_error_mgr         jerr;
00057        FILE     *infile;
00058        cinfo.err = jpeg_std_error (&jerr.pub);
00059        jerr.pub.error_exit = my_error_exit;
00060        infile = NULL;
00061        if (setjmp (jerr.setjmp_buffer))
00062        {
00063               jpeg_destroy_decompress (&cinfo);
00064               if (infile)
00065                      fclose (infile);
00066               return;
00067        }
00068        jpeg_create_decompress (&cinfo);
00069        if ((infile = fopen (fn.local8Bit(), "rb")) == NULL)
00070               return;
00071        jpeg_stdio_src(&cinfo, infile);
00072        jpeg_save_markers(&cinfo, ICC_MARKER, 0xFFFF);
00073        jpeg_read_header(&cinfo, true);
00074        //jpeg_start_decompress(&cinfo);
00075        unsigned int EmbedLen = 0;
00076        unsigned char* EmbedBuffer;
00077        if (read_jpeg_marker(ICC_MARKER,&cinfo, &EmbedBuffer, &EmbedLen))
00078        {
00079               cmsHPROFILE prof = cmsOpenProfileFromMem(EmbedBuffer, EmbedLen);
00080               if (prof)
00081               {
00082                      if (static_cast<int>(cmsGetColorSpace(prof)) == icSigRgbData)
00083                             m_profileComponents = 3;
00084                      if (static_cast<int>(cmsGetColorSpace(prof)) == icSigCmykData)
00085                             m_profileComponents = 4;
00086                      m_embeddedProfile.duplicate((const char*) EmbedBuffer, EmbedLen);
00087               }
00088               cmsCloseProfile(prof);
00089               free(EmbedBuffer);
00090        }
00091        //(void) jpeg_finish_decompress(&cinfo);
00092        fclose (infile);
00093        jpeg_destroy_decompress (&cinfo);
00094 }
00095 
00096 void ScImgDataLoader_JPEG::preloadAlphaChannel(const QString& fn, int res)
00097 {
00098        // No support for aplha in jpeg pictures
00099        initialize();
00100 }
00101 
00102 bool ScImgDataLoader_JPEG::loadPicture(const QString& fn, int res, bool thumbnail)
00103 {
00104        bool isCMYK = false;
00105        bool fromPS = false;
00106        float xres = 72.0, yres = 72.0;
00107        if (!QFile::exists(fn))
00108               return false;
00109        ExifData ExifInf;
00110        struct jpeg_decompress_struct cinfo;
00111        struct my_error_mgr         jerr;
00112        FILE     *infile;
00113        cinfo.err = jpeg_std_error (&jerr.pub);
00114        jerr.pub.error_exit = my_error_exit;
00115        infile = NULL;
00116 
00117        initialize();
00118        m_imageInfoRecord.type = 0;
00119        m_imageInfoRecord.exifInfo.thumbnail = QImage();
00120        if (setjmp (jerr.setjmp_buffer))
00121        {
00122               jpeg_destroy_decompress (&cinfo);
00123               if (infile)
00124                      fclose (infile);
00125               return false;
00126        }
00127        jpeg_create_decompress (&cinfo);
00128        if ((infile = fopen (fn.local8Bit(), "rb")) == NULL)
00129               return false;
00130        jpeg_stdio_src(&cinfo, infile);
00131        jpeg_save_markers(&cinfo, ICC_MARKER, 0xFFFF);
00132        jpeg_save_markers(&cinfo, PHOTOSHOP_MARKER, 0xFFFF);
00133        jpeg_read_header(&cinfo, true);
00134        jpeg_start_decompress(&cinfo);
00135        bool exi = ExifInf.scan(fn);
00136        if ((exi) && (ExifInf.exifDataValid))
00137        {
00138               if (cinfo.output_components == 4)
00139                      m_imageInfoRecord.colorspace = 1;
00140               else if (cinfo.output_components == 3)
00141                      m_imageInfoRecord.colorspace = 0;
00142               else if (cinfo.output_components == 1)
00143                      m_imageInfoRecord.colorspace = 2;
00144               if ((!ExifInf.isNullThumbnail()) && thumbnail)
00145               {
00146                      m_image = ExifInf.getThumbnail();
00147                      m_imageInfoRecord.exifInfo.thumbnail = ExifInf.getThumbnail();
00148                      if (cinfo.output_components == 4)
00149                      {
00150                             QRgb *s;
00151                             unsigned char cc, cm, cy, ck;
00152                             for( int yit=0; yit < m_image.height(); ++yit )
00153                             {
00154                                    s = (QRgb*)(m_image.scanLine( yit ));
00155                                    for(int xit=0; xit < m_image.width(); ++xit )
00156                                    {
00157                                           cc = 255 - qRed(*s);
00158                                           cm = 255 - qGreen(*s);
00159                                           cy = 255 - qBlue(*s);
00160                                           ck = QMIN(QMIN(cc, cm), cy);
00161                                           *s = qRgba(cc-ck,cm-ck,cy-ck,ck);
00162                                           s++;
00163                                    }
00164                             }
00165                      }
00166               }
00167               else
00168                      m_imageInfoRecord.exifInfo.thumbnail = QImage();
00169               m_imageInfoRecord.exifInfo.cameraName = ExifInf.getCameraModel();
00170               m_imageInfoRecord.exifInfo.cameraVendor = ExifInf.getCameraMake();
00171               m_imageInfoRecord.exifInfo.comment = ExifInf.getComment();
00172               m_imageInfoRecord.exifInfo.width = ExifInf.getWidth();
00173               m_imageInfoRecord.exifInfo.height = ExifInf.getHeight();
00174               m_imageInfoRecord.exifInfo.userComment = ExifInf.getUserComment();
00175               m_imageInfoRecord.exifInfo.dateTime = ExifInf.getDateTime();
00176               m_imageInfoRecord.exifInfo.ApertureFNumber = ExifInf.getApertureFNumber();
00177               m_imageInfoRecord.exifInfo.ExposureTime = ExifInf.getExposureTime();
00178               m_imageInfoRecord.exifInfo.ISOequivalent = ExifInf.getISOequivalent();
00179               m_imageInfoRecord.exifDataValid = true;
00180               if (cinfo.density_unit == 0)
00181               {
00182                      xres = 72;
00183                      yres = 72;
00184               }
00185               else if ( cinfo.density_unit == 1 )
00186               {
00187                      xres = cinfo.X_density;
00188                      yres = cinfo.Y_density;
00189               }
00190               else if ( cinfo.density_unit == 2 )
00191               {
00192                      xres = cinfo.X_density * 2.54;
00193                      yres = cinfo.Y_density * 2.54;
00194               }
00195               if( xres <= 1.0 || yres <= 1.0 || xres > 3000.0 || yres > 3000.0 )
00196               {
00197                      xres = yres = 72.0;
00198                      QFileInfo qfi(fn);
00199                      m_message = QObject::tr("%1 may be corrupted : missing or wrong resolution tags").arg(qfi.fileName());
00200                      m_msgType = warningMsg;
00201               }
00202               m_imageInfoRecord.xres = qRound(xres);
00203               m_imageInfoRecord.yres = qRound(yres);
00204               m_imageInfoRecord.progressive = jpeg_has_multiple_scans(&cinfo);
00205               if ((!ExifInf.isNullThumbnail()) && thumbnail)
00206               {
00207                      jpeg_destroy_decompress(&cinfo);
00208                      fclose(infile);
00209                      return true;
00210               }
00211        }
00212        else
00213               m_imageInfoRecord.exifDataValid = false;
00214        m_imageInfoRecord.exifInfo.thumbnail = QImage();
00215        unsigned int EmbedLen = 0;
00216        unsigned char* EmbedBuffer;
00217        if (read_jpeg_marker(ICC_MARKER,&cinfo, &EmbedBuffer, &EmbedLen))
00218        {
00219               const char *Descriptor;
00220               cmsHPROFILE prof = cmsOpenProfileFromMem(EmbedBuffer, EmbedLen);
00221               Descriptor = cmsTakeProductDesc(prof);
00222               m_embeddedProfile.duplicate((const char*) EmbedBuffer, EmbedLen);
00223               m_imageInfoRecord.profileName = QString(Descriptor);
00224               m_imageInfoRecord.isEmbedded = true;
00225               free(EmbedBuffer);
00226        }
00227        else
00228        {
00229               m_imageInfoRecord.isEmbedded = false;
00230               m_imageInfoRecord.profileName = "";
00231        }
00232        unsigned int PhotoshopLen = 0;
00233        unsigned char * PhotoshopBuffer;
00234        if (cinfo.density_unit == 0)
00235        {
00236               xres = 72;
00237               yres = 72;
00238               m_image.setDotsPerMeterX(2834);
00239               m_image.setDotsPerMeterY(2834);
00240        }
00241        else if ( cinfo.density_unit == 1 )
00242        {
00243               xres = cinfo.X_density;
00244               yres = cinfo.Y_density;
00245               m_image.setDotsPerMeterX( int(100. * cinfo.X_density / 2.54) );
00246               m_image.setDotsPerMeterY( int(100. * cinfo.Y_density / 2.54) );
00247        }
00248        else if ( cinfo.density_unit == 2 )
00249        {
00250               xres = cinfo.X_density * 2.54;
00251               yres = cinfo.Y_density * 2.54;
00252               m_image.setDotsPerMeterX( int(100. * cinfo.X_density) );
00253               m_image.setDotsPerMeterY( int(100. * cinfo.Y_density) );
00254        }
00255        if( xres <= 1.0 || yres <= 1.0 || xres > 3000.0 || yres > 3000.0 )
00256        {
00257               xres = yres = 72.0;
00258               m_image.setDotsPerMeterX(2834);
00259               m_image.setDotsPerMeterY(2834);
00260               QFileInfo qfi(fn);
00261               m_message = QObject::tr("%1 may be corrupted : missing or wrong resolution tags").arg(qfi.fileName());
00262               m_msgType = warningMsg;
00263        }
00264        m_imageInfoRecord.xres = qRound(xres);
00265        m_imageInfoRecord.yres = qRound(yres);
00266        if (cinfo.output_components == 4)
00267        {
00268               isCMYK = true;
00269               m_imageInfoRecord.colorspace = 1;
00270        }
00271        else if (cinfo.output_components == 3)
00272               m_imageInfoRecord.colorspace = 0;
00273        else if (cinfo.output_components == 1)
00274               m_imageInfoRecord.colorspace = 2;
00275        m_imageInfoRecord.progressive = jpeg_has_multiple_scans(&cinfo);
00276 
00277        if (read_jpeg_marker(PHOTOSHOP_MARKER,&cinfo, &PhotoshopBuffer, &PhotoshopLen) )
00278        {
00279               if (PhotoshopLen != 0)
00280               {
00281                      bool savEx = m_imageInfoRecord.exifDataValid;
00282                      QByteArray arrayPhot(PhotoshopLen);
00283                      arrayPhot.setRawData((const char*)PhotoshopBuffer,PhotoshopLen);
00284                      QDataStream strPhot(arrayPhot,IO_ReadOnly);
00285                      strPhot.setByteOrder( QDataStream::BigEndian );
00286                      PSDHeader fakeHeader;
00287                      fakeHeader.width = cinfo.output_width;
00288                      fakeHeader.height = cinfo.output_height;
00289                      if (cinfo.output_components == 4)
00290                             m_imageInfoRecord.colorspace = 1;
00291                      else if (cinfo.output_components == 3)
00292                             m_imageInfoRecord.colorspace = 0;
00293                      else if (cinfo.output_components == 1)
00294                             m_imageInfoRecord.colorspace = 2;
00295                      m_imageInfoRecord.progressive = jpeg_has_multiple_scans(&cinfo);
00296                      parseRessourceData(strPhot, fakeHeader, PhotoshopLen);
00297                      // Photoshop resolution is more accurate than jpeg header resolution
00298                      xres = m_imageInfoRecord.xres;
00299                      yres = m_imageInfoRecord.yres;
00300                      m_image.setDotsPerMeterX( int(100. * m_imageInfoRecord.xres / 2.54) );
00301                      m_image.setDotsPerMeterY( int(100. * m_imageInfoRecord.yres / 2.54) );
00302                      if( xres <= 1.0 || yres <= 1.0 || xres > 3000.0 || yres > 3000.0 )
00303                      {
00304                             xres = yres = 72.0;
00305                             m_imageInfoRecord.xres = qRound(xres);
00306                             m_imageInfoRecord.yres = qRound(yres);
00307                             m_image.setDotsPerMeterX(2834);
00308                             m_image.setDotsPerMeterY(2834);
00309                             QFileInfo qfi(fn);
00310                             m_message = QObject::tr("%1 may be corrupted : missing or wrong resolution tags").arg(qfi.fileName());
00311                             m_msgType = warningMsg;
00312                      }
00313                      if (m_imageInfoRecord.exifDataValid && thumbnail)
00314                      {
00315                             m_image.create(m_imageInfoRecord.exifInfo.width, m_imageInfoRecord.exifInfo.height, 32 );
00316                             m_imageInfoRecord.exifInfo.width = cinfo.output_width;
00317                             m_imageInfoRecord.exifInfo.height = cinfo.output_height;
00318                             if (cinfo.output_components == 4)
00319                             {
00320                                    m_image.setAlphaBuffer(false);
00321                                    QRgb *d;
00322                                    QRgb *s;
00323                                    unsigned char cc, cm, cy, ck;
00324                                    for( int yit=0; yit < m_image.height(); ++yit )
00325                                    {
00326                                           d = (QRgb*)(m_image.scanLine( yit ));
00327                                           s = (QRgb*)(m_imageInfoRecord.exifInfo.thumbnail.scanLine( yit ));
00328                                           for(int xit=0; xit < m_image.width(); ++xit )
00329                                           {
00330                                                  cc = 255 - qRed(*s);
00331                                                  cm = 255 - qGreen(*s);
00332                                                  cy = 255 - qBlue(*s);
00333                                                  ck = QMIN(QMIN(cc, cm), cy);
00334                                                  *d = qRgba(cc-ck,cm-ck,cy-ck,ck);
00335                                                  s++;
00336                                                  d++;
00337                                           }
00338                                    }
00339                             }
00340                             else
00341                                    m_image = m_imageInfoRecord.exifInfo.thumbnail.copy();
00342                      }
00343                      m_imageInfoRecord.valid = (m_imageInfoRecord.PDSpathData.size())>0?true:false; // The only interest is vectormask
00344                      arrayPhot.resetRawData((const char*)PhotoshopBuffer,PhotoshopLen);
00345                      free( PhotoshopBuffer );
00346                      if (m_imageInfoRecord.exifDataValid && thumbnail)
00347                      {
00348                             jpeg_destroy_decompress(&cinfo);
00349                             fclose(infile);
00350                             return true;
00351                      }
00352                      m_imageInfoRecord.exifInfo.thumbnail = QImage();
00353                      m_imageInfoRecord.exifDataValid = savEx;
00354                      fromPS = true;
00355               }
00356        }
00357        if ( cinfo.output_components == 3 || cinfo.output_components == 4)
00358               m_image.create( cinfo.output_width, cinfo.output_height, 32 );
00359        else if ( cinfo.output_components == 1 )
00360        {
00361               m_image.create( cinfo.output_width, cinfo.output_height, 8, 256 );
00362               for (int i=0; i<256; i++)
00363                      m_image.setColor(i, qRgb(i,i,i));
00364        }
00365        if (!m_image.isNull())
00366        {
00367               uchar** lines = m_image.jumpTable();
00368               while (cinfo.output_scanline < cinfo.output_height)
00369                      (void) jpeg_read_scanlines(&cinfo, lines + cinfo.output_scanline, cinfo.output_height);
00370               if ( cinfo.output_components == 3 )
00371               {
00372                      uchar *in;
00373                      QRgb *out;
00374                      for (uint j=0; j<cinfo.output_height; j++)
00375                      {
00376                             in = m_image.scanLine(j) + cinfo.output_width * 3;
00377                             out = (QRgb*) m_image.scanLine(j);
00378                             for (uint i=cinfo.output_width; i--; )
00379                             {
00380                                    in -= 3;
00381                                    out[i] = qRgb(in[0], in[1], in[2]);
00382                             }
00383                      }
00384               }
00385               if ( cinfo.output_components == 4 )
00386               {
00387                      int method = 0;
00388                      if (cinfo.jpeg_color_space == JCS_YCCK)
00389                             method = 1;
00390                      else if (fromPS)
00391                      {
00392                             if ((cinfo.jpeg_color_space == JCS_CMYK) && (cinfo.saw_Adobe_marker) && (cinfo.Adobe_transform == 0))
00393                                    method = 2;
00394                      }
00395                      else if ((cinfo.jpeg_color_space == JCS_CMYK) && (cinfo.saw_Adobe_marker))
00396                             method = 1;
00397                      QRgb *ptr;
00398                      unsigned char c, m, y ,k;
00399                      unsigned char *p;
00400                      for (int i = 0; i < m_image.height(); i++)
00401                      {
00402                             ptr = (QRgb*)  m_image.scanLine(i);
00403                             if (method == 1)
00404                             {
00405                                    for (int j = 0; j <  m_image.width(); j++)
00406                                    {
00407                                           p = (unsigned char *) ptr;
00408                                           c = p[0];
00409                                           m = p[1];
00410                                           y =  p[2];
00411                                           k =  p[3];
00412                                           *ptr = qRgba(255 - c, 255 - m, 255 - y, 255 - k);
00413                                           ptr++;
00414                                    }
00415                             }
00416                             else if (method == 2)
00417                             {
00418                                    for (int j = 0; j <  m_image.width(); j++)
00419                                    {
00420                                           p = (unsigned char *) ptr;
00421                                           c = p[0];
00422                                           m = p[1];
00423                                           y =  p[2];
00424                                           k =  p[3];
00425                                           *ptr = qRgba(255 - c, 255 - m, 255 - y, k);
00426                                           ptr++;
00427                                    }
00428                             }
00429                             else
00430                             {
00431                                    for (int j = 0; j <  m_image.width(); j++)
00432                                    {
00433                                           p = (unsigned char *) ptr;
00434                                           c = p[0];
00435                                           m = p[1];
00436                                           y =  p[2];
00437                                           k =  p[3];
00438                                           *ptr = qRgba(y, m, c, k);
00439                                           ptr++;
00440                                    }
00441                             }
00442                      }
00443                      isCMYK = true;
00444               }
00445               else
00446                      isCMYK = false;
00447               if ( cinfo.output_components == 1 )
00448               {
00449                      QImage tmpImg = m_image.convertDepth(32);
00450                      m_image.create( cinfo.output_width, cinfo.output_height, 32 );
00451                      QRgb *s;
00452                      QRgb *d;
00453                      for( int yi=0; yi < tmpImg.height(); ++yi )
00454                      {
00455                             s = (QRgb*)(tmpImg.scanLine( yi ));
00456                             d = (QRgb*)(m_image.scanLine( yi ));
00457                             for(int xi=0; xi < tmpImg.width(); ++xi )
00458                             {
00459                                    (*d) = (*s);
00460                                    s++;
00461                                    d++;
00462                             }
00463                      }
00464               }
00465               m_image.setAlphaBuffer(true);
00466        }
00467        (void) jpeg_finish_decompress(&cinfo);
00468        fclose (infile);
00469        jpeg_destroy_decompress (&cinfo);
00470        m_imageInfoRecord.layerInfo.clear();
00471        m_imageInfoRecord.BBoxX = 0;
00472        m_imageInfoRecord.BBoxH = m_image.height();
00473        return (!m_image.isNull());
00474 }
00475 
00476 bool ScImgDataLoader_JPEG::marker_is_icc (jpeg_saved_marker_ptr marker)
00477 {
00478        return
00479            marker->marker == ICC_MARKER &&
00480            marker->data_length >= ICC_OVERHEAD_LEN &&
00481            /* verify the identifying string */
00482            GETJOCTET(marker->data[0]) == 0x49 &&
00483            GETJOCTET(marker->data[1]) == 0x43 &&
00484            GETJOCTET(marker->data[2]) == 0x43 &&
00485            GETJOCTET(marker->data[3]) == 0x5F &&
00486            GETJOCTET(marker->data[4]) == 0x50 &&
00487            GETJOCTET(marker->data[5]) == 0x52 &&
00488            GETJOCTET(marker->data[6]) == 0x4F &&
00489            GETJOCTET(marker->data[7]) == 0x46 &&
00490            GETJOCTET(marker->data[8]) == 0x49 &&
00491            GETJOCTET(marker->data[9]) == 0x4C &&
00492            GETJOCTET(marker->data[10]) == 0x45 &&
00493            GETJOCTET(marker->data[11]) == 0x0;
00494 }
00495 
00496 bool ScImgDataLoader_JPEG::marker_is_photoshop (jpeg_saved_marker_ptr marker)
00497 {
00498        return
00499            marker->marker == PHOTOSHOP_MARKER &&
00500            marker->data_length >= ICC_OVERHEAD_LEN &&
00501            /* verify the identifying string */
00502            GETJOCTET(marker->data[0]) == 0x50 &&
00503            GETJOCTET(marker->data[1]) == 0x68 &&
00504            GETJOCTET(marker->data[2]) == 0x6F &&
00505            GETJOCTET(marker->data[3]) == 0x74 &&
00506            GETJOCTET(marker->data[4]) == 0x6F &&
00507            GETJOCTET(marker->data[5]) == 0x73 &&
00508            GETJOCTET(marker->data[6]) == 0x68 &&
00509            GETJOCTET(marker->data[7]) == 0x6F &&
00510            GETJOCTET(marker->data[8]) == 0x70 &&
00511            GETJOCTET(marker->data[9]) == 0x20 &&
00512            GETJOCTET(marker->data[10]) == 0x33 &&
00513            GETJOCTET(marker->data[11]) == 0x2E &&
00514            GETJOCTET(marker->data[12]) == 0x30 &&
00515            GETJOCTET(marker->data[13]) == 0x0;
00516 }
00517 
00518 /* Small modification of original read_icc_profile method from jpegicc of lcms project
00519  * to enable read of Photoshop marker
00520  */
00521 bool ScImgDataLoader_JPEG::read_jpeg_marker (UINT8 requestmarker, j_decompress_ptr cinfo, JOCTET **icc_data_ptr, unsigned int *icc_data_len)
00522 {
00523        jpeg_saved_marker_ptr marker;
00524        int num_markers = 0;
00525        int seq_no;
00526        JOCTET *icc_data;
00527        unsigned int total_length;
00528 #define MAX_SEQ_NO  255            /* sufficient since marker numbers are bytes */
00529        char marker_present[MAX_SEQ_NO+1];   /* 1 if marker found */
00530        unsigned int data_length[MAX_SEQ_NO+1]; /* size of profile data in marker */
00531        unsigned int data_offset[MAX_SEQ_NO+1]; /* offset for data in marker */
00532 
00533        *icc_data_ptr = NULL;              /* avoid confusion if false return */
00534        *icc_data_len = 0;
00535 
00536        /* This first pass over the saved markers discovers whether there are
00537         * any ICC markers and verifies the consistency of the marker numbering.
00538         */
00539 
00540        for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++)
00541               marker_present[seq_no] = 0;
00542        seq_no = 0;
00543        for (marker = cinfo->marker_list; marker != NULL; marker = marker->next)
00544        {
00545               if (requestmarker == ICC_MARKER && marker_is_icc(marker))
00546               {
00547                      if (num_markers == 0)
00548                             num_markers = GETJOCTET(marker->data[13]);
00549                      else if (num_markers != GETJOCTET(marker->data[13]))
00550                             return false;        /* inconsistent num_markers fields */
00551                      seq_no = GETJOCTET(marker->data[12]);
00552                      if (seq_no <= 0 || seq_no > num_markers)
00553                             return false;        /* bogus sequence number */
00554                      if (marker_present[seq_no])
00555                             return false;        /* duplicate sequence numbers */
00556                      marker_present[seq_no] = 1;
00557                      data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
00558               }
00559               else if(requestmarker == PHOTOSHOP_MARKER && marker_is_photoshop(marker))
00560               {
00561                      num_markers = ++seq_no;
00562                      marker_present[seq_no] = 1;
00563                      data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
00564               }
00565        }
00566 
00567        if (num_markers == 0)
00568               return false;
00569 
00570        /* Check for missing markers, count total space needed,
00571         * compute offset of each marker's part of the data.
00572         */
00573 
00574        total_length = 0;
00575        for (seq_no = 1; seq_no <= num_markers; seq_no++)
00576        {
00577               if (marker_present[seq_no] == 0)
00578                      return false;        /* missing sequence number */
00579               data_offset[seq_no] = total_length;
00580               total_length += data_length[seq_no];
00581        }
00582 
00583        if (total_length <= 0)
00584               return false;        /* found only empty markers? */
00585 
00586        /* Allocate space for assembled data */
00587        icc_data = (JOCTET *) malloc(total_length * sizeof(JOCTET));
00588        if (icc_data == NULL)
00589               return false;        /* oops, out of memory */
00590        seq_no=0;
00591        /* and fill it in */
00592        for (marker = cinfo->marker_list; marker != NULL; marker = marker->next)
00593        {
00594               if ( (requestmarker == ICC_MARKER && marker_is_icc(marker)) ||
00595                       (requestmarker == PHOTOSHOP_MARKER && marker_is_photoshop(marker)) || (requestmarker == 0xE1))
00596               {
00597                      JOCTET FAR *src_ptr;
00598                      JOCTET *dst_ptr;
00599                      unsigned int length;
00600                      if(requestmarker == ICC_MARKER)
00601                             seq_no = GETJOCTET(marker->data[12]);
00602                      else if(requestmarker == PHOTOSHOP_MARKER)
00603                             seq_no++;
00604                      dst_ptr = icc_data + data_offset[seq_no];
00605                      src_ptr = marker->data + ICC_OVERHEAD_LEN;
00606                      length = data_length[seq_no];
00607                      while (length--)
00608                      {
00609                             *dst_ptr++ = *src_ptr++;
00610                      }
00611               }
00612        }
00613 
00614        *icc_data_ptr = icc_data;
00615        *icc_data_len = total_length;
00616 
00617        return true;
00618 }