Example #1
0
/* Add a link to an arbitrary Internet resource (URL) */
PDFLIB_API void PDFLIB_CALL
PDF_add_weblink(
    PDF *p,
    float llx,
    float lly,
    float urx,
    float ury,
    const char *url)
{
    static const char fn[] = "PDF_add_weblink";
    pdf_annot *ann;

    PDF_TRACE(("%s\t(pdf[%p], %f, %f, %f, %f, \"%s\");\n",
    	fn, (void *) p, llx, lly, urx, ury, url));

    if (PDF_SANITY_CHECK_FAILED(p))
	return;

    PDF_CHECK_SCOPE(p, fn, pdf_state_page);

    if (url == NULL || *url == '\0')
	pdf_error(p, PDF_ValueError, "NULL URL in PDF_add_weblink");

    ann = (pdf_annot *) p->malloc(p, sizeof(pdf_annot), "PDF_add_weblink");

    ann->filename = pdf_strdup(p, url);

    ann->type	  = ann_weblink;
    ann->rect.llx = llx;
    ann->rect.lly = lly;
    ann->rect.urx = urx;
    ann->rect.ury = ury;

    pdf_add_annot(p, ann);
}
Example #2
0
/* Add a link to another PDF file */
PDFLIB_API void PDFLIB_CALL
PDF_add_pdflink(
    PDF *p,
    float llx,
    float lly,
    float urx,
    float ury,
    const char *filename,
    int page,
    const char *desttype)
{
    static const char fn[] = "PDF_add_pdflink";
    pdf_annot *ann;

    PDF_TRACE(("%s\t(pdf[%p], %f, %f, %f, %f, \"%s\", %d, \"%s\");\n",
    	fn, (void *) p, llx, lly, urx, ury, filename, page, desttype));

    if (PDF_SANITY_CHECK_FAILED(p))
	return;

    PDF_CHECK_SCOPE(p, fn, pdf_state_page);

    if (filename == NULL)
	pdf_error(p, PDF_ValueError, "NULL filename in PDF_add_pdflink");

    ann = (pdf_annot *) p->malloc(p, sizeof(pdf_annot), "PDF_add_pdflink");

    ann->filename = pdf_strdup(p, filename);

    ann->type	  	= ann_pdflink;
    ann->dest.page 	= page;

    if (desttype == NULL)
	ann->dest.type 	= fitpage;
    else if (!strcmp(desttype, "retain"))
	ann->dest.type 	= retain;
    else if (!strcmp(desttype, "fitpage"))
	ann->dest.type 	= fitpage;
    else if (!strcmp(desttype, "fitwidth"))
	ann->dest.type 	= fitwidth;
    else if (!strcmp(desttype, "fitheight"))
	ann->dest.type 	= fitheight;
    else if (!strcmp(desttype, "fitbbox"))
	ann->dest.type 	= fitbbox;
    else
	pdf_error(p, PDF_ValueError,
		"Unknown destination type '%s' in PDF_add_pdflink", desttype);

    ann->rect.llx = llx;
    ann->rect.lly = lly;
    ann->rect.urx = urx;
    ann->rect.ury = ury;


    pdf_add_annot(p, ann);
}
Example #3
0
PDFLIB_API int PDFLIB_CALL
PDF_open_file(PDF *p, const char *filename)
{
    static const char fn[] = "PDF_open_file";

    PDF_TRACE(("%s\t(pdf[%p], \"%s\");", fn, (void *) p, filename));

    if (PDF_SANITY_CHECK_FAILED(p))
	return -1;

    PDF_CHECK_SCOPE(p, fn, pdf_state_object);

    pdf_init_all(p);

    if (filename == NULL || *filename == '\0') {
	/* no file name supplied ==> in-core PDF generation requested */
	p->writeproc = NULL;
	p->filename = NULL;

    } else {
#if !(defined(MAC) && defined(__MWERKS__))
	if (filename && !strcmp(filename, "-")) {
	    p->filename = NULL;
	    p->fp = stdout;
#if !defined(__MWERKS__) && (defined(WIN32) || defined(OS2))
#if defined WINCE
	    _setmode(fileno(stdout), _O_BINARY);
#else
	    _setmode(_fileno(stdout), O_BINARY);
#endif /* !WINCE */
#endif
	} else
#endif /* MAC */

	if ((p->fp = fopen(filename, WRITEMODE)) == NULL) {
	    PDF_SET_STATE(p, "PDF_open_file", pdf_state_object);
	    PDF_TRACE((" [%d]\n", -1));
	    return -1;
	}

	p->writeproc = pdf_writeproc_file;
	p->filename = pdf_strdup(p, filename);
    }

    pdf_write_header(p);

    PDF_TRACE((" [%d]\n", pdf_true));
    return pdf_true;
}
Example #4
0
int
pdf_add_colorspace(PDF *p, pdf_colorspace cs, const char *spotname)
{
    int	slot;

    /* TODO: optimize and check for known color space combinations
    if (cs == Separation)
    for (slot = 0; slot < p->colorspaces_number; slot++) {
    if (!strcmp(p->colorspaces[slot].name, spotname))
        return slot;
    }
    */

    slot = p->colorspaces_number;

    if (p->colorspaces_number >= p->colorspaces_capacity)
        pdf_grow_colorspaces(p);

    if (cs == Separation) {
        p->colorspaces[slot].obj_id = pdf_alloc_id(p);
        p->colorspaces[slot].name = pdf_strdup(p, spotname);
        p->colorspaces[slot].cs = Separation;

        p->colorspaces[slot].alternate = p->cstate[p->sl].fill;

    } else if (cs == PatternCS) {
        p->colorspaces[slot].obj_id = pdf_alloc_id(p);
        p->colorspaces[slot].name = (char *) NULL;
        p->colorspaces[slot].cs = PatternCS;

        p->colorspaces[slot].alternate = p->cstate[p->sl].fill;

    } else {
        pdf_error(p, PDF_SystemError,
                  "Unknown color space in pdf_add_colorspace");
    }

    p->colorspaces[p->colorspaces_number].used_on_current_page = pdf_true;

    p->colorspaces_number++;

    return slot;
}
Example #5
0
PDFLIB_API int PDFLIB_CALL
PDF_open_CCITT(PDF *p, const char *filename, int width, int height,
		int BitReverse, int K, int BlackIs1)
{
    pdf_image *image;
    int im;
    char scratch[30];

    if (PDF_SANITY_CHECK_FAILED(p))
	return -1;

    for (im = 0; im < p->images_capacity; im++)
	if (!p->images[im].in_use)		/* found free slot */
	    break;

    if (im == p->images_capacity) 
	pdf_grow_images(p);

    image = &p->images[im];

    if ((image->fp = fopen(filename, READMODE)) == NULL) {
	if (p->debug['i']) {
	    pdf_error(p, PDF_NonfatalError, "Couldn't open CCITT file '%s'", filename);
	}
        return -1;
    }

    /* Grab the image parameters and pack them into image struct */
    image->filename     		= pdf_strdup(p, filename);

    /* CCITT specific information */
    image->width          		= width;
    image->height         		= height;
    image->info.ccitt.BitReverse	= BitReverse;

    if (BlackIs1 == 0 && K == 0)	/* default values */
	image->params = NULL;
    else {
	scratch[0] = '\0';
	if (K != 0) {
	    sprintf(scratch, "/K %d", K);
	}
	if (BlackIs1 == 1)
	    strcat(scratch, "/BlackIs1 true");
	image->params = pdf_strdup(p, scratch);
    }

    /* The following are fixed for CCITT images */
    image->compression  	= ccitt;
    image->colorspace		= DeviceGray;
    image->components		= 1;
    image->bpc			= 1;

    image->src.init             = pdf_data_source_CCITT_init;
    image->src.fill             = pdf_data_source_CCITT_fill;
    image->src.terminate        = pdf_data_source_CCITT_terminate;
    image->src.private_data     = (void *) image;

    image->in_use 		= pdf_true;		/* mark slot as used */

    pdf_put_image(p, im, pdf_true);
    fclose(image->fp);

    return im;
}
Example #6
0
PDFLIB_API void PDFLIB_CALL
PDF_add_note(
    PDF *p,
    float llx,
    float lly,
    float urx,
    float ury,
    const char *contents,
    const char *title,
    const char *icon,
    int open)
{
    static const char fn[] = "PDF_add_note";
    pdf_annot *ann;

    PDF_TRACE(("%s\t(pdf[%p], %f, %f, %f, %f, \"%s\", \"%s\", \"%s\", %d);\n",
    	fn, (void *) p, llx, lly, urx, ury, contents, title, icon, open));

    if (PDF_SANITY_CHECK_FAILED(p))
	return;

    PDF_CHECK_SCOPE(p, fn, pdf_state_page);

    ann = (pdf_annot *) p->malloc(p, sizeof(pdf_annot), "pdf_add_note");

    ann->type	  = ann_text;
    ann->open	  = open;
    ann->rect.llx = llx;
    ann->rect.lly = lly;
    ann->rect.urx = urx;
    ann->rect.ury = ury;

    if (p->compatibility == PDF_1_2 && icon != NULL && *icon != '\0')
	pdf_error(p, PDF_RuntimeError,
		"Note icons are not supported in PDF 1.2");

    if (icon == NULL || *icon == '\0')
	ann->icon = icon_text_note;
    else if (!strcmp(icon, "comment"))
	ann->icon = icon_text_comment;
    else if (!strcmp(icon, "insert"))
	ann->icon = icon_text_insert;
    else if (!strcmp(icon, "note"))
	ann->icon = icon_text_note;
    else if (!strcmp(icon, "paragraph"))
	ann->icon = icon_text_paragraph;
    else if (!strcmp(icon, "newparagraph"))
	ann->icon = icon_text_newparagraph;
    else if (!strcmp(icon, "key"))
	ann->icon = icon_text_key;
    else if (!strcmp(icon, "help"))
	ann->icon = icon_text_help;
    else
	pdf_error(p, PDF_ValueError,
		"Unknown icon type '%s' for text note", icon);
	
    /* title may be NULL */
    if (title != NULL) {
	ann->title = pdf_strdup(p, title);
#ifdef PDFLIB_EBCDIC
	if (!pdf_is_unicode(ann->title))
	    pdf_make_ascii(ann->title);
#endif
    } else
	ann->title = NULL;

    /* It is legal to create an empty text annnotation */
    if (contents != NULL) {
	ann->contents = pdf_strdup(p, contents);
#ifdef PDFLIB_EBCDIC
	if (!pdf_is_unicode(ann->contents))
	    pdf_make_ascii(ann->contents);
#endif
    } else
	ann->contents = NULL;

    pdf_add_annot(p, ann);
}
Example #7
0
/* Attach an arbitrary file to the PDF. Note that the actual
 * embedding takes place in PDF_end_page().
 * description, author, and mimetype may be NULL.
 */
PDFLIB_API void PDFLIB_CALL
PDF_attach_file(
    PDF *p,
    float llx,
    float lly,
    float urx,
    float ury,
    const char *filename,
    const char *description,
    const char *author,
    const char *mimetype,
    const char *icon)
{
    static const char fn[] = "PDF_attach_file";
    pdf_annot *ann;

    PDF_TRACE(("%s\t(pdf[%p], %f, %f, %f, %f, ", fn, (void *) p,
	llx, lly, urx, ury));

    PDF_TRACE(("\"%s\", \"%s\", \"%s\", \"%s\", \"%s\");\n",
    	filename, description, author, mimetype, icon));

    if (PDF_SANITY_CHECK_FAILED(p))
	return;

    PDF_CHECK_SCOPE(p, fn, pdf_state_page);

    if (p->compatibility == PDF_1_2)
	pdf_error(p, PDF_RuntimeError,
		"File attachments are not supported in PDF 1.2");

    if (filename == NULL)
	pdf_error(p, PDF_ValueError, "Empty file name for file attachment");

    ann = (pdf_annot *) p->malloc(p, sizeof(pdf_annot),"PDF_attach_file");

    ann->type	  = ann_attach;
    ann->rect.llx = llx;
    ann->rect.lly = lly;
    ann->rect.urx = urx;
    ann->rect.ury = ury;

    if (icon == NULL)
	ann->icon = icon_file_pushpin;
    else if (!strcmp(icon, "graph"))
	ann->icon = icon_file_graph;
    else if (!strcmp(icon, "paperclip"))
	ann->icon = icon_file_paperclip;
    else if (!strcmp(icon, "pushpin"))
	ann->icon = icon_file_pushpin;
    else if (!strcmp(icon, "tag"))
	ann->icon = icon_file_tag;
    else
	pdf_error(p, PDF_ValueError, "Unknown icon type '%s'for embedded file",
			icon);

    ann->filename = (char *) pdf_strdup(p, filename);

    if (description != NULL) {
	ann->contents = (char *) pdf_strdup(p, description);
#ifdef PDFLIB_EBCDIC
	if (!pdf_is_unicode(ann->contents))
	    pdf_make_ascii(ann->contents);
#endif
    }

    if (author != NULL) {
	ann->title = (char *) pdf_strdup(p, author);
#ifdef PDFLIB_EBCDIC
	if (!pdf_is_unicode(ann->title))
	    pdf_make_ascii(ann->title);
#endif
    }

    if (mimetype != NULL)
	ann->mimetype = (char *) pdf_strdup(p, mimetype);

    pdf_add_annot(p, ann);
}
Example #8
0
PDFLIB_API int PDFLIB_CALL
PDF_open_image(
    PDF *p,
    const char *type,
    const char *source,
    const char *data,
    long length,
    int width,
    int height,
    int components,
    int bpc,
    const char *params)
{
    static const char fn[] = "PDF_open_image";
    pdf_image *image;
    int im;

    PDF_TRACE(("%s\t(pdf[%p], \"%s\", \"%s\", source[%p], ",
    	fn, (void *) p, type, source, (void *) data));

    PDF_TRACE(("%ld, %d, %d, %d, %d, \"%s\");",
    	length, width, height, components, bpc, params));

    if (PDF_SANITY_CHECK_FAILED(p))
	return -1;

    PDF_CHECK_SCOPE(p, fn, pdf_state_document | pdf_state_page);

    if (type == NULL || *type == '\0')
    	pdf_error(p, PDF_ValueError, "No image type in PDF_open_image");

    if (source == NULL || *source == '\0')
    	pdf_error(p, PDF_ValueError, "No image source in PDF_open_image");

    if (!strcmp(type, "raw") && data == NULL)
    	pdf_error(p, PDF_ValueError, "Bad raw image pointer in PDF_open_image");

    if (strcmp(type, "ccitt") && strcmp(type, "raw")
	    && params != NULL && *params != '\0')
    	pdf_error(p, PDF_NonfatalError,
	    "Unnecessary CCITT parameter in PDF_open_image");

    for (im = 0; im < p->images_capacity; im++)
	if (!p->images[im].in_use)		/* found free slot */
	    break;

    if (im == p->images_capacity) 
	pdf_grow_images(p);

    image = &p->images[im];

    if (!strcmp(type, "jpeg")) {
	image->compression = dct;
	image->use_raw	= pdf_true;

    } else if (!strcmp(type, "ccitt")) {
	image->compression = ccitt;
	image->use_raw	= pdf_true;

	if (length < 0L) {
	    image->info.ccitt.BitReverse = pdf_true;
	    length = -length;
	}

	if (params != NULL && *params != '\0')
	    image->params = pdf_strdup(p, params);
	else
	    image->params = NULL;

    } else if (!strcmp(type, "raw")) {
	image->compression = none;

    } else
	pdf_error(p, PDF_ValueError,
	    "Unknown image type '%s' in PDF_open_image", type);

    switch (components) {
	case 1:
	    if (params && !strcmp(params, "mask")) {
		if (strcmp(type, "raw") || bpc != 1)
		    pdf_error(p, PDF_ValueError,
			"Unsuitable image mask in PDF_open_image");
		image->colorspace = ImageMask;
	    } else
		image->colorspace = DeviceGray;
	    break;

	case 3:
	    image->colorspace = DeviceRGB;
	    break;

	case 4:
	    image->colorspace = DeviceCMYK;
	    break;

	default:
	    pdf_error(p, PDF_ValueError,
	    	"Bogus number of components (%d) in PDF_open_image",
		components);
    }

    image->width		= (float) width;
    image->height		= (float) height;
    image->bpc			= bpc;
    image->components		= components;
    image->in_use		= pdf_true;		/* mark slot as used */

    if (!strcmp(source, "memory")) {	/* in-memory image data */
	if (image->compression == none && length != (long)
	    	(height * ((width * components * bpc + 7) / 8)))
	    pdf_error(p, PDF_ValueError,
		"Bogus image data length '%ld' in PDF_open_image", length);

	image->src.init		= pdf_noop;
	image->src.fill		= pdf_data_source_buf_fill;
	image->src.terminate	= pdf_noop;

	image->src.buffer_start	= (unsigned char *) data;
	image->src.buffer_length= (size_t) length;

	image->src.bytes_available = 0;
	image->src.next_byte	= NULL;

    } else if (!strcmp(source, "memory32")) {
	/* 32 bit aligned in-memory image data */
	FILL_ALIGN fa;

	if (image->compression == none && length != (long)
	    	(height * ((width * components * bpc + 7) / 8)))
	    pdf_error(p, PDF_ValueError,
		"Bogus image data length '%ld' in PDF_open_image", length);

	image->src.buffer_start	= (unsigned char *) data;
	image->src.buffer_length= (size_t) length;

	image->src.init		= pdf_noop;
	image->src.fill		= pdf_data_source_buf_fill_aligned;
	image->src.terminate	= pdf_noop;

	fa.cur_scanline = 0;
	fa.num_scanlines = (size_t) height;
	fa.scanline_widthbytes = (size_t) ((width * components * bpc + 7) / 8);
	/* dword align */
	fa.scanline_widthbytes_aligned = (fa.scanline_widthbytes + 3) & ~0x3;

	image->src.private_data = (void *) &fa;
	image->src.bytes_available = 0;
	image->src.next_byte	= NULL;

    } else if (!strcmp(source, "fileref")) {	/* file reference */
	if (p->compatibility == PDF_1_2)
	    pdf_error(p, PDF_RuntimeError,
		"External image file references are not supported in PDF 1.2");

	image->reference	= pdf_ref_file;
	image->filename		= pdf_strdup(p, data);

    } else if (!strcmp(source, "url")) {	/* url reference */
	if (p->compatibility == PDF_1_2)
	    pdf_error(p, PDF_RuntimeError,
		"External image URLs are not supported in PDF 1.2");

	image->reference	= pdf_ref_url;
	image->filename		= pdf_strdup(p, data);

    } else			/* error */
	pdf_error(p, PDF_ValueError,
	    "Bogus image data source '%s' in PDF_open_image", source);

    pdf_put_image(p, im, pdf_true);

    PDF_TRACE((" [%d]\n", im));

    return im;
}
Example #9
0
/* open JPEG image and analyze marker */
int
pdf_open_JPEG_data(
    PDF *p,
    int imageslot,
    const char *filename,
    const char *stringparam,
    int intparam)
{
    static const char fn[] = "pdf_open_JPEG_data";

    int b, c, unit;
    unsigned long i, length;
#define APP_MAX 255
    unsigned char appstring[APP_MAX];
    pdf_byte *app13;
    pdf_byte *s;
    pdf_image *image;
    int mask = -1;
    pdf_bool adobeflag = pdf_false;
    pdf_bool SOF_done = pdf_false;
    pdf_bool colorize = pdf_false;

    image = &p->images[imageslot];

    if ((image->fp = fopen(filename, READMODE)) == NULL) {
	if (p->debug['i'])
	    pdf_error(p, PDF_NonfatalError,
		"Couldn't open JPEG file '%s'", filename);
	return -1;		/* Couldn't open JPEG file */
    }

    image->compression		= dct;
    image->use_raw		= pdf_true;

    image->src.init		= pdf_data_source_JPEG_init;
    image->src.fill		= pdf_data_source_JPEG_fill;
    image->src.terminate	= pdf_data_source_JPEG_terminate;
    image->src.private_data	= (void *) image;

  /* Tommy's special trick for Macintosh JPEGs: simply skip some  */
  /* hundred bytes at the beginning of the file!		  */
  do {
    do {                            /* skip if not FF 		  */
      c = getc(image->fp);
    } while (!feof(image->fp) && c != 0xFF);

    if (feof(image->fp)) {
	fclose(image->fp);
	if (p->debug['i'])
	    pdf_error(p, PDF_NonfatalError,
		"File problem with JPEG file '%s'", filename);
	return -1;
    }

    do {                            /* skip repeated FFs 	  */
      c = getc(image->fp);
    } while (c == 0xFF);

    /* remember start position */
    if ((image->info.jpeg.startpos = ftell(image->fp)) < 0L) {
	fclose(image->fp);
	if (p->debug['i'])
	    pdf_error(p, PDF_NonfatalError,
		"File problem with JPEG file '%s'", filename);
	return -1;
    }

    image->info.jpeg.startpos -= 2;	/* subtract marker length     */

    if (c == M_SOI) {
      fseek(image->fp, image->info.jpeg.startpos, SEEK_SET);
      break;
    }
  } while (!feof(image->fp));

#define BOGUS_LENGTH	768
  /* Heuristics: if we are that far from the start chances are
   * it is a TIFF file with embedded JPEG data which we cannot
   * handle - regard as hopeless...
   */
  if (feof(image->fp) || image->info.jpeg.startpos > BOGUS_LENGTH) {
    fclose(image->fp);
    if (p->debug['i'])
	pdf_error(p, PDF_NonfatalError,
	    "File '%s' doesn't appear to be of type JPEG", filename);
    return -1;
  }

  /* process JPEG markers */
  while (!SOF_done && (c = pdf_next_jpeg_marker(image->fp)) != M_EOI) {
    switch (c) {
      case M_ERROR:
      /* The following are not supported in PDF 1.3 */
      case M_SOF3:
      case M_SOF5:
      case M_SOF6:
      case M_SOF7:
      case M_SOF9:
      case M_SOF11:
      case M_SOF13:
      case M_SOF14:
      case M_SOF15:
	fclose(image->fp);
        if (p->debug['i'])
	    pdf_error(p, PDF_NonfatalError,
	"JPEG compression scheme '%d' in file '%s' is not supported in PDF 1.3",
		(int) c, filename);
	return -1;

      /*
       * SOF2 and SOF10 are progressive DCT which are not
       * supported prior to Acrobat 4.
       */
      case M_SOF2:
      case M_SOF10:
	if (p->compatibility == PDF_1_2) {
	    fclose(image->fp);
	    if (p->debug['i'])
		pdf_error(p, PDF_NonfatalError, 
		    "Progressive JPEG images are not supported in PDF 1.2");
	    return -1;
	}
	/* fallthrough */

      case M_SOF0:
      case M_SOF1:
	(void) get_2bytes(image->fp);    /* read segment length  */

	image->bpc		 = getc(image->fp);
	image->height            = (float) get_2bytes(image->fp);
	image->width             = (float) get_2bytes(image->fp);
	image->components        = getc(image->fp);

	SOF_done = pdf_true;
	break;

      case M_APP0:		/* check for JFIF marker with resolution */
	length = get_2bytes(image->fp);

	for (i = 0; i < length-2; i++) {	/* get contents of marker */
	  b = getc(image->fp);
	  if (i < APP_MAX)			/* store marker in appstring */
	    appstring[i] = (unsigned char) b;
	}

	/* Check for JFIF application marker and read density values
	 * per JFIF spec version 1.02.
	 */

#define JFIF_ASPECT_RATIO	0	/* JFIF unit byte: aspect ratio only */
#define JFIF_DOTS_PER_INCH	1	/* JFIF unit byte: dots per inch     */
#define JFIF_DOTS_PER_CM	2	/* JFIF unit byte: dots per cm       */

#define PDF_STRING_JFIF	"\112\106\111\106"

	if (length >= 14 && !strncmp(PDF_STRING_JFIF, (char *) appstring, 4)) {
	  unit = appstring[7];		        /* resolution unit */
	  					/* resolution value */
	  image->dpi_x = (float) ((appstring[8]<<8) + appstring[9]);	
	  image->dpi_y = (float) ((appstring[10]<<8) + appstring[11]);	

	  if (image->dpi_x <= (float) 0.0 || image->dpi_y <= (float) 0.0) {
	    image->dpi_x = (float) 0.0;
	    image->dpi_y = (float) 0.0;
	    break;
	  }

	  switch (unit) {
	    case JFIF_DOTS_PER_INCH:
	      break;

	    case JFIF_DOTS_PER_CM:
	      image->dpi_x *= (float) 2.54;
	      image->dpi_y *= (float) 2.54;
	      break;

	    case JFIF_ASPECT_RATIO:
	      image->dpi_x *= -1;
	      image->dpi_y *= -1;
	      break;

	    default:				/* unknown ==> ignore */
		/* */ ;
	  }
	}

        break;

#ifdef NYI
        /* LATER: read SPIFF marker */
      case M_APP8:				/* check for SPIFF marker */

        break;
#endif

      case M_APP13:				/* check for Photoshop marker */
	length = get_2bytes(image->fp);

	/* get marker contents */
	length -= 2;			/* account for two length bytes */
	app13 = p->malloc(p, length, fn);

	if (fread(app13, 1, length, image->fp) != length) {
	    fclose(image->fp);
	    p->free(p, app13);
	    if (p->debug['i']) {
		pdf_error(p, PDF_NonfatalError,
		"JPEG file '%s' is damaged (Photoshop marker too short)",
		filename);
	    }
	    return -1;
	}

#define PS_HEADER_LEN		14
#define PDF_STRING_Photoshop	"\120\150\157\164\157\163\150\157\160"
#define PDF_STRING_8BIM		"\070\102\111\115"
#define RESOLUTION_INFO_ID	0x03ED	/* resolution info resource block */
#define PS_FIXED_TO_FLOAT(h, l)	((float) (h) + ((float) (l)/(1<<16)))

	/* Not a valid Photoshop marker */
	if (length < 9 || strncmp(PDF_STRING_Photoshop, (char *) app13, 9)) {
	    p->free(p, app13);
	    break;
	}

	/* walk all image resource blocks and look for ResolutionInfo */
	for (s = app13 + PS_HEADER_LEN; s < app13 + length; /* */) {
	    long len;
	    unsigned int type;

	    if (strncmp((char *) s, PDF_STRING_8BIM, 4))
		break;	/* out of sync */
	    s += 4;	/* identifying string */

	    type = (unsigned int) ((s[0]<<8) + s[1]);
	    s += 2;	/* resource type */

	    s += *s + ((*s & 1) ? 1 : 2);	/* resource name */

	    len = (((((s[0]<<8) + s[1])<<8) + s[2])<<8) + s[3];
	    s += 4;	/* Size */

	    if (type == RESOLUTION_INFO_ID && len >= 16) {
		  image->dpi_x =
			PS_FIXED_TO_FLOAT((s[0]<<8) + s[1], (s[2]<<8) + s[3]);
		  image->dpi_y =
			PS_FIXED_TO_FLOAT((s[8]<<8) + s[9], (s[10]<<8) + s[11]);
		  break;
	    }

	    s += len + ((len & 1) ? 1 : 0); 	/* Data */
	}

	p->free(p, app13);
        break;

      case M_APP14:				/* check for Adobe marker */
	length = get_2bytes(image->fp);

	for (i = 0; i < length-2; i++) {	/* get contents of marker */
	  b = getc(image->fp);
	  if (i < APP_MAX)			/* store marker in appstring */
	    appstring[i] = (unsigned char) b;
	  else
	    break;
	}

	/* 
	 * Check for Adobe application marker. It is known (per Adobe's TN5116)
	 * to contain the string "Adobe" at the start of the APP14 marker.
	 */
#define PDF_STRING_Adobe	"\101\144\157\142\145"

	if (length >= 12 && !strncmp(PDF_STRING_Adobe, (char *) appstring, 5))
	  adobeflag = pdf_true;		/* set Adobe flag */

	break;

      case M_SOI:		/* ignore markers without parameters */
      case M_EOI:
      case M_TEM:
      case M_RST0:
      case M_RST1:
      case M_RST2:
      case M_RST3:
      case M_RST4:
      case M_RST5:
      case M_RST6:
      case M_RST7:
	break;

      default:			/* skip variable length markers */
	length = get_2bytes(image->fp);
	for (length -= 2; length > 0; length--) {
	  if (feof(image->fp)) {
	      fclose(image->fp);
	      if (p->debug['i'])
	  	pdf_error(p, PDF_NonfatalError,
	  	    "JPEG file '%s' is damaged", filename);
	      return -1;
	  }
	  (void) getc(image->fp);
	}
	break;
    }
  }

    /* do some sanity checks with the parameters */
    if (image->height <= 0 || image->width <= 0 || image->components <= 0) {
	fclose(image->fp);
	if (p->debug['i'])
	    pdf_error(p, PDF_NonfatalError,
		"Bad image parameters in JPEG file '%s' (w=%d h=%d, colors=%d",
		filename, image->width, image->height, image->components);
	return -1;
    }

    if (image->bpc != 8) {
	fclose(image->fp);
	if (p->debug['i'])
	    pdf_error(p, PDF_NonfatalError, 
		"Bad number of bits per pixel (%d) in JPEG file '%s'",
		image->bpc, filename);
	return -1;
    }

    if (stringparam && *stringparam) {
	if (!strcmp(stringparam, "mask")) {
	    fclose(image->fp);
	    pdf_error(p, PDF_ValueError, "Can't handle JPEG image mask");

	} else if (!strcmp(stringparam, "colorize")) {
	    if (image->components != 1) {
		fclose(image->fp);
		pdf_error(p, PDF_ValueError,
		    "Can't colorize JPEG image with more than 1 component");
	    }
	    if (intparam >= p->colorspaces_number) {
		fclose(image->fp);
                pdf_error(p, PDF_ValueError,
		    "Invalid color number %d for image %s", intparam, filename);
	    }
            image->colorspace = (pdf_colorspace) (intparam + LastCS);
	    colorize = pdf_true;

	} else if (!strcmp(stringparam, "masked")) {
	    mask = intparam;
	    if (mask >= 0 && (mask >= p->images_capacity ||
		!p->images[mask].in_use || p->images[mask].strips != 1 ||
		p->images[mask].colorspace != ImageMask)) {
		    fclose(image->fp);
		    pdf_error(p, PDF_ValueError,
		    "Bad image mask (no %d) for image '%s'", mask, filename);
	    }
	}
	else {
	    fclose(image->fp);
	    pdf_error(p, PDF_ValueError,
	    	"Unknown parameter %s in pdf_open_JPEG", stringparam);
	}
    }

    image->mask = mask;

    switch (image->components) {
	case 1:
	    if (!colorize)
		image->colorspace = DeviceGray;
	    break;

	case 3:
	    image->colorspace = DeviceRGB;
	    break;

	case 4:
	    image->colorspace = DeviceCMYK;
	    /* special handling of Photoshop-generated CMYK JPEG files */
	    if (adobeflag)
		image->invert = pdf_true;
	    break;

	default:
	    fclose(image->fp);
	    if (p->debug['i'])
		pdf_error(p, PDF_NonfatalError,
		    "Unknown number of color components (%d) in JPEG file '%s'",
		    image->components, filename);
	    return -1;
    }

    image->in_use	= pdf_true;		/* mark slot as used */

    image->filename	= pdf_strdup(p, filename);

    pdf_put_image(p, imageslot, pdf_true);
    fclose(image->fp);

    return imageslot;
}