Esempio n. 1
0
/*
 * Create an Indexed color space.  This is a single-use procedure,
 * broken out only for readability.
 */
static int
pdf_indexed_color_space(gx_device_pdf *pdev, cos_value_t *pvalue,
			const gs_color_space *pcs, cos_array_t *pca)
{
    const gs_indexed_params *pip = &pcs->params.indexed;
    const gs_color_space *base_space = pcs->base_space;
    int num_entries = pip->hival + 1;
    int num_components = gs_color_space_num_components(base_space);
    uint table_size = num_entries * num_components;
    /* Guess at the extra space needed for PS string encoding. */
    uint string_size = 2 + table_size * 4;
    uint string_used;
    byte buf[100];		/* arbitrary */
    stream_AXE_state st;
    stream s, es;
    gs_memory_t *mem = pdev->pdf_memory;
    byte *table;
    byte *palette;
    cos_value_t v;
    int code;

    /* PDF doesn't support Indexed color spaces with more than 256 entries. */
    if (num_entries > 256)
	return_error(gs_error_rangecheck);
    if (pdev->CompatibilityLevel < 1.3) {
	switch (gs_color_space_get_index(pcs)) {
	    case gs_color_space_index_Pattern:
	    case gs_color_space_index_Separation:
	    case gs_color_space_index_Indexed:
	    case gs_color_space_index_DeviceN:
		return_error(gs_error_rangecheck);
	    default: DO_NOTHING; 
	}

    }
    table = gs_alloc_string(mem, string_size, "pdf_color_space(table)");
    palette = gs_alloc_string(mem, table_size, "pdf_color_space(palette)");
    if (table == 0 || palette == 0) {
	gs_free_string(mem, palette, table_size,
		       "pdf_color_space(palette)");
	gs_free_string(mem, table, string_size,
		       "pdf_color_space(table)");
	return_error(gs_error_VMerror);
    }
    s_init(&s, mem);
    swrite_string(&s, table, string_size);
    s_init(&es, mem);
    s_init_state((stream_state *)&st, &s_PSSE_template, NULL);
    s_init_filter(&es, (stream_state *)&st, buf, sizeof(buf), &s);
    sputc(&s, '(');
    if (pcs->params.indexed.use_proc) {
	gs_client_color cmin, cmax;
	byte *pnext = palette;
	int i, j;

	/* Find the legal range for the color components. */
	for (j = 0; j < num_components; ++j)
	    cmin.paint.values[j] = (float)min_long,
		cmax.paint.values[j] = (float)max_long;
	gs_color_space_restrict_color(&cmin, base_space);
	gs_color_space_restrict_color(&cmax, base_space);
	/*
	 * Compute the palette values, with the legal range for each
	 * one mapped to [0 .. 255].
	 */
	for (i = 0; i < num_entries; ++i) {
	    gs_client_color cc;

	    gs_cspace_indexed_lookup(pcs, i, &cc);
	    for (j = 0; j < num_components; ++j) {
		float v = (cc.paint.values[j] - cmin.paint.values[j])
		    * 255 / (cmax.paint.values[j] - cmin.paint.values[j]);

		*pnext++ = (v <= 0 ? 0 : v >= 255 ? 255 : (byte)v);
	    }
	}
    } else
	memcpy(palette, pip->lookup.table.data, table_size);
    if (gs_color_space_get_index(base_space) ==
	gs_color_space_index_DeviceRGB
	) {
	/* Check for an all-gray palette3. */
	int i;

	for (i = table_size; (i -= 3) >= 0; )
	    if (palette[i] != palette[i + 1] ||
		palette[i] != palette[i + 2]
		)
		break;
	if (i < 0) {
	    /* Change the color space to DeviceGray. */
	    for (i = 0; i < num_entries; ++i)
		palette[i] = palette[i * 3];
	    table_size = num_entries;
	    base_space = gs_cspace_new_DeviceGray(mem);
	}
    }
    stream_write(&es, palette, table_size);
    gs_free_string(mem, palette, table_size, "pdf_color_space(palette)");
    sclose(&es);
    sflush(&s);
    string_used = (uint)stell(&s);
    table = gs_resize_string(mem, table, string_size, string_used,
			     "pdf_color_space(table)");
    /*
     * Since the array is always referenced by name as a resource
     * rather than being written as a value, even for in-line images,
     * always use the full name for the color space.
     *
     * We don't have to worry about the range of the base space:
     * in PDF, unlike PostScript, the values from the lookup table are
     * scaled automatically.
     */
    if ((code = pdf_color_space(pdev, pvalue, NULL, base_space,
				&pdf_color_space_names, false)) < 0 ||
	(code = cos_array_add(pca,
			      cos_c_string_value(&v, 
						 pdf_color_space_names.Indexed
						 /*pcsn->Indexed*/))) < 0 ||
	(code = cos_array_add(pca, pvalue)) < 0 ||
	(code = cos_array_add_int(pca, pip->hival)) < 0 ||
	(code = cos_array_add_no_copy(pca,
				      cos_string_value(&v, table,
						       string_used))) < 0
	)
	return code;
    return 0;
}
Esempio n. 2
0
int
gs_image_next_planes(gs_image_enum * penum,
		     gs_const_string *plane_data /*[num_planes]*/,
		     uint *used /*[num_planes]*/)
{
    const int num_planes = penum->num_planes;
    int i;
    int code = 0;

#ifdef DEBUG
    vd_get_dc('i');
    vd_set_shift(0, 0);
    vd_set_scale(0.01);
    vd_set_origin(0, 0);
    if (gs_debug_c('b')) {
	int pi;

	for (pi = 0; pi < num_planes; ++pi)
	    dprintf6("[b]plane %d source=0x%lx,%u pos=%u data=0x%lx,%u\n",
		     pi, (ulong)penum->planes[pi].source.data,
		     penum->planes[pi].source.size, penum->planes[pi].pos,
		     (ulong)plane_data[pi].data, plane_data[pi].size);
    }
#endif
    for (i = 0; i < num_planes; ++i) {
        used[i] = 0;
	if (penum->wanted[i] && plane_data[i].size != 0) {
	    penum->planes[i].source.size = plane_data[i].size;
	    penum->planes[i].source.data = plane_data[i].data;
	}
    }
    for (;;) {
	/* If wanted can vary, only transfer 1 row at a time. */
	int h = (penum->wanted_varies ? 1 : max_int);

	/* Move partial rows from source[] to row[]. */
	for (i = 0; i < num_planes; ++i) {
	    int pos, size;
	    uint raster;

	    if (!penum->wanted[i])
		continue;	/* skip unwanted planes */
	    pos = penum->planes[i].pos;
	    size = penum->planes[i].source.size;
	    raster = penum->image_planes[i].raster;
	    if (size > 0) {
		if (pos < raster && (pos != 0 || size < raster)) {
		    /* Buffer a partial row. */
		    int copy = min(size, raster - pos);
		    uint old_size = penum->planes[i].row.size;

		    /* Make sure the row buffer is fully allocated. */
		    if (raster > old_size) {
			gs_memory_t *mem = gs_image_row_memory(penum);
			byte *old_data = penum->planes[i].row.data;
			byte *row =
			    (old_data == 0 ?
			     gs_alloc_string(mem, raster,
					     "gs_image_next(row)") :
			     gs_resize_string(mem, old_data, old_size, raster,
					      "gs_image_next(row)"));

			if_debug5('b', "[b]plane %d row (0x%lx,%u) => (0x%lx,%u)\n",
				  i, (ulong)old_data, old_size,
				  (ulong)row, raster);
			if (row == 0) {
			    code = gs_note_error(gs_error_VMerror);
			    free_row_buffers(penum, i, "gs_image_next(row)");
			    break;
			}
			penum->planes[i].row.data = row;
			penum->planes[i].row.size = raster;
		    }
		    memcpy(penum->planes[i].row.data + pos,
			   penum->planes[i].source.data, copy);
		    penum->planes[i].source.data += copy;
		    penum->planes[i].source.size = size -= copy;
		    penum->planes[i].pos = pos += copy;
		    used[i] += copy;
		}
	    }
	    if (h == 0)
		continue;	/* can't transfer any data this cycle */
	    if (pos == raster) {
		/*
		 * This plane will be transferred from the row buffer,
		 * so we can only transfer one row.
		 */
		h = min(h, 1);
		penum->image_planes[i].data = penum->planes[i].row.data;
	    } else if (pos == 0 && size >= raster) {
		/* We can transfer 1 or more planes from the source. */
		h = min(h, size / raster);
		penum->image_planes[i].data = penum->planes[i].source.data;
	    } else
		h = 0;		/* not enough data in this plane */
	}
	if (h == 0 || code != 0)
	    break;
	/* Pass rows to the device. */
	if (penum->dev == 0) {
	    /*
	     * ****** NOTE: THE FOLLOWING IS NOT CORRECT FOR ImageType 3
	     * ****** InterleaveType 2, SINCE MASK HEIGHT AND IMAGE HEIGHT
	     * ****** MAY DIFFER (BY AN INTEGER FACTOR).  ALSO, plane_depths[0]
	     * ****** AND plane_widths[0] ARE NOT UPDATED.
	 */
	    if (penum->y + h < penum->height)
		code = 0;
	    else
		h = penum->height - penum->y, code = 1;
	} else {
	    code = gx_image_plane_data_rows(penum->info, penum->image_planes,
					    h, &h);
	    if_debug2('b', "[b]used %d, code=%d\n", h, code);
	    penum->error = code < 0;
	}
	penum->y += h;
	/* Update positions and sizes. */
	if (h == 0)
	    break;
	for (i = 0; i < num_planes; ++i) {
	    int count;

	    if (!penum->wanted[i])
		continue;
	    count = penum->image_planes[i].raster * h;
	    if (penum->planes[i].pos) {
		/* We transferred the row from the row buffer. */
		penum->planes[i].pos = 0;
	    } else {
		/* We transferred the row(s) from the source. */
		penum->planes[i].source.data += count;
		penum->planes[i].source.size -= count;
		used[i] += count;
	    }
	}
	cache_planes(penum);
	if (code > 0)
	    break;
    }
    /* Return the retained data pointers. */
    for (i = 0; i < num_planes; ++i)
	plane_data[i] = penum->planes[i].source;
    vd_release_dc;
    return code;
}
Esempio n. 3
0
/* This opens %statementedit% or %lineedit% and is also the 
 * continuation proc for callouts.
 * Input:
 *  string is the statement/line buffer, 
 *  int is the write index into string
 *  bool is true if %statementedit%
 *  file is stdin
 * Output:
 *  file is a string based stream
 * We store the line being read in a PostScript string.
 * This limits the size to max_string_size (64k).
 * This could be increased by storing the input line in something 
 * other than a PostScript string.
 */
int
zfilelineedit(i_ctx_t *i_ctx_p)
{
    uint count = 0;
    bool in_eol = false;
    int code;
    os_ptr op = osp;
    bool statement;
    stream *s;
    stream *ins;
    gs_string str;
    uint initial_buf_size;
    const char *filename;
    /*
     * buf exists only for stylistic parallelism: all occurrences of
     * buf-> could just as well be str. .
     */
    gs_string *const buf = &str;

    check_type(*op, t_string);		/* line assembled so far */
    buf->data = op->value.bytes;
    buf->size = op->tas.rsize;
    check_type(*(op-1), t_integer);	/* index */
    count = (op-1)->value.intval;
    check_type(*(op-2), t_boolean);	/* statementedit/lineedit */
    statement = (op-2)->value.boolval;
    check_read_file(ins, op - 3);	/* %stdin */

    /* extend string */
    initial_buf_size = statement ? STATEMENTEDIT_BUF_SIZE : LINEEDIT_BUF_SIZE;
    if (initial_buf_size > max_string_size)
	return_error(e_limitcheck);
    if (!buf->data || (buf->size < initial_buf_size)) {
	count = 0;
	buf->data = gs_alloc_string(imemory_system, initial_buf_size, 
	    "zfilelineedit(buffer)");
	if (buf->data == 0)
	    return_error(e_VMerror);
        op->value.bytes = buf->data;
	op->tas.rsize = buf->size = initial_buf_size;
    }

rd:
    code = zreadline_from(ins, buf, imemory_system, &count, &in_eol);
    if (buf->size > max_string_size) {
	/* zreadline_from reallocated the buffer larger than
	 * is valid for a PostScript string.
	 * Return an error, but first realloc the buffer
	 * back to a legal size.
	 */
	byte *nbuf = gs_resize_string(imemory_system, buf->data, buf->size, 
		max_string_size, "zfilelineedit(shrink buffer)");
	if (nbuf == 0)
	    return_error(e_VMerror);
	op->value.bytes = buf->data = nbuf;
	op->tas.rsize = buf->size = max_string_size;
	return_error(e_limitcheck);
    }

    op->value.bytes = buf->data; /* zreadline_from sometimes resizes the buffer. */
    op->tas.rsize = buf->size;

    switch (code) {
	case EOFC:
	    code = gs_note_error(e_undefinedfilename);
	    /* falls through */
	case 0:
	    break;
	default:
	    code = gs_note_error(e_ioerror);
	    break;
	case CALLC:
	    {
		ref rfile;
		(op-1)->value.intval = count;
		/* callout is for stdin */
		make_file(&rfile, a_readonly | avm_system, ins->read_id, ins);
		code = s_handle_read_exception(i_ctx_p, code, &rfile,  
		    NULL, 0, zfilelineedit);
	    }
	    break;
	case 1:		/* filled buffer */
	    {
		uint nsize = buf->size;
		byte *nbuf;

		if (nsize >= max_string_size) {
		    code = gs_note_error(e_limitcheck);
		    break;
		}
		else if (nsize >= max_string_size / 2)
		    nsize= max_string_size;
		else
		    nsize = buf->size * 2;
		nbuf = gs_resize_string(imemory_system, buf->data, buf->size, nsize,
					"zfilelineedit(grow buffer)");
		if (nbuf == 0) {
		    code = gs_note_error(e_VMerror);
		    break;
		}
		op->value.bytes = buf->data = nbuf;
		op->tas.rsize = buf->size = nsize;
		goto rd;
	    }
    }
    if (code != 0)
	return code;
    if (statement) {
	/* If we don't have a complete token, keep going. */
	stream st;
	stream *ts = &st;
	scanner_state state;
	ref ignore_value;
	uint depth = ref_stack_count(&o_stack);
	int code;

	/* Add a terminating EOL. */
	if (count + 1 > buf->size) {
	    uint nsize;
	    byte *nbuf;

	    nsize = buf->size + 1;
	    if (nsize > max_string_size) {
		return_error(gs_note_error(e_limitcheck));
	    }
	    else {
		nbuf = gs_resize_string(imemory_system, buf->data, buf->size, nsize,
					"zfilelineedit(grow buffer)");
		if (nbuf == 0) {
		    code = gs_note_error(e_VMerror);
		    return_error(code);
		}
		op->value.bytes = buf->data = nbuf;
		op->tas.rsize = buf->size = nsize;
	    }
	}
	buf->data[count++] = char_EOL;
	s_init(ts, NULL);
	sread_string(ts, buf->data, count);
sc:
	scanner_init_stream_options(&state, ts, SCAN_CHECK_ONLY);
	code = scan_token(i_ctx_p, &ignore_value, &state);
	ref_stack_pop_to(&o_stack, depth);
	if (code < 0)
	    code = scan_EOF;	/* stop on scanner error */
	switch (code) {
	    case 0:		/* read a token */
	    case scan_BOS:
		goto sc;	/* keep going until we run out of data */
	    case scan_Refill:
		goto rd;
	    case scan_EOF:
		break;
	    default:		/* error */
		return code;
	}
    }
    buf->data = gs_resize_string(imemory_system, buf->data, buf->size, count,
			   "zfilelineedit(resize buffer)");
    if (buf->data == 0)
	return_error(e_VMerror);
    op->value.bytes = buf->data;
    op->tas.rsize = buf->size;

    s = file_alloc_stream(imemory_system, "zfilelineedit(stream)");
    if (s == 0)
	return_error(e_VMerror);

    sread_string(s, buf->data, count);
    s->save_close = s->procs.close;
    s->procs.close = file_close_disable;

    filename = statement ? gs_iodev_statementedit.dname
	: gs_iodev_lineedit.dname;
    code = ssetfilename(s, (const byte *)filename, strlen(filename)+1);
    if (code < 0) {
	sclose(s);
	return_error(e_VMerror);
    }

    pop(3);
    make_stream_file(osp, s, "r");

    return code;
}