Exemple #1
0
bool PdfCreator::AddImagePage(fz_image *image, float imgDpi)
{
    CrashIf(!ctx || !doc);
    if (!ctx || !doc) return false;

    pdf_page *page = nullptr;
    fz_device *dev = nullptr;
    fz_var(page);
    fz_var(dev);

    fz_try(ctx) {
        float zoom = imgDpi ? 72 / imgDpi : 1.0f;
        fz_matrix ctm = { image->w * zoom, 0, 0, image->h * zoom, 0, 0 };
        fz_rect bounds = fz_unit_rect;
        fz_transform_rect(&bounds, &ctm);
        page = pdf_create_page(doc, bounds, 72, 0);
        dev = pdf_page_write(doc, page);
        fz_fill_image(dev, image, &ctm, 1.0);
        fz_free_device(dev);
        dev = nullptr;
        pdf_insert_page(doc, page, INT_MAX);
    }
    fz_always(ctx) {
        fz_free_device(dev);
        pdf_free_page(doc, page);
    }
    fz_catch(ctx) {
        return false;
    }
    return true;
}
Exemple #2
0
static void page_merge(int page_from, int page_to, pdf_graft_map *graft_map)
{
	pdf_obj *pageref = NULL;
	pdf_obj *page_dict;
	pdf_obj *obj = NULL, *ref = NULL;
	/* Include minimal number of objects for page.  Do not include items that
	 * reference other pages */
	pdf_obj *known_page_objs[] = { PDF_NAME_Contents, PDF_NAME_Resources,
		PDF_NAME_MediaBox, PDF_NAME_CropBox, PDF_NAME_BleedBox, PDF_NAME_TrimBox,
		PDF_NAME_ArtBox, PDF_NAME_Rotate, PDF_NAME_UserUnit};
	int n = nelem(known_page_objs);
	int i;
	int num;

	fz_var(obj);
	fz_var(ref);

	fz_try(ctx)
	{
		pageref = pdf_lookup_page_obj(ctx, doc_src, page_from - 1);

		/* Make a new dictionary and copy over the items from the source object to
		* the new dict that we want to deep copy. */
		page_dict = pdf_new_dict(ctx, doc_des, 4);

		pdf_dict_put_drop(ctx, page_dict, PDF_NAME_Type, PDF_NAME_Page);

		for (i = 0; i < n; i++)
		{
			obj = pdf_dict_get(ctx, pageref, known_page_objs[i]);
			if (obj != NULL)
				pdf_dict_put_drop(ctx, page_dict, known_page_objs[i], pdf_graft_object(ctx, doc_des, doc_src, obj, graft_map));
		}

		/* Add the dictionary */
		obj = pdf_add_object_drop(ctx, doc_des, page_dict);

		/* Get indirect ref */
		num = pdf_to_num(ctx, obj);
		ref = pdf_new_indirect(ctx, doc_des, num, 0);

		/* Insert */
		pdf_insert_page(ctx, doc_des, page_to - 1, ref);
	}
	fz_always(ctx)
	{
		pdf_drop_obj(ctx, obj);
		pdf_drop_obj(ctx, ref);
	}
	fz_catch(ctx)
	{
		fz_rethrow(ctx);
	}
}
Exemple #3
0
static void page_merge(int page_from, int page_to, pdf_graft_map *graft_map)
{
	pdf_obj *page_ref;
	pdf_obj *page_dict;
	pdf_obj *obj;
	pdf_obj *ref = NULL;
	int i;

	/* Copy as few key/value pairs as we can. Do not include items that reference other pages. */
	static pdf_obj * const copy_list[] = { PDF_NAME(Contents), PDF_NAME(Resources),
		PDF_NAME(MediaBox), PDF_NAME(CropBox), PDF_NAME(BleedBox), PDF_NAME(TrimBox), PDF_NAME(ArtBox),
		PDF_NAME(Rotate), PDF_NAME(UserUnit) };

	fz_var(ref);

	fz_try(ctx)
	{
		page_ref = pdf_lookup_page_obj(ctx, doc_src, page_from - 1);
		pdf_flatten_inheritable_page_items(ctx, page_ref);

		/* Make a new page object dictionary to hold the items we copy from the source page. */
		page_dict = pdf_new_dict(ctx, doc_des, 4);

		pdf_dict_put(ctx, page_dict, PDF_NAME(Type), PDF_NAME(Page));

		for (i = 0; i < nelem(copy_list); i++)
		{
			obj = pdf_dict_get(ctx, page_ref, copy_list[i]);
			if (obj != NULL)
				pdf_dict_put_drop(ctx, page_dict, copy_list[i], pdf_graft_mapped_object(ctx, graft_map, obj));
		}

		/* Add the page object to the destination document. */
		ref = pdf_add_object_drop(ctx, doc_des, page_dict);

		/* Insert it into the page tree. */
		pdf_insert_page(ctx, doc_des, page_to - 1, ref);
	}
	fz_always(ctx)
	{
		pdf_drop_obj(ctx, ref);
	}
	fz_catch(ctx)
	{
		fz_rethrow(ctx);
	}
}
Exemple #4
0
static ErrorCode juggler_impose_create_sheet(fz_context *ctx, pdf_document *dest_doc, int width, int height)
{
	/* create and insert page to dest_doc */
	fz_rect rect = { 0, 0, width, height };// { 0, 0, 1390, 1684 };
	pdf_page *sheet = pdf_create_page(ctx, dest_doc, rect, 0, 0);

	sheet->resources = pdf_new_dict(ctx, dest_doc, 16);
	pdf_dict_puts(ctx, sheet->me, "Resources", sheet->resources); /* will be droped when freeing the page */
	sheet->contents = pdf_new_array(ctx, dest_doc, 8);
	pdf_dict_puts(ctx, sheet->me, "Contents", sheet->contents); /* will be droped when freeing the page */

	pdf_insert_page(ctx, dest_doc, sheet, INT_MAX);
	
	pdf_drop_page(ctx, sheet);
	
	return(NoError);
}
Exemple #5
0
static int make_fake_doc(pdfapp_t *app)
{
	fz_context *ctx = app->ctx;
	pdf_document *pdf = NULL;
	fz_buffer *contents = NULL;
	pdf_obj *page_obj = NULL;

	fz_var(contents);
	fz_var(page_obj);

	fz_try(ctx)
	{
		fz_rect mediabox = { 0, 0, app->winw, app->winh };
		int i;

		pdf = pdf_create_document(ctx);


		contents = fz_new_buffer(ctx, 100);
		fz_append_printf(ctx, contents, "1 0 0 RG %g w 0 0 m %g %g l 0 %g m %g 0 l s\n",
			fz_min(mediabox.x1, mediabox.y1) / 20,
			mediabox.x1, mediabox.y1,
			mediabox.y1, mediabox.x1);

		/* Create enough copies of our blank(ish) page so that the
		 * page number is preserved if and when a subsequent load
		 * works. */
		page_obj = pdf_add_page(ctx, pdf, &mediabox, 0, NULL, contents);
		for (i = 0; i < app->pagecount; i++)
			pdf_insert_page(ctx, pdf, -1, page_obj);
	}
	fz_always(ctx)
	{
		pdf_drop_obj(ctx, page_obj);
		fz_drop_buffer(ctx, contents);
	}
	fz_catch(ctx)
	{
		fz_drop_document(ctx, (fz_document *) pdf);
		return 1;
	}

	app->doc = (fz_document*)pdf;
	return 0;
}
Exemple #6
0
static int make_fake_doc(pdfapp_t *app)
{
	fz_context *ctx = app->ctx;
	pdf_document *pdf = NULL;
	fz_buffer *contents = NULL;

	fz_try(ctx)
	{
		fz_rect mediabox = { 0, 0, app->winw, app->winh };
		pdf_obj *page_obj;
		int i;

		contents = fz_new_buffer(ctx, 100);
		pdf = pdf_create_document(ctx);

		app->doc = (fz_document*)pdf;

		fz_buffer_printf(ctx, contents, "1 0 0 rg %f w 0 0 m %f %f l 0 %f m %f 0 l\n",
			fz_min(mediabox.x1, mediabox.y1) / 4,
			mediabox.x1, mediabox.y1,
			mediabox.y1, mediabox.x1);

		/* Create enough copies of our blank(ish) page so that the
		 * page number is preserved if and when a subsequent load
		 * works. */
		page_obj = pdf_add_page(ctx, pdf, &mediabox, 0, contents, NULL);
		for (i = 0; i < app->pagecount; i++)
			pdf_insert_page(ctx, pdf, -1, page_obj);
		pdf_drop_obj(ctx, page_obj);
	}
	fz_always(ctx)
	{
		fz_drop_buffer(ctx, contents);
	}
	fz_catch(ctx)
	{
		fz_rethrow(ctx);
	}
	return 0;
}
Exemple #7
0
static void drawpage(fz_context *ctx, fz_document *doc, int pagenum)
{
	fz_page *page;
	fz_display_list *list = NULL;
	fz_device *dev = NULL;
	int start;
	fz_cookie cookie = { 0 };
	int needshot = 0;

	fz_var(list);
	fz_var(dev);

	if (showtime)
	{
		start = gettime();
	}

	fz_try(ctx)
	{
		page = fz_load_page(doc, pagenum - 1);
	}
	fz_catch(ctx)
	{
		fz_rethrow_message(ctx, "cannot load page %d in file '%s'", pagenum, filename);
	}

	if (mujstest_file)
	{
		pdf_document *inter = pdf_specifics(doc);
		pdf_widget *widget = NULL;

		if (inter)
			widget = pdf_first_widget(inter, (pdf_page *)page);

		if (widget)
		{
			fprintf(mujstest_file, "GOTO %d\n", pagenum);
			needshot = 1;
		}
		for (;widget; widget = pdf_next_widget(widget))
		{
			fz_rect rect;
			int w, h, len;
			int type = pdf_widget_get_type(widget);

			pdf_bound_widget(widget, &rect);
			w = (rect.x1 - rect.x0);
			h = (rect.y1 - rect.y0);
			++mujstest_count;
			switch (type)
			{
			default:
				fprintf(mujstest_file, "%% UNKNOWN %0.2f %0.2f %0.2f %0.2f\n", rect.x0, rect.y0, rect.x1, rect.y1);
				break;
			case PDF_WIDGET_TYPE_PUSHBUTTON:
				fprintf(mujstest_file, "%% PUSHBUTTON %0.2f %0.2f %0.2f %0.2f\n", rect.x0, rect.y0, rect.x1, rect.y1);
				break;
			case PDF_WIDGET_TYPE_CHECKBOX:
				fprintf(mujstest_file, "%% CHECKBOX %0.2f %0.2f %0.2f %0.2f\n", rect.x0, rect.y0, rect.x1, rect.y1);
				break;
			case PDF_WIDGET_TYPE_RADIOBUTTON:
				fprintf(mujstest_file, "%% RADIOBUTTON %0.2f %0.2f %0.2f %0.2f\n", rect.x0, rect.y0, rect.x1, rect.y1);
				break;
			case PDF_WIDGET_TYPE_TEXT:
			{
				int maxlen = pdf_text_widget_max_len(inter, widget);
				int texttype = pdf_text_widget_content_type(inter, widget);

				/* If height is low, assume a single row, and base
				 * the width off that. */
				if (h < 10)
				{
					w = (w+h-1) / (h ? h : 1);
					h = 1;
				}
				/* Otherwise, if width is low, work off height */
				else if (w < 10)
				{
					h = (w+h-1) / (w ? w : 1);
					w = 1;
				}
				else
				{
					w = (w+9)/10;
					h = (h+9)/10;
				}
				len = w*h;
				if (len < 2)
					len = 2;
				if (len > maxlen)
					len = maxlen;
				fprintf(mujstest_file, "%% TEXT %0.2f %0.2f %0.2f %0.2f\n", rect.x0, rect.y0, rect.x1, rect.y1);
				switch (texttype)
				{
				default:
				case PDF_WIDGET_CONTENT_UNRESTRAINED:
					fprintf(mujstest_file, "TEXT %d ", mujstest_count);
					escape_string(mujstest_file, len-3, lorem);
					fprintf(mujstest_file, "\n");
					break;
				case PDF_WIDGET_CONTENT_NUMBER:
					fprintf(mujstest_file, "TEXT %d\n", mujstest_count);
					break;
				case PDF_WIDGET_CONTENT_SPECIAL:
#ifdef __MINGW32__
					fprintf(mujstest_file, "TEXT %I64d\n", 46702919800LL + mujstest_count);
#else
					fprintf(mujstest_file, "TEXT %lld\n", 46702919800LL + mujstest_count);
#endif
					break;
				case PDF_WIDGET_CONTENT_DATE:
					fprintf(mujstest_file, "TEXT Jun %d 1979\n", 1 + ((13 + mujstest_count) % 30));
					break;
				case PDF_WIDGET_CONTENT_TIME:
					++mujstest_count;
					fprintf(mujstest_file, "TEXT %02d:%02d\n", ((mujstest_count/60) % 24), mujstest_count % 60);
					break;
				}
				break;
			}
			case PDF_WIDGET_TYPE_LISTBOX:
				fprintf(mujstest_file, "%% LISTBOX %0.2f %0.2f %0.2f %0.2f\n", rect.x0, rect.y0, rect.x1, rect.y1);
				break;
			case PDF_WIDGET_TYPE_COMBOBOX:
				fprintf(mujstest_file, "%% COMBOBOX %0.2f %0.2f %0.2f %0.2f\n", rect.x0, rect.y0, rect.x1, rect.y1);
				break;
			}
			fprintf(mujstest_file, "CLICK %0.2f %0.2f\n", (rect.x0+rect.x1)/2, (rect.y0+rect.y1)/2);
		}
	}

	if (uselist)
	{
		fz_try(ctx)
		{
			list = fz_new_display_list(ctx);
			dev = fz_new_list_device(ctx, list);
			fz_run_page(doc, page, dev, &fz_identity, &cookie);
		}
		fz_always(ctx)
		{
			fz_free_device(dev);
			dev = NULL;
		}
		fz_catch(ctx)
		{
			fz_drop_display_list(ctx, list);
			fz_free_page(doc, page);
			fz_rethrow_message(ctx, "cannot draw page %d in file '%s'", pagenum, filename);
		}
	}

	if (showxml)
	{
		fz_try(ctx)
		{
			dev = fz_new_trace_device(ctx);
			if (list)
				fz_run_display_list(list, dev, &fz_identity, &fz_infinite_rect, &cookie);
			else
				fz_run_page(doc, page, dev, &fz_identity, &cookie);
		}
		fz_always(ctx)
		{
			fz_free_device(dev);
			dev = NULL;
		}
		fz_catch(ctx)
		{
			fz_drop_display_list(ctx, list);
			fz_free_page(doc, page);
			fz_rethrow(ctx);
		}
	}

	if (showtext)
	{
		fz_text_page *text = NULL;

		fz_var(text);

		fz_try(ctx)
		{
			text = fz_new_text_page(ctx);
			dev = fz_new_text_device(ctx, sheet, text);
			if (showtext == TEXT_HTML)
				fz_disable_device_hints(dev, FZ_IGNORE_IMAGE);
			if (list)
				fz_run_display_list(list, dev, &fz_identity, &fz_infinite_rect, &cookie);
			else
				fz_run_page(doc, page, dev, &fz_identity, &cookie);
			fz_free_device(dev);
			dev = NULL;
			if (showtext == TEXT_XML)
			{
				fz_print_text_page_xml(ctx, out, text);
			}
			else if (showtext == TEXT_HTML)
			{
				fz_analyze_text(ctx, sheet, text);
				fz_print_text_page_html(ctx, out, text);
			}
			else if (showtext == TEXT_PLAIN)
			{
				fz_print_text_page(ctx, out, text);
				fz_printf(out, "\f\n");
			}
		}
		fz_always(ctx)
		{
			fz_free_device(dev);
			dev = NULL;
			fz_free_text_page(ctx, text);
		}
		fz_catch(ctx)
		{
			fz_drop_display_list(ctx, list);
			fz_free_page(doc, page);
			fz_rethrow(ctx);
		}
	}

	if (showmd5 || showtime)
		printf("page %s %d", filename, pagenum);

	if (pdfout)
	{
		fz_matrix ctm;
		fz_rect bounds, tbounds;
		pdf_page *newpage;

		fz_bound_page(doc, page, &bounds);
		fz_rotate(&ctm, rotation);
		tbounds = bounds;
		fz_transform_rect(&tbounds, &ctm);

		newpage = pdf_create_page(pdfout, bounds, 72, 0);

		fz_try(ctx)
		{
			dev = pdf_page_write(pdfout, newpage);
			if (list)
				fz_run_display_list(list, dev, &ctm, &tbounds, &cookie);
			else
				fz_run_page(doc, page, dev, &ctm, &cookie);
			fz_free_device(dev);
			dev = NULL;
		}
		fz_always(ctx)
		{
			fz_free_device(dev);
			dev = NULL;
		}
		fz_catch(ctx)
		{
			fz_drop_display_list(ctx, list);
			fz_free_page(doc, page);
			fz_rethrow(ctx);
		}
		pdf_insert_page(pdfout, newpage, INT_MAX);
		pdf_free_page(pdfout, newpage);
	}

	if (output && output_format == OUT_SVG)
	{
		float zoom;
		fz_matrix ctm;
		fz_rect bounds, tbounds;
		char buf[512];
		FILE *file;
		fz_output *out;

		if (!strcmp(output, "-"))
			file = stdout;
		else
		{
			sprintf(buf, output, pagenum);
			file = fopen(buf, "wb");
			if (file == NULL)
				fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", buf, strerror(errno));
		}

		out = fz_new_output_with_file(ctx, file);

		fz_bound_page(doc, page, &bounds);
		zoom = resolution / 72;
		fz_pre_rotate(fz_scale(&ctm, zoom, zoom), rotation);
		tbounds = bounds;
		fz_transform_rect(&tbounds, &ctm);

		fz_try(ctx)
		{
			dev = fz_new_svg_device(ctx, out, tbounds.x1-tbounds.x0, tbounds.y1-tbounds.y0);
			if (list)
				fz_run_display_list(list, dev, &ctm, &tbounds, &cookie);
			else
				fz_run_page(doc, page, dev, &ctm, &cookie);
			fz_free_device(dev);
			dev = NULL;
		}
		fz_always(ctx)
		{
			fz_free_device(dev);
			dev = NULL;
			fz_close_output(out);
			if (file != stdout)
				fclose(file);
		}
		fz_catch(ctx)
		{
			fz_drop_display_list(ctx, list);
			fz_free_page(doc, page);
			fz_rethrow(ctx);
		}
	}
Exemple #8
0
static void drawpage(fz_context *ctx, fz_document *doc, int pagenum)
{
	fz_page *page;
	fz_display_list *list = NULL;
	fz_device *dev = NULL;
	int start;
	fz_cookie cookie = { 0 };

	fz_var(list);
	fz_var(dev);

	if (showtime)
	{
		start = gettime();
	}

	fz_try(ctx)
	{
		page = fz_load_page(doc, pagenum - 1);
	}
	fz_catch(ctx)
	{
		fz_rethrow_message(ctx, "cannot load page %d in file '%s'", pagenum, filename);
	}

	if (uselist)
	{
		fz_try(ctx)
		{
			list = fz_new_display_list(ctx);
			dev = fz_new_list_device(ctx, list);
			fz_run_page(doc, page, dev, &fz_identity, &cookie);
		}
		fz_always(ctx)
		{
			fz_free_device(dev);
			dev = NULL;
		}
		fz_catch(ctx)
		{
			fz_drop_display_list(ctx, list);
			fz_free_page(doc, page);
			fz_rethrow_message(ctx, "cannot draw page %d in file '%s'", pagenum, filename);
		}
	}

	if (showxml)
	{
		fz_try(ctx)
		{
			dev = fz_new_trace_device(ctx);
			if (list)
				fz_run_display_list(list, dev, &fz_identity, &fz_infinite_rect, &cookie);
			else
				fz_run_page(doc, page, dev, &fz_identity, &cookie);
		}
		fz_always(ctx)
		{
			fz_free_device(dev);
			dev = NULL;
		}
		fz_catch(ctx)
		{
			fz_drop_display_list(ctx, list);
			fz_free_page(doc, page);
			fz_rethrow(ctx);
		}
	}

	if (showtext)
	{
		fz_text_page *text = NULL;

		fz_var(text);

		fz_try(ctx)
		{
			text = fz_new_text_page(ctx);
			dev = fz_new_text_device(ctx, sheet, text);
			if (showtext == TEXT_HTML)
				fz_disable_device_hints(dev, FZ_IGNORE_IMAGE);
			if (list)
				fz_run_display_list(list, dev, &fz_identity, &fz_infinite_rect, &cookie);
			else
				fz_run_page(doc, page, dev, &fz_identity, &cookie);
			fz_free_device(dev);
			dev = NULL;
			if (showtext == TEXT_XML)
			{
				fz_print_text_page_xml(ctx, out, text);
			}
			else if (showtext == TEXT_HTML)
			{
				fz_analyze_text(ctx, sheet, text);
				fz_print_text_page_html(ctx, out, text);
			}
			else if (showtext == TEXT_PLAIN)
			{
				fz_print_text_page(ctx, out, text);
				fz_printf(out, "\f\n");
			}
		}
		fz_always(ctx)
		{
			fz_free_device(dev);
			dev = NULL;
			fz_free_text_page(ctx, text);
		}
		fz_catch(ctx)
		{
			fz_drop_display_list(ctx, list);
			fz_free_page(doc, page);
			fz_rethrow(ctx);
		}
	}

	if (showmd5 || showtime || showfeatures)
		printf("page %s %d", filename, pagenum);

	if (showfeatures)
	{
		int iscolor;
		dev = fz_new_test_device(ctx, &iscolor, 0.02f);
		fz_try(ctx)
		{
			if (list)
				fz_run_display_list(list, dev, &fz_identity, &fz_infinite_rect, NULL);
			else
				fz_run_page(doc, page, dev, &fz_identity, &cookie);
		}
		fz_always(ctx)
		{
			fz_free_device(dev);
			dev = NULL;
		}
		fz_catch(ctx)
		{
			fz_rethrow(ctx);
		}
		printf(" %s", iscolor ? "color" : "grayscale");
	}

	if (pdfout)
	{
		fz_matrix ctm;
		fz_rect bounds, tbounds;
		pdf_page *newpage;

		fz_bound_page(doc, page, &bounds);
		fz_rotate(&ctm, rotation);
		tbounds = bounds;
		fz_transform_rect(&tbounds, &ctm);

		newpage = pdf_create_page(pdfout, bounds, 72, 0);

		fz_try(ctx)
		{
			dev = pdf_page_write(pdfout, newpage);
			if (list)
				fz_run_display_list(list, dev, &ctm, &tbounds, &cookie);
			else
				fz_run_page(doc, page, dev, &ctm, &cookie);
			fz_free_device(dev);
			dev = NULL;
		}
		fz_always(ctx)
		{
			fz_free_device(dev);
			dev = NULL;
		}
		fz_catch(ctx)
		{
			fz_drop_display_list(ctx, list);
			fz_free_page(doc, page);
			fz_rethrow(ctx);
		}
		pdf_insert_page(pdfout, newpage, INT_MAX);
		pdf_free_page(pdfout, newpage);
	}

	if (output && output_format == OUT_SVG)
	{
		float zoom;
		fz_matrix ctm;
		fz_rect bounds, tbounds;
		char buf[512];
		FILE *file;
		fz_output *out;

		if (!strcmp(output, "-"))
			file = stdout;
		else
		{
			sprintf(buf, output, pagenum);
			file = fopen(buf, "wb");
			if (file == NULL)
				fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", buf, strerror(errno));
		}

		out = fz_new_output_with_file(ctx, file);

		fz_bound_page(doc, page, &bounds);
		zoom = resolution / 72;
		fz_pre_rotate(fz_scale(&ctm, zoom, zoom), rotation);
		tbounds = bounds;
		fz_transform_rect(&tbounds, &ctm);

		fz_try(ctx)
		{
			dev = fz_new_svg_device(ctx, out, tbounds.x1-tbounds.x0, tbounds.y1-tbounds.y0);
			if (list)
				fz_run_display_list(list, dev, &ctm, &tbounds, &cookie);
			else
				fz_run_page(doc, page, dev, &ctm, &cookie);
			fz_free_device(dev);
			dev = NULL;
		}
		fz_always(ctx)
		{
			fz_free_device(dev);
			dev = NULL;
			fz_close_output(out);
			if (file != stdout)
				fclose(file);
		}
		fz_catch(ctx)
		{
			fz_drop_display_list(ctx, list);
			fz_free_page(doc, page);
			fz_rethrow(ctx);
		}
	}
static int make_fake_doc(pdfapp_t *app)
{
	fz_context *ctx = app->ctx;
	fz_matrix ctm = { 1, 0, 0, 1, 0, 0 };
	fz_rect bounds;
	pdf_page *newpage = NULL;
	pdf_document *pdf = NULL;
	fz_device *dev = NULL;
	fz_path *path = NULL;
	fz_stroke_state stroke = fz_default_stroke_state;
	float red[3] = { 1, 0, 0 };
	int i;

	fz_var(pdf);
	fz_var(dev);
	fz_var(newpage);

	fz_try(ctx)
	{
		pdf = pdf_create_document(ctx);
		app->doc = &pdf->super;
		bounds.x0 = 0;
		bounds.y0 = 0;
		bounds.x1 = app->winw;
		bounds.y1 = app->winh;

		newpage = pdf_create_page(ctx, pdf, bounds, 72, 0);

		dev = pdf_page_write(ctx, pdf, newpage);

		/* Now the page content */
		fz_begin_page(ctx, dev, &bounds, &ctm);

		path = fz_new_path(ctx);
		fz_moveto(ctx, path, 0, 0);
		fz_lineto(ctx, path, bounds.x1, bounds.y1);
		fz_moveto(ctx, path, 0, bounds.y1);
		fz_lineto(ctx, path, bounds.x1, 0);

		stroke.linewidth = fz_min(bounds.x1, bounds.y1)/4;

		fz_stroke_path(ctx, dev, path, &stroke, &ctm, fz_device_rgb(ctx), red, 1);

		fz_end_page(ctx, dev);

		fz_drop_device(ctx, dev);
		dev = NULL;

		/* Create enough copies of our blank(ish) page so that the
		 * page number is preserved if and when a subsequent load
		 * works. */
		for (i = 0; i < app->pagecount; i++)
			pdf_insert_page(ctx, pdf, newpage, INT_MAX);
	}
	fz_always(ctx)
	{
		fz_drop_path(ctx, path);
		pdf_drop_page(ctx, newpage);
		fz_drop_device(ctx, dev);
		dev = NULL;
	}
	fz_catch(ctx)
	{
		fz_rethrow(ctx);
	}

	return 0;
}