示例#1
0
/* Finish the pattern definition. */
PDFLIB_API void PDFLIB_CALL
PDF_end_pattern(PDF *p)
{
    static const char fn[] = "PDF_end_pattern";
    long length;

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

    if (PDF_SANITY_CHECK_FAILED(p))
	return;

    PDF_CHECK_SCOPE(p, fn, pdf_state_pattern);

    /* check whether PDF_save() and PDF_restore() calls are balanced */
    if (p->sl > 0)
	pdf_error(p, PDF_RuntimeError,
	    "Unmatched save level at end of pattern");

    pdf_end_text(p);
    p->contents = c_none;

    if (p->compresslevel)
	pdf_compress_end(p);
					
    length = pdf_tell(p) - p->start_contents_pos;
    pdf_end_stream(p);
    pdf_end_obj(p);				/* pattern */

    pdf_begin_obj(p, p->contents_length_id);	/* Length object */
    pdf_printf(p, "%ld\n", length);
    pdf_end_obj(p);
  
    pdf_begin_obj(p, p->res_id);		/* Resource object */
    pdf_begin_dict(p);				/* Resource dict */

    pdf_write_page_procsets(p);			/* ProcSet resources */

    pdf_write_page_fonts(p);			/* Font resources */

    pdf_write_page_colorspaces(p);		/* Color space resources */

    pdf_write_page_pattern(p);			/* Pattern resources */

    pdf_write_xobjects(p);			/* XObject resources */

    pdf_end_dict(p);				/* resource dict */
    pdf_end_obj(p);				/* resource object */

    PDF_POP_STATE(p, fn);

    if (p->flush & PDF_FLUSH_PAGE)
	pdf_flush_stream(p);
}
示例#2
0
static void
pdf_write_pnode(PDF *p,
	id node_id,
	id parent_id,
	id *kids,
	int n_kids,
	int n_pages)
{
    pdf_begin_obj(p, node_id);
    pdf_begin_dict(p);
    pdf_puts(p, "/Type/Pages\n");
    pdf_printf(p, "/Count %d\n", n_pages);

    if (parent_id != BAD_ID)
	pdf_printf(p, "/Parent %d 0 R\n", parent_id);

    pdf_puts(p, "/Kids[");

    do
    {
	pdf_printf(p, "%ld 0 R", *kids++);
	pdf_putc(p, PDF_NEWLINE);
    } while (--n_kids > 0);

    pdf_puts(p, "]");
    pdf_end_dict(p);
    pdf_end_obj(p);
}
示例#3
0
void write_pdfstream(PDF pdf, image_dict * idict)
{
    pdf_begin_obj(pdf, img_objnum(idict), OBJSTM_NEVER);
    pdf_begin_dict(pdf);
    if (!img_notype(idict)) {
        pdf_dict_add_name(pdf, "Type", "XObject");
        pdf_dict_add_name(pdf, "Subtype", "Form");
        pdf_dict_add_int(pdf, "FormType", 1);
    }
    if (!img_nobbox(idict)) {
        pdf_add_name(pdf, "BBox");
        pdf_begin_array(pdf);
        pdf_add_real(pdf, sp2bp(img_bbox(idict)[0]));
        pdf_add_real(pdf, sp2bp(img_bbox(idict)[1]));
        pdf_add_real(pdf, sp2bp(img_bbox(idict)[2]));
        pdf_add_real(pdf, sp2bp(img_bbox(idict)[3]));
        pdf_end_array(pdf);
    }
    if (img_attr(idict) != NULL && strlen(img_attr(idict)) > 0) {
        pdf_printf(pdf, "\n%s\n", img_attr(idict));
    }
    if (!img_nolength(idict)) {
        pdf_dict_add_streaminfo(pdf);
    }
    pdf_end_dict(pdf);
    pdf_begin_stream(pdf);
    if (img_pdfstream_stream(idict) != NULL) {
        pdf_out_block(pdf, (const char *) img_pdfstream_stream(idict), img_pdfstream_size(idict));
    }
    pdf_end_stream(pdf);
    pdf_end_obj(pdf);
}
示例#4
0
void
pdf_end_contents_section(PDF *p)
{
    long length;

    if (p->contents == c_none)
	return;

    pdf_end_text(p);
    p->contents = c_none;

    pdf_compress_end(p);
						/* Contents object */
    length = pdf_tell(p) - p->start_contents_pos;
    pdf_end_stream(p);
    pdf_end_obj(p);

    pdf_begin_obj(p, p->contents_length_id);	/* Length object */
    pdf_printf(p, "%ld\n", length);
    pdf_end_obj(p);
}
示例#5
0
/* Write all pending document information up to the xref table and trailer */
static void
pdf_wrapup_document(PDF *p)
{
    static const char bin2hex[] = PDF_STRING_0123456789ABCDEF;

    long	pos;
    id		i;
    id		pages_id;
    unsigned char digest[MD5_DIGEST_LENGTH];

    pdf_write_info(p);

    pdf_write_doc_fonts(p);			/* font objects */

    pdf_write_doc_colorspaces(p);		/* color space resources */

    pages_id = pdf_make_tree(p, BAD_ID, p->pnodes, p->pages+1, p->current_page);

    pdf_begin_obj(p, p->root_id);		/* Catalog or Root object */
    pdf_begin_dict(p);
    pdf_puts(p, "/Type/Catalog\n");

    /* 
     * specify the open action (display of the first page) 
     * default = retain: top of the first page at default zoom level
     */
    if (p->open_action == fitpage) {
	pdf_printf(p, "/OpenAction[%ld 0 R/Fit]\n", p->pages[1]);

    } else if (p->open_action == fitwidth) {
	pdf_printf(p, "/OpenAction[%ld 0 R/FitH]\n", p->pages[1]);

    } else if (p->open_action == fitheight) {
	pdf_printf(p, "/OpenAction[%ld 0 R/FitV 0]\n", p->pages[1]);

    } else if (p->open_action == fitbbox) {
	pdf_printf(p, "/OpenAction[%ld 0 R/FitB]\n", p->pages[1]);
    }

    /* 
     * specify the document's open mode
     * default = open_none: open document with neither bookmarks nor 
     * thumbnails visible
     */
    if (p->open_mode == open_bookmarks) {
	pdf_printf(p, "/PageMode/UseOutlines\n");

    } else if (p->open_mode == open_thumbnails) {
	pdf_printf(p, "/PageMode/UseThumbs\n");

    } else if (p->open_mode == open_fullscreen) {
	pdf_printf(p, "/PageMode/FullScreen\n");
    }

    if (p->base) {
	pdf_printf(p, "/URI<</Base", p->base);
        pdf_quote_string(p, p->base);
	pdf_printf(p, ">>\n", p->base);
    }
    						/* Pages object */
    pdf_printf(p, "/Pages %ld 0 R\n", pages_id);

    pdf_write_outline_root(p);

    pdf_end_dict(p);				/* Catalog */
    pdf_end_obj(p);

    pdf_write_outlines(p);

#ifdef DEBUG
    if (p->debug['s']) {
	fprintf(stderr, "PDF document statistics:\n");
	fprintf(stderr, "    %d pages\n", p->current_page);
	fprintf(stderr, "    %d fonts\n", p->fonts_number);
	fprintf(stderr, "    %d xobjects\n", p->xobjects_number);
	fprintf(stderr, "    %ld objects\n", p->currentobj + 1);
    }
#endif

    /* Don't write any object after this check! */
    for (i = 1; i <= p->currentobj; i++) {
	if (p->file_offset[i] == BAD_ID) {
	    pdf_error(p, PDF_NonfatalError,
		"Object %ld allocated but not used", i);
	    pdf_begin_obj(p, i);
	    pdf_end_obj(p);
	}
    }

    pos = pdf_tell(p);				/* xref table */
    pdf_puts(p, "xref\n");
    pdf_printf(p, "0 %ld\n", p->currentobj + 1);
    pdf_puts(p, "0000000000 65535 f \n");
    for (i = 1; i <= p->currentobj; i++) {
	pdf_printf(p, "%010ld 00000 n \n", p->file_offset[i]);
    }

    pdf_puts(p, "trailer\n");

    pdf_begin_dict(p);				/* trailer */
    pdf_printf(p, "/Size %ld\n", p->currentobj + 1);
    pdf_printf(p, "/Info %ld 0 R\n", p->info_id);
    pdf_printf(p, "/Root %ld 0 R\n", p->root_id);

    /* put some more data into the MD5 digest */
    MD5_Update(p->md5, (unsigned char *) &pos, sizeof pos);
    MD5_Update(p->md5, (unsigned char *) p, sizeof (PDF));
    if (p->filename && strcmp(p->filename, "-") != 0)
	MD5_Update(p->md5, (unsigned char *) p->filename, strlen(p->filename));

    /* write the digest to the ID array */
    MD5_Final(digest, p->md5);
    pdf_puts(p, "/ID[<");
    for (i = 0; i < MD5_DIGEST_LENGTH; ++i)
    {
	pdf_putc(p, bin2hex[digest[i] >> 4]);
	pdf_putc(p, bin2hex[digest[i] & 0x0F]);
    }
    pdf_puts(p, "><");
    for (i = 0; i < MD5_DIGEST_LENGTH; ++i)
    {
	pdf_putc(p, bin2hex[digest[i] >> 4]);
	pdf_putc(p, bin2hex[digest[i] & 0x0F]);
    }
    pdf_puts(p, ">]\n");

    pdf_end_dict(p);				/* trailer */

    pdf_puts(p, "startxref\n");
    pdf_printf(p, "%ld\n", pos);
    pdf_puts(p, "%%EOF\n");
}
示例#6
0
PDFLIB_API void PDFLIB_CALL
PDF_end_page(PDF *p)
{
    static const char fn[] = "PDF_end_page";
    int index;


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

    if (PDF_SANITY_CHECK_FAILED(p))
	return;

    PDF_CHECK_SCOPE(p, fn, pdf_state_page);

    /* check whether PDF_save() and PDF_restore() calls are balanced */
    if (p->sl > 0)
	pdf_error(p, PDF_RuntimeError, "Unmatched save level at end of page");


    /* restore text parameter and color defaults for out-of-page usage.
    */
    pdf_init_tstate(p);
    pdf_init_cstate(p);

    pdf_end_contents_section(p);

    /* Page object */
    pdf_begin_obj(p, p->pages[p->current_page]);

    pdf_begin_dict(p);
    pdf_puts(p, "/Type/Page\n");
    pdf_printf(p, "/Parent %ld 0 R\n", pdf_get_pnode_id(p));

    p->res_id = pdf_alloc_id(p);
    pdf_printf(p, "/Resources %ld 0 R\n", p->res_id);

    pdf_printf(p, "/MediaBox[0 0 %f %f]\n", p->width, p->height);

    if (p->CropBox.llx != (float) 0 || p->CropBox.lly != (float) 0 ||
        p->CropBox.urx != (float) 0 || p->CropBox.ury != (float) 0 )
    {
	if (p->CropBox.urx <= p->CropBox.llx ||
	    p->CropBox.ury <= p->CropBox.lly)
		pdf_error(p, PDF_ValueError, "Illegal CropBox dimensions");

	pdf_printf(p, "/CropBox[%f %f %f %f]\n",
	    p->CropBox.llx, p->CropBox.lly, p->CropBox.urx, p->CropBox.ury);
    }

    if (p->BleedBox.llx != (float) 0 || p->BleedBox.lly != (float) 0 ||
        p->BleedBox.urx != (float) 0 || p->BleedBox.ury != (float) 0 )
    {
	if (p->BleedBox.urx <= p->BleedBox.llx ||
	    p->BleedBox.ury <= p->BleedBox.lly)
		pdf_error(p, PDF_ValueError, "Illegal BleedBox dimensions");

	pdf_printf(p, "/BleedBox[%f %f %f %f]\n",
	    p->BleedBox.llx, p->BleedBox.lly, p->BleedBox.urx, p->BleedBox.ury);
    }

    if (p->TrimBox.llx != (float) 0 || p->TrimBox.lly != (float) 0 ||
        p->TrimBox.urx != (float) 0 || p->TrimBox.ury != (float) 0 )
    {
	if (p->TrimBox.urx <= p->TrimBox.llx ||
	    p->TrimBox.ury <= p->TrimBox.lly)
		pdf_error(p, PDF_ValueError, "Illegal TrimBox dimensions");

	pdf_printf(p, "/TrimBox[%f %f %f %f]\n",
	    p->TrimBox.llx, p->TrimBox.lly, p->TrimBox.urx, p->TrimBox.ury);
    }

    if (p->ArtBox.llx != (float) 0 || p->ArtBox.lly != (float) 0 ||
        p->ArtBox.urx != (float) 0 || p->ArtBox.ury != (float) 0 )
    {
	if (p->ArtBox.urx <= p->ArtBox.llx ||
	    p->ArtBox.ury <= p->ArtBox.lly)
		pdf_error(p, PDF_ValueError, "Illegal ArtBox dimensions");

	pdf_printf(p, "/ArtBox[%f %f %f %f]\n",
	    p->ArtBox.llx, p->ArtBox.lly, p->ArtBox.urx, p->ArtBox.ury);
    }

    /*
     * The duration can be placed in the transition dictionary (/D)
     * or in the page dictionary (/Dur). We put it here so it can
     * be used without setting a transition effect.
     */

    if (p->duration > 0)
	pdf_printf(p, "/Dur %f\n", p->duration);

    pdf_write_page_transition(p);

    pdf_puts(p, "/Contents[");
    for (index = 0; index < p->next_content; index++) {
	pdf_printf(p, "%ld 0 R", p->contents_ids[index]);
	pdf_putc(p, (char) (index + 1 % 8 ? PDF_SPACE : PDF_NEWLINE));
    }
    pdf_puts(p, "]\n");

    /* Thumbnail image */
    if (p->thumb_id != BAD_ID)
	pdf_printf(p, "/Thumb %ld 0 R\n", p->thumb_id);

    pdf_write_annots_root(p);

    pdf_end_dict(p);				/* Page object */
    pdf_end_obj(p);

    pdf_write_page_annots(p);			/* Annotation dicts */
    
    pdf_begin_obj(p, p->res_id);		/* resource object */
    pdf_begin_dict(p);				/* resource dict */

    pdf_write_page_procsets(p);			/* ProcSet resources */

    pdf_write_page_fonts(p);			/* Font resources */

    pdf_write_page_colorspaces(p);		/* Color space resources */

    pdf_write_page_pattern(p);			/* Pattern resources */

    pdf_write_xobjects(p);			/* XObject resources */

    pdf_end_dict(p);				/* resource dict */
    pdf_end_obj(p);				/* resource object */

    pdf_cleanup_page(p);

    PDF_SET_STATE(p, fn, pdf_state_document);

    if (p->flush & PDF_FLUSH_PAGE)
	pdf_flush_stream(p);
}
示例#7
0
static int l_immediateobj(lua_State * L)
{
    int n, first_arg = 1;
    int k;
    lstring buf;
    const_lstring st1,st2, st3;
    const char *st1_s = NULL;
    st1.s = st2.s = st3.s = NULL;
    check_o_mode(static_pdf, "immediateobj()", 1 << OMODE_PDF, true);
    if (global_shipping_mode != NOT_SHIPPING)
        luaL_error(L, "pdf.immediateobj() can not be used with \\latelua");
    n = lua_gettop(L);
    if ((n > 0) && (lua_type(L, 1) == LUA_TNUMBER)) {
        first_arg++;
        k = (int) lua_tointeger(L, 1);
        check_obj_type(static_pdf, obj_type_obj, k);
        if (is_obj_scheduled(static_pdf, k) || obj_data_ptr(static_pdf, k) != 0)
            luaL_error(L, "pdf.immediateobj() object in use");
    } else {
        static_pdf->obj_count++;
        k = pdf_create_obj(static_pdf, obj_type_obj, static_pdf->obj_ptr + 1);
    }
    pdf_last_obj = k;
    switch (n - first_arg + 1) {
        case 0:
            luaL_error(L, "pdf.immediateobj() needs at least one argument");
            break;
        case 1:
            if (!lua_isstring(L, first_arg)) /* or number */
                luaL_error(L, "pdf.immediateobj() 1st argument must be string");
            pdf_begin_obj(static_pdf, k, OBJSTM_ALWAYS);
            st1.s = lua_tolstring(L, first_arg, &st1.l);
            pdf_out_block(static_pdf, st1.s, st1.l);
            pdf_end_obj(static_pdf);
            break;
        case 2:
        case 3:
            if (lua_type(L,first_arg) != LUA_TSTRING)
                luaL_error(L, "pdf.immediateobj() 1st argument must be string");
            if (!lua_isstring(L, first_arg + 1)) /* or number */
                luaL_error(L, "pdf.immediateobj() 2nd argument must be string");
            st1_s = lua_tostring(L, first_arg);
            st2.s = lua_tolstring(L, first_arg + 1, &st2.l);
            if (lua_key_eq(st1_s, file)) {
                if (n == first_arg + 2)
                    luaL_error(L, "pdf.immediateobj() 3rd argument forbidden in file mode");
                pdf_begin_obj(static_pdf, k, OBJSTM_ALWAYS);
                buf.s = fread_to_buf(L, st2.s, &buf.l);
                pdf_out_block(static_pdf, (const char *) buf.s, buf.l);
                xfree(buf.s);
                pdf_end_obj(static_pdf);
            } else {
                pdf_begin_obj(static_pdf, k, OBJSTM_NEVER); /* not an object stream candidate! */
                pdf_begin_dict(static_pdf);
                if (n == first_arg + 2) {   /* write attr text */
                    if (!lua_isstring(L, first_arg + 2)) /* or number (maybe only string as it's an attr) */
                        luaL_error(L, "pdf.immediateobj() 3rd argument must be string");
                    st3.s = lua_tolstring(L, first_arg + 2, &st3.l);
                    pdf_out_block(static_pdf, st3.s, st3.l);
                    if (st3.s[st3.l - 1] != '\n')
                        pdf_out(static_pdf, '\n');
                }
                pdf_dict_add_streaminfo(static_pdf);
                pdf_end_dict(static_pdf);
                pdf_begin_stream(static_pdf);
                if (lua_key_eq(st1_s, stream)) {
                    pdf_out_block(static_pdf, st2.s, st2.l);
                }  else if (lua_key_eq(st1_s, streamfile)) {
                    buf.s = fread_to_buf(L, st2.s, &buf.l);
                    pdf_out_block(static_pdf, (const char *) buf.s, buf.l);
                    xfree(buf.s);
                } else
                    luaL_error(L, "pdf.immediateobj() invalid argument");
                pdf_end_stream(static_pdf);
                pdf_end_obj(static_pdf);
            }
            break;
        default:
            luaL_error(L, "pdf.immediateobj() allows max. 3 arguments");
    }
    lua_pushinteger(L, k);
    return 1;
}
示例#8
0
static int table_obj(lua_State * L)
{
    const char *type;
    int k, obj_compression;
    int compress_level = -1;    /* unset */
    int os_threshold = OBJSTM_ALWAYS;   /* default: put non-stream objects into object streams */
    int saved_compress_level = static_pdf->compress_level;
    const_lstring attr, st;
    lstring buf;
    int immediate = 0;          /* default: not immediate */
    attr.s = st.s = NULL;
    attr.l = 0;
    assert(lua_istable(L, 1));  /* t */
    lua_key_rawgeti(type);
    if (lua_isnil(L, -1))       /* !vs t */
        luaL_error(L, "pdf.obj(): object \"type\" missing");
    if (lua_type(L,-1) != LUA_TSTRING)   /* !vs t */
        luaL_error(L, "pdf.obj(): object \"type\" must be string");
    type = lua_tostring(L, -1);
    if (! (lua_key_eq(type, raw) || lua_key_eq(type, stream))) {
        luaL_error(L, "pdf.obj(): \"%s\" is not a valid object type", type);     /* i vs t */
    }
    lua_pop(L, 1);              /* t */
    lua_key_rawgeti(immediate);
    if (!lua_isnil(L, -1)) {    /* b? t */
        if (!lua_isboolean(L, -1))      /* !b t */
            luaL_error(L, "pdf.obj(): \"immediate\" must be boolean");
        immediate = lua_toboolean(L, -1);       /* 0 or 1 */
    }
    lua_pop(L, 1);              /* t */

    /* is a reserved object referenced by "objnum"? */

    lua_key_rawgeti(objnum);
    if (!lua_isnil(L, -1)) {    /* vi? t */
        if (lua_type(L,-1) != LUA_TNUMBER)       /* !vi t */
            luaL_error(L, "pdf.obj(): \"objnum\" must be integer");
        k = (int) lua_tointeger(L, -1); /* vi t */
        check_obj_type(static_pdf, obj_type_obj, k);
        if (is_obj_scheduled(static_pdf, k) || obj_data_ptr(static_pdf, k) != 0)
            luaL_error(L, "pdf.obj() object in use");
    } else {
        static_pdf->obj_count++;
        k = pdf_create_obj(static_pdf, obj_type_obj, static_pdf->obj_ptr + 1);
    }
    pdf_last_obj = k;
    if (immediate == 0) {
        obj_data_ptr(static_pdf, k) = pdf_get_mem(static_pdf, pdfmem_obj_size);
        init_obj_obj(static_pdf, k);
    }
    lua_pop(L, 1);              /* t */

    /* get optional "attr" (allowed only for stream case) */

    lua_key_rawgeti(attr);
    if (!lua_isnil(L, -1)) {    /* attr-s? t */
        if (! lua_key_eq(type, stream))
            luaL_error(L, "pdf.obj(): \"attr\" key not allowed for non-stream object");
        if (!lua_isstring(L, -1)) /* or number */      /* !attr-s t */
            luaL_error(L, "pdf.obj(): object \"attr\" must be string");
        if (immediate == 1) {
            attr.s = lua_tolstring(L, -1, &attr.l);     /* attr-s t */
            lua_pop(L, 1);      /* t */
        } else
            obj_obj_stream_attr(static_pdf, k) = luaL_ref(Luas, LUA_REGISTRYINDEX);     /* t */
    } else {
        lua_pop(L, 1);          /* t */
    }

    /* get optional "compresslevel" (allowed only for stream case) */

    lua_key_rawgeti(compresslevel);
    if (!lua_isnil(L, -1)) {    /* vi? t */
        if (lua_key_eq(type, raw))
            luaL_error(L, "pdf.obj(): \"compresslevel\" key not allowed for raw object");
        if (lua_type(L, -1) != LUA_TNUMBER)       /* !vi t */
            luaL_error(L, "pdf.obj(): \"compresslevel\" must be integer");
        compress_level = (int) lua_tointeger(L, -1);    /* vi t */
        if (compress_level > 9)
            luaL_error(L, "pdf.obj(): \"compresslevel\" must be <= 9");
        else if (compress_level < 0)
            luaL_error(L, "pdf.obj(): \"compresslevel\" must be >= 0");
        if (immediate == 0)
            obj_obj_pdfcompresslevel(static_pdf, k) = compress_level;
    }
    lua_pop(L, 1);              /* t */

    /* get optional "objcompression" (allowed only for non-stream case) */

    lua_key_rawgeti(objcompression);
    if (!lua_isnil(L, -1)) {    /* b? t */
        if (lua_key_eq(type, stream))
            luaL_error(L, "pdf.obj(): \"objcompression\" key not allowed for stream object");
        if (!lua_isboolean(L, -1))      /* !b t */
            luaL_error(L, "pdf.obj(): \"objcompression\" must be boolean");
        obj_compression = lua_toboolean(L, -1); /* 0 or 1 */
        /* OBJSTM_NEVER: never into object stream; OBJSTM_ALWAYS: depends then on \pdfobjcompresslevel */
        if (obj_compression > 0)
            os_threshold = OBJSTM_ALWAYS;
        else
            os_threshold = OBJSTM_NEVER;
        if (immediate == 0)
            obj_obj_objstm_threshold(static_pdf, k) = os_threshold;
    }
    lua_pop(L, 1);              /* t */

    /* now the object contents for all cases are handled */

    lua_key_rawgeti(string);
    lua_key_rawgeti_n(file,-2);

    if (!lua_isnil(L, -1) && !lua_isnil(L, -2)) /* file-s? string-s? t */
        luaL_error(L, "pdf.obj(): \"string\" and \"file\" must not be given together");
    if (lua_isnil(L, -1) && lua_isnil(L, -2))   /* nil nil t */
        luaL_error(L, "pdf.obj(): no \"string\" or \"file\" given");

    if (lua_key_eq(type, raw)) {
        if (immediate == 1)
            pdf_begin_obj(static_pdf, k, os_threshold);
        if (!lua_isnil(L, -2)) {        /* file-s? string-s? t */
            /* from string */
            lua_pop(L, 1);      /* string-s? t */
            if (!lua_isstring(L, -1)) /* or number */   /* !string-s t */
                luaL_error(L, "pdf.obj(): \"string\" must be string for raw object");
            if (immediate == 1) {
                st.s = lua_tolstring(L, -1, &st.l);
                pdf_out_block(static_pdf, st.s, st.l);
            } else
                obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX);   /* t */
        } else {
            /* from file */
            if (lua_type(L, -1) != LUA_TSTRING)   /* !file-s nil t */
                luaL_error(L, "pdf.obj(): \"file\" name must be string for raw object");
            if (immediate == 1) {
                st.s = lua_tolstring(L, -1, &st.l);     /* file-s nil t */
                buf.s = fread_to_buf(L, st.s, &buf.l);
                pdf_out_block(static_pdf, (const char *) buf.s, buf.l);
                /* already in pdf_end_obj:
                    if (buf.s[buf.l - 1] != '\n')
                        pdf_out(static_pdf, '\n');
                */
                xfree(buf.s);
            } else {
                set_obj_obj_is_file(static_pdf, k);
                obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX);   /* nil t */
            }
        }
        if (immediate == 1)
            pdf_end_obj(static_pdf);
    } else {
        if (immediate == 1) {
            pdf_begin_obj(static_pdf, k, OBJSTM_NEVER); /* 0 = not an object stream candidate! */
            pdf_begin_dict(static_pdf);
            if (attr.s != NULL) {
                pdf_out_block(static_pdf, attr.s, attr.l);
                if (attr.s[attr.l - 1] != '\n')
                    pdf_out(static_pdf, '\n');
            }
            if (compress_level > -1)
                static_pdf->compress_level = compress_level;
            pdf_dict_add_streaminfo(static_pdf);
            pdf_end_dict(static_pdf);
            pdf_begin_stream(static_pdf);
        } else {
            set_obj_obj_is_stream(static_pdf, k);
            if (compress_level > -1)
                obj_obj_pdfcompresslevel(static_pdf, k) = compress_level;
        }
        if (!lua_isnil(L, -2)) {        /* file-s? string-s? t */
            /* from string */
            lua_pop(L, 1);      /* string-s? t */
            if (!lua_isstring(L, -1)) /* or number */  /* !string-s t */
                luaL_error(L, "pdf.obj(): \"string\" must be string for stream object");
            if (immediate == 1) {
                st.s = lua_tolstring(L, -1, &st.l);     /* string-s t */
                pdf_out_block(static_pdf, st.s, st.l);
            } else
                obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX);   /* t */
        } else {
            /* from file */
            if (lua_type(L, -1) != LUA_TSTRING)   /* !file-s nil t */
                luaL_error(L, "pdf.obj(): \"file\" name must be string for stream object");
            if (immediate == 1) {
                st.s = lua_tolstring(L, -1, &st.l);     /* file-s nil t */
                buf.s = fread_to_buf(L, st.s, &buf.l);
                pdf_out_block(static_pdf, (const char *) buf.s, buf.l);
                xfree(buf.s);
            } else {
                set_obj_obj_is_file(static_pdf, k);
                obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX);   /* nil t */
            }
        }
        if (immediate == 1) {
            pdf_end_stream(static_pdf);
            pdf_end_obj(static_pdf);
        }
    }
    static_pdf->compress_level = saved_compress_level;
    return k;
}
示例#9
0
void
pdf_write_page_annots(PDF *p)
{
    pdf_annot	*ann;
    long	length, start_pos;
    id		length_id;
    PDF_data_source src;

    for (ann = p->annots; ann != NULL; ann = ann->next) {
	pdf_begin_obj(p, ann->obj_id);	/* Annotation object */
	pdf_begin_dict(p);		/* Annotation dict */

	pdf_puts(p, "/Type/Annot\n");
	switch (ann->type) {
	    case ann_text:
		pdf_puts(p, "/Subtype/Text\n");
		pdf_printf(p, "/Rect[%f %f %f %f]\n", 
		    ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury);

		pdf_write_border_style(p, ann);

		if (ann->open)
		    pdf_puts(p, "/Open true\n");

		if (ann->icon != icon_text_note)	/* note is default */
		    pdf_printf(p, "/Name/%s\n", pdf_icon_names[ann->icon]);

		/* Contents key is required, but may be empty */
		pdf_puts(p, "/Contents");

		if (ann->contents) {
		    pdf_quote_string(p, ann->contents);
		    pdf_putc(p, PDF_NEWLINE);
		} else
		    pdf_puts(p, "()\n"); /* empty contents is OK */

		/* title is optional */
		if (ann->title) {
		    pdf_puts(p, "/T");
		    pdf_quote_string(p, ann->title);
		    pdf_putc(p, PDF_NEWLINE);
		}

		break;

	    case ann_locallink:
		pdf_puts(p, "/Subtype/Link\n");
		pdf_printf(p, "/Rect[%f %f %f %f]\n", 
		    ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury);

		pdf_write_border_style(p, ann);

		/* preallocate page object id for a later page */
		if (ann->dest.page > p->current_page) {
		    while (ann->dest.page >= p->pages_capacity)
			pdf_grow_pages(p);

		    /* if this page has already been used as a link target
		     * it will already have an object id.
		     */
		    if (p->pages[ann->dest.page] == BAD_ID)
			p->pages[ann->dest.page] = pdf_alloc_id(p);
		}

		if (ann->dest.type == retain) {
		    pdf_printf(p, "/Dest[%ld 0 R/XYZ null null 0]\n",
			    p->pages[ann->dest.page]);
		} else if (ann->dest.type == fitpage) {
		    pdf_printf(p, "/Dest[%ld 0 R/Fit]\n",
			    p->pages[ann->dest.page]);
		} else if (ann->dest.type == fitwidth) {
		    pdf_printf(p, "/Dest[%ld 0 R/FitH 0]\n",
			    p->pages[ann->dest.page]);
		} else if (ann->dest.type == fitheight) {
		    pdf_printf(p, "/Dest[%ld 0 R/FitV 0]\n",
			    p->pages[ann->dest.page]);
		} else if (ann->dest.type == fitbbox) {
		    pdf_printf(p, "/Dest[%ld 0 R/FitB]\n",
			    p->pages[ann->dest.page]);
		}

		break;

	    case ann_pdflink:
		pdf_puts(p, "/Subtype/Link\n");
		pdf_printf(p, "/Rect[%f %f %f %f]\n", 
		    ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury);

		pdf_write_border_style(p, ann);

		pdf_puts(p, "/A");
		pdf_begin_dict(p);			/* A dict */
		pdf_puts(p, "/Type/Action/S/GoToR\n");

		if (ann->dest.type == retain) {
		    pdf_printf(p, "/D[%d 0 R/XYZ null null 0]\n",
			    ann->dest.page-1);	/* zero-based */
		} else if (ann->dest.type == fitpage) {
		    /* zero-based */
		    pdf_printf(p, "/D[%d 0 R/Fit]\n", ann->dest.page-1);
		} else if (ann->dest.type == fitwidth) {
		    /* Trick: we don't know the height of a future page yet,
		     * so we use a "large" value for top which will do for
		     * most pages. If it doesn't work, not much harm is done.
		     */
		    /* zero-based */
		    pdf_printf(p, "/D[%d 0 R/FitH 2000]\n", ann->dest.page-1);
		} else if (ann->dest.type == fitheight) {
		    /* zero-based */
		    pdf_printf(p, "/D[%d 0 R/FitV 0]\n", ann->dest.page-1);
		} else if (ann->dest.type == fitbbox) {
		    /* zero-based */
		    pdf_printf(p, "/D[%d 0 R/FitB]\n", ann->dest.page-1);
		}

		pdf_puts(p, "/F");
		pdf_begin_dict(p);			/* F dict */
		pdf_puts(p, "/Type/FileSpec\n");
		pdf_printf(p, "/F(");
		pdf_puts(p, ann->filename);
		pdf_puts(p,")\n");
		pdf_end_dict(p);			/* F dict */

		pdf_end_dict(p);			/* A dict */

		break;

	    case ann_launchlink:
		pdf_puts(p, "/Subtype/Link\n");
		pdf_printf(p, "/Rect[%f %f %f %f]\n", 
		    ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury);

		pdf_write_border_style(p, ann);

		pdf_puts(p, "/A");
		pdf_begin_dict(p);			/* A dict */
		pdf_puts(p, "/Type/Action/S/Launch\n");

		pdf_puts(p, "/F");
		pdf_begin_dict(p);			/* F dict */
		pdf_puts(p, "/Type/FileSpec\n");
		pdf_printf(p, "/F(");
		pdf_puts(p, ann->filename);
		pdf_puts(p,")\n");
		pdf_end_dict(p);			/* F dict */

		pdf_end_dict(p);			/* A dict */

		break;

	    case ann_weblink:
		pdf_puts(p, "/Subtype/Link\n");
		pdf_printf(p, "/Rect[%f %f %f %f]\n", 
		    ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury);

		pdf_write_border_style(p, ann);

		pdf_printf(p, "/A<</S/URI/URI(");
		pdf_puts(p, ann->filename);
		pdf_puts(p, ")>>\n");
		break;

	    case ann_attach:
		pdf_puts(p, "/Subtype/FileAttachment\n");
		pdf_printf(p, "/Rect[%f %f %f %f]\n", 
		    ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury);

		pdf_write_border_style(p, ann);

		if (ann->icon != icon_file_pushpin)	/* pushpin is default */
		    pdf_printf(p, "/Name/%s\n",
		    	pdf_icon_names[ann->icon]);

		if (ann->title) {
		    pdf_puts(p, "/T");
		    pdf_quote_string(p, ann->title);
		    pdf_putc(p, PDF_NEWLINE);
		}

		if (ann->contents) {
		    pdf_puts(p, "/Contents");
		    pdf_quote_string(p, ann->contents);
		    pdf_putc(p, PDF_NEWLINE);
		}
		    
		/* the icon is too small without these flags (=28) */
		pdf_printf(p, "/F %d\n",
			pdf_ann_flag_print |
			pdf_ann_flag_nozoom | 
			pdf_ann_flag_norotate);

		pdf_puts(p, "/FS");
		pdf_begin_dict(p);			/* FS dict */
		pdf_puts(p, "/Type/FileSpec\n");

		pdf_printf(p, "/F(");
		pdf_puts(p, ann->filename);
		pdf_puts(p, ")\n");

		/* alloc id for the actual embedded file stream */
		ann->obj_id = pdf_alloc_id(p);
		pdf_printf(p, "/EF<</F %ld 0 R>>\n", ann->obj_id);
		pdf_end_dict(p);			/* FS dict */

		break;

	    default:
		pdf_error(p, PDF_SystemError, "Unknown annotation type %d",
				ann->type);
	}

	pdf_end_dict(p);		/* Annotation dict */
	pdf_end_obj(p);			/* Annotation object */
    }

    /* Write the actual embedded files with preallocated ids */
    for (ann = p->annots; ann != NULL; ann = ann->next) {
	if (ann->type != ann_attach)
	    continue;

	pdf_begin_obj(p, ann->obj_id);	/* EmbeddedFile */
	pdf_puts(p, "<</Type/EmbeddedFile\n");

	if (ann->mimetype)
	    pdf_printf(p, "/Subtype (%s)\n", ann->mimetype);

	if (p->compresslevel)
	    pdf_puts(p, "/Filter/FlateDecode\n");

	length_id = pdf_alloc_id(p);
	pdf_printf(p, "/Length %ld 0 R\n", length_id);
	pdf_end_dict(p);		/* F dict */

	pdf_begin_stream(p);		/* Embedded file stream */
	start_pos = pdf_tell(p);

	/* write the file in the PDF */
	src.private_data = (void *) ann->filename;
	src.init	= pdf_data_source_file_init;
	src.fill	= pdf_data_source_file_fill;
	src.terminate	= pdf_data_source_file_terminate;
	src.length	= (long) 0;
	src.offset	= (long) 0;

	pdf_compress(p, &src);

	length = pdf_tell(p) - start_pos;
	pdf_end_stream(p);		/* Embedded file stream */
	pdf_end_obj(p);			/* EmbeddedFile object */

	pdf_begin_obj(p, length_id);	/* Length object */
	pdf_printf(p, "%ld\n", length);
	pdf_end_obj(p);			/* Length object */

	if (p->flush & PDF_FLUSH_CONTENT)
	    pdf_flush_stream(p);
    }
}
示例#10
0
void
pdf_write_doc_colorspaces(PDF *p)
{
    int i;

    pdf_csresource *cs;

    for (i = 0; i < p->colorspaces_number; i++) {
        cs = &p->colorspaces[i];

        pdf_begin_obj(p, cs->obj_id);		/* color space resource */

        /* Separation color space, or pattern based on separation */
        if (cs->cs == Separation ||
                (cs->cs == PatternCS && cs->alternate.cs == Separation)) {
            const char *name;

            if (cs->cs == PatternCS) {
                pdf_printf(p, "[/Pattern");	/* pattern color space */
                name = p->colorspaces[cs->alternate.val.sep.cs].name;
            } else
                name = cs->name;

            pdf_puts(p, "[/Separation/");
            pdf_puts(p, name);		/* this is already quoted */
            pdf_puts(p, "\n");

            if (cs->alternate.cs == DeviceGray) {
                pdf_puts(p, "/DeviceGray<<\n");
                pdf_puts(p, "/Range[0 1]\n");
                pdf_printf(p, "/C0[0]\n");
                pdf_printf(p, "/C1[%f]\n", cs->alternate.val.gray);

            } else if (cs->alternate.cs == DeviceRGB) {
                pdf_puts(p, "/DeviceRGB<<\n");
                pdf_puts(p, "/Range[0 1 0 1 0 1]\n");
                pdf_printf(p, "/C0[0 0 0]\n");
                pdf_printf(p, "/C1[%f %f %f]\n", cs->alternate.val.rgb.r,
                           cs->alternate.val.rgb.g, cs->alternate.val.rgb.b);

            } else if (cs->alternate.cs == DeviceCMYK) {
                pdf_puts(p, "/DeviceCMYK<<\n");
                pdf_puts(p, "/Range[0 1 0 1 0 1 0 1]\n");
                pdf_printf(p, "/C0[0 0 0 0]\n");
                pdf_printf(p, "/C1[%f %f %f %f]\n",
                           cs->alternate.val.cmyk.c, cs->alternate.val.cmyk.m,
                           cs->alternate.val.cmyk.y, cs->alternate.val.cmyk.k);

            } else if (cs->alternate.cs != Separation)
                pdf_error(p, PDF_SystemError,
                          "Unknown alternate color space in pdf_write_doc_colorspaces");

            pdf_puts(p, "/FunctionType 2\n");
            pdf_puts(p, "/Domain[0 1]\n");
            pdf_puts(p, "/N 1\n");

            pdf_end_dict(p);		/* alternate color space */
            pdf_puts(p, "]\n");		/* separation color space */

            if (cs->cs == PatternCS)
                pdf_puts(p, "]\n");	/* pattern color space */

            /* Pattern color space based on simple color space */
        } else if (cs->cs == PatternCS) {
            pdf_printf(p, "[/Pattern/%s]\n",
                       pdf_colorspace_names[cs->alternate.cs]);

        } else {
            pdf_error(p, PDF_SystemError,
                      "Unknown base or alternate color space in pdf_write_doc_colorspaces");
        }

        pdf_end_obj(p);			/* color space resource */
    }
}
示例#11
0
void
pdf_put_image(PDF *p, int im, pdf_bool firststrip)
{
    id		length_id;
    long	length;
    pdf_image	*image;
    int		i;

    image = &p->images[im];

    /* york: how to check? see also F-imagecolor!
    switch (image->colorspace) {
        case ImageMask:
        case DeviceGray:
        case Indexed:
        case DeviceRGB:
        case DeviceCMYK:
	    break;

	default:
	    pdf_error(p, PDF_SystemError, "Unknown color space");
	    break;
    }
    */

    /* Images may also be written to the output before the first page */
    if (PDF_GET_STATE(p) == pdf_state_page)
	pdf_end_contents_section(p);

    /* Image object */

    image->no = pdf_new_xobject(p, image_xobject, NEW_ID);

    pdf_begin_dict(p); 		/* XObject */

    pdf_puts(p, "/Type/XObject\n");
    pdf_puts(p, "/Subtype/Image\n");

    pdf_printf(p,"/Width %d\n", (int) image->width);
    pdf_printf(p,"/Height %d\n", (int) image->height);
    pdf_printf(p,"/BitsPerComponent %d\n", image->bpc);

    /* 
     * Transparency handling
     */

    /* Masking by color: single transparent color value */
    if (image->transparent) {
	if (image->colorspace == Indexed || image->colorspace == DeviceGray)
	    pdf_printf(p,"/Mask[%d %d]\n",
		(int) image->transval[0], (int) image->transval[0]);

	else if (image->colorspace == DeviceRGB)
	    pdf_printf(p,"/Mask[%d %d %d %d %d %d]\n",
		(int) image->transval[0], (int) image->transval[0],
		(int) image->transval[1], (int) image->transval[1],
		(int) image->transval[2], (int) image->transval[2]);

	else if (image->colorspace == DeviceCMYK)
	    pdf_printf(p,"/Mask[%d %d %d %d %d %d %d %d]\n",
		(int) image->transval[0], (int) image->transval[0],
		(int) image->transval[1], (int) image->transval[1],
		(int) image->transval[2], (int) image->transval[2],
		(int) image->transval[3], (int) image->transval[3]);
	else
	    pdf_error(p, PDF_SystemError,
	    	"Unknown color space with transparency");

    /* Masking by position: separate bitmap mask */
    } else if (image->mask != -1) {
	pdf_printf(p, "/Mask %ld 0 R\n",
	    p->xobjects[p->images[image->mask].no].obj_id);
    }

    switch (image->colorspace) {
	case ImageMask:
	    pdf_puts(p, "/ImageMask true\n");
	    break;

	case Indexed:
	    if (firststrip)
		image->colormap_id = pdf_alloc_id(p);

	    pdf_puts(p, "/ColorSpace[/Indexed/DeviceRGB ");
	    pdf_printf(p, "%d %ld 0 R]\n", image->palette_size - 1,
	    	image->colormap_id);
	    break;
	
	default:
            /* colorize the image with a spot color */
            if (image->colorspace >= LastCS) {
                /* TODO: reconsider spot color numbering scheme */
                int spot = image->colorspace - LastCS;
                p->colorspaces[spot].used_on_current_page = pdf_true;
                pdf_printf(p, "/ColorSpace %ld 0 R\n",
                    p->colorspaces[spot].obj_id);

                /* the following is tricky: /Separation color space
                 * always works as a subtractive color space. The
                 * image, however, is Grayscale, and therefore
                 * additive.
                 */
                if (firststrip) {
                    image->invert = !image->invert;
                }
            } else {
                pdf_printf(p, "/ColorSpace/%s\n",
                    pdf_colorspace_names[image->colorspace]);
            }
	    break;
    }

    /* special case: referenced image data instead of direct data */
    if (image->reference != pdf_ref_direct) {

	if (image->compression != none) {
	    pdf_printf(p, "/FFilter[/%s]\n",
		    pdf_filter_names[image->compression]);
	}

	if (image->compression == ccitt) {
	    pdf_puts(p, "/FDecodeParms[<<");

	    if ((int) image->width != 1728)	/* CCITT default width */
		pdf_printf(p, "/Columns %d", (int) image->width);

	    pdf_printf(p, "/Rows %d", (int) image->height);

	    /* write CCITT parameters if required */
	    if (image->params)
		pdf_puts(p, image->params);

	    pdf_puts(p, ">>]\n");

	}

	if (image->reference == pdf_ref_file) {

	    /* LATER: make image file name platform-neutral:
	     * Change : to / on the Mac
	     * Change \ to / on Windows
	     */
	    pdf_printf(p, "/F(%s)/Length 0", image->filename);

	} else if (image->reference == pdf_ref_url) {

	    pdf_printf(p, "/F<</FS/URL/F(%s)>>/Length 0", image->filename);
	}

	pdf_end_dict(p);		/* XObject */

	pdf_begin_stream(p);		/* dummy image data */
	pdf_end_stream(p);		/* dummy image data */

	if (PDF_GET_STATE(p) == pdf_state_page)
	    pdf_begin_contents_section(p);

	pdf_end_obj(p);			/* XObject */

	return;
    }

    /* 
     * Now the (more common) handling of actual image
     * data to be included in the PDF output.
     */
    /* do we need a filter (either ASCII or decompression)? */

    if (p->debug['a']) {
	pdf_puts(p, "/Filter[/ASCIIHexDecode");
	if (image->compression != none)
	    pdf_printf(p, "/%s", pdf_filter_names[image->compression]);
	pdf_puts(p, "]\n");

    } else {
	/* force compression if not a recognized precompressed image format */
	if (!image->use_raw && p->compresslevel)
	    image->compression = flate;

	if (image->compression != none)
	    pdf_printf(p, "/Filter[/%s]\n",
		    pdf_filter_names[image->compression]);
    }

    /* prepare precompressed (raw) image data */
    if (image->use_raw) {
	pdf_printf(p, "/DecodeParms[%s<<", (p->debug['a'] ? "null" : ""));

	/* write EarlyChange or CCITT parameters if required */
	if (image->params)
	    pdf_puts(p, image->params);

	if (image->compression == flate || image->compression == lzw) {
	    if (image->predictor != pred_default) {
		pdf_printf(p, "/Predictor %d", (int) image->predictor);
		pdf_printf(p, "/Columns %d", (int) image->width);
		if (image->bpc != 8)
		    pdf_printf(p, "/BitsPerComponent %d", image->bpc);

		if (image->colorspace < LastCS) {
		    switch (image->colorspace) {
			case Indexed:
			case ImageMask:
			case DeviceGray:
			    /* 1 is default */
			    break;
			case DeviceRGB:
			    pdf_puts(p, "/Colors 3");
			    break;
			case DeviceCMYK:
			    pdf_puts(p, "/Colors 4");
			    break;
			default:
			    pdf_error(p, PDF_SystemError,
			"Unknown colorspace (%d)", (int )image->colorspace);
			    break;
		    }
		}
	    }
	}

	if (image->compression == ccitt) {
	    if ((int) image->width != 1728)	/* CCITT default width */
		pdf_printf(p, "/Columns %d", (int) image->width);

	    pdf_printf(p, "/Rows %d", (int) image->height);
	}
	pdf_puts(p, ">>]\n");		/* DecodeParms dict and array */
    }

    if (image->invert) {
	pdf_puts(p, "/Decode[1 0");
	for (i = 1; i < image->components; i++)
	    pdf_puts(p, " 1 0");
	pdf_puts(p, "]\n");
    }

    /* Write the actual image data */
    length_id = pdf_alloc_id(p);

    pdf_printf(p,"/Length %ld 0 R\n", length_id);
    pdf_end_dict(p);		/* XObject */

    pdf_begin_stream(p);	/* image data */
    p->start_contents_pos = pdf_tell(p);

    /* image data */

    if (p->debug['a'])
	pdf_ASCIIHexEncode(p, &image->src);
    else {
	if (image->use_raw)
	    pdf_copy(p, &image->src);
	else
	    pdf_compress(p, &image->src);
    }

    length = pdf_tell(p) - p->start_contents_pos;

    pdf_end_stream(p);	/* image data */
    pdf_end_obj(p);	/* XObject */

    pdf_begin_obj(p, length_id);		/* Length object */
    pdf_printf(p,"%ld\n", length);
    pdf_end_obj(p);

    if (p->flush & PDF_FLUSH_CONTENT)
	pdf_flush_stream(p);

    /* Image data done */

    /*
     * Write colormap information for indexed color spaces
     */
    if (firststrip && image->colorspace == Indexed) {
	pdf_begin_obj(p, image->colormap_id);		/* colormap object */
	pdf_begin_dict(p); 		

	if (p->debug['a'])
	    pdf_puts(p, "/Filter[/ASCIIHexDecode]\n");
	else if (p->compresslevel)
	    pdf_puts(p, "/Filter[/FlateDecode]\n");

	/* Length of colormap object */
	length_id = pdf_alloc_id(p);
	pdf_printf(p,"/Length %ld 0 R\n", length_id);
	pdf_end_dict(p);

	pdf_begin_stream(p);			/* colormap data */
	p->start_contents_pos = pdf_tell(p);

	if (image->components != 1) {
	    pdf_error(p, PDF_SystemError,
	    	"Bogus indexed colorspace (%d color components)",
		image->components);
	}

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

	image->src.buffer_start	= (unsigned char *) image->colormap;
	image->src.buffer_length= (size_t) (image->palette_size * 3);

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

	/* Write colormap data */
	if (p->debug['a'])
	    pdf_ASCIIHexEncode(p, &image->src);
	else {
	    pdf_compress(p, &image->src);
	}

	length = pdf_tell(p) - p->start_contents_pos;

	pdf_end_stream(p);			/* Colormap data */
	pdf_end_obj(p);				/* Colormap object */

	pdf_begin_obj(p, length_id);		/* Length object for colormap */
	pdf_printf(p, "%ld\n", length);
	pdf_end_obj(p);				/* Length object for colormap */
    }

    if (PDF_GET_STATE(p) == pdf_state_page)
	pdf_begin_contents_section(p);

    if (p->flush & PDF_FLUSH_CONTENT)
	pdf_flush_stream(p);
}