📄 print.c
字号:
/* * GQview * (C) 2004 John Ellis * * Author: John Ellis * * This software is released under the GNU General Public License (GNU GPL). * Please read the included file COPYING for more information. * This software comes with no warranty of any kind, use at your own risk! */#include "gqview.h"#include "print.h"#include "filelist.h"#include "image.h"#include "image-load.h"#include "pixbuf_util.h"#include "thumb.h"#include "utilops.h"#include "ui_bookmark.h"#include "ui_menu.h"#include "ui_misc.h"#include "ui_utildlg.h"#include "ui_fileops.h"#include "ui_spinner.h"#include "ui_tabcomp.h"#include <locale.h>#include <signal.h>#define PRINT_LPR_COMMAND "lpr"#define PRINT_LPR_CUSTOM "lpr -P %s"#define PRINT_LPR_QUERY "lpstat -p"#define PRINT_DLG_WIDTH 600#define PRINT_DLG_HEIGHT 400#define PRINT_DLG_PREVIEW_WIDTH 270#define PRINT_DLG_PREVIEW_HEIGHT -1/* these are in point units */#define PRINT_MIN_WIDTH 100#define PRINT_MIN_HEIGHT 100#define PRINT_MAX_WIDTH 4000#define PRINT_MAX_HEIGHT 4000#define PRINT_MARGIN_DEFAULT 36#define PRINT_PROOF_MIN_SIZE 8#define PRINT_PROOF_MAX_SIZE 720#define PRINT_PROOF_DEFAULT_SIZE 144#define PRINT_PROOF_MARGIN 5/* default page size */#define PAGE_LAYOUT_WIDTH 850#define PAGE_LAYOUT_HEIGHT 1100/* preview uses 1 pixel = PRINT_PREVIEW_SCALE points */#define PRINT_PREVIEW_SCALE 4/* default dpi to use for printing ps image data */#define PRINT_PS_DPI_DEFAULT 300.0#define PRINT_PS_DPI_MIN 150.0/* method to use when scaling down image data */#define PRINT_PS_MAX_INTERP GDK_INTERP_BILINEAR/* padding between objects */#define PRINT_TEXT_PADDING 3.0/* locale for postscript portability */#define POSTSCRIPT_LOCALE "C"/* group and keys for saving prefs */#define PRINT_PREF_GROUP "print_settings"#define PRINT_PREF_SAVE "save_settings"#define PRINT_PREF_OUTPUT "output"#define PRINT_PREF_FORMAT "format"#define PRINT_PREF_DPI "dpi"#define PRINT_PREF_UNITS "units"#define PRINT_PREF_SIZE "size"#define PRINT_PREF_ORIENTATION "orientation"#define PRINT_PREF_CUSTOM_WIDTH "custom_width"#define PRINT_PREF_CUSTOM_HEIGHT "custom_height"#define PRINT_PREF_MARGIN_LEFT "margin_left"#define PRINT_PREF_MARGIN_RIGHT "margin_right"#define PRINT_PREF_MARGIN_TOP "margin_top"#define PRINT_PREF_MARGIN_BOTTOM "margin_bottom"#define PRINT_PREF_PROOF_WIDTH "proof_width"#define PRINT_PREF_PROOF_HEIGHT "proof_height"#define PRINT_PREF_PRINTERC "custom_printer"typedef enum { PRINT_SOURCE_IMAGE = 0, PRINT_SOURCE_SELECTION, PRINT_SOURCE_ALL, PRINT_SOURCE_COUNT} PrintSource;const gchar *print_source_text[] = { N_("Image"), N_("Selection"), N_("All"), NULL};typedef enum { PRINT_LAYOUT_IMAGE = 0, PRINT_LAYOUT_PROOF, PRINT_LAYOUT_COUNT} PrintLayout;const gchar *print_layout_text[] = { N_("One image per page"), N_("Proof sheet"), NULL};typedef enum { PRINT_OUTPUT_PS_LPR = 0, PRINT_OUTPUT_PS_CUSTOM, PRINT_OUTPUT_PS_FILE, PRINT_OUTPUT_RGB_FILE, PRINT_OUTPUT_COUNT} PrintOutput;const gchar *print_output_text[] = { N_("Default printer"), N_("Custom printer"), N_("PostScript file"), N_("Image file"), NULL, NULL};typedef enum { PRINT_FILE_JPG_LOW = 0, PRINT_FILE_JPG_NORMAL, PRINT_FILE_JPG_HIGH, PRINT_FILE_PNG, PRINT_FILE_COUNT} PrintFileFormat;const gchar *print_file_format_text[] = { N_("jpeg, low quality"), N_("jpeg, normal quality"), N_("jpeg, high quality"), "png", NULL};typedef enum { RENDER_FORMAT_PREVIEW, RENDER_FORMAT_RGB, RENDER_FORMAT_PS} RenderFormat;typedef enum { TEXT_INFO_FILENAME = 1 << 0, TEXT_INFO_FILEDATE = 1 << 1, TEXT_INFO_FILESIZE = 1 << 2, TEXT_INFO_DIMENSIONS = 1 << 3} TextInfo;typedef struct _PrintWindow PrintWindow;struct _PrintWindow{ GenericDialog *dialog; gchar *source_path; GList *source_selection; GList *source_list; PrintSource source; PrintLayout layout; PrintOutput output; gchar *output_path; gchar *output_custom; PrintFileFormat output_format; gdouble max_dpi; GtkWidget *notebook; GtkWidget *path_entry; GtkWidget *custom_entry; GtkWidget *path_format_menu; GtkWidget *max_dpi_menu; ImageWindow *layout_image; gdouble layout_width; gdouble layout_height; gint layout_idle_id; gint image_scale; GtkWidget *image_scale_spin; gdouble proof_width; gdouble proof_height; gint proof_columns; gint proof_rows; GList *proof_point; gint proof_position; gint proof_page; GtkWidget *proof_group; GtkWidget *proof_width_spin; GtkWidget *proof_height_spin; GtkWidget *paper_menu; GtkWidget *paper_width_spin; GtkWidget *paper_height_spin; GtkWidget *paper_units_menu; GtkWidget *paper_orientation_menu; GtkWidget *margin_left_spin; GtkWidget *margin_right_spin; GtkWidget *margin_top_spin; GtkWidget *margin_bottom_spin; gint paper_units; gint paper_size; gdouble paper_width; gdouble paper_height; gint paper_orientation; gdouble margin_left; gdouble margin_right; gdouble margin_top; gdouble margin_bottom; GtkWidget *button_back; GtkWidget *button_next; GtkWidget *page_label; GtkWidget *print_button; gdouble single_scale; gdouble single_x; gdouble single_y; GtkWidget *single_scale_spin; TextInfo text_fields; gint text_points; guint8 text_r; guint8 text_g; guint8 text_b; gint save_settings; /* job printing */ GenericDialog *job_dialog; GtkWidget *job_progress; GtkWidget *job_progress_label; RenderFormat job_format; PrintOutput job_output; FILE *job_file; FILE *job_pipe; gchar *job_path; GdkPixbuf *job_pixbuf; gint job_page; ImageLoader *job_loader;};static void print_job_throw_error(PrintWindow *pw, const gchar *message);static gint print_job_start(PrintWindow *pw, RenderFormat format, PrintOutput output);static void print_job_close(PrintWindow *pw, gint error);static void print_window_close(PrintWindow *pw);/* misc utils */static gint clip_region(gdouble x1, gdouble y1, gdouble w1, gdouble h1, gdouble x2, gdouble y2, gdouble w2, gdouble h2, gdouble *rx, gdouble *ry, gdouble *rw, gdouble *rh){ if (x2 + w2 <= x1 || x2 >= x1 + w1 || y2 + h2 <= y1 || y2 >= y1 + h1) { return FALSE; } *rx = MAX(x1, x2); *rw = MIN((x1 + w1), (x2 + w2)) - *rx; *ry = MAX(y1, y2); *rh = MIN((y1 + h1), (y2 + h2)) - *ry; return TRUE;}static const gchar *print_output_name(PrintOutput output){ if (output < 0 || output >= PRINT_OUTPUT_COUNT) return ""; return _(print_output_text[output]);}/* *----------------------------------------------------------------------------- * data *----------------------------------------------------------------------------- */typedef enum { PAPER_UNIT_POINTS = 0, PAPER_UNIT_MM, PAPER_UNIT_CM, PAPER_UNIT_INCH, PAPER_UNIT_PICAS, PAPER_UNIT_COUNT} PaperUnits;typedef enum { PAPER_ORIENTATION_PORTRAIT = 0, PAPER_ORIENTATION_LANDSCAPE, PAPER_ORIENTATION_COUNT} PaperOrientation;typedef struct _PaperSize PaperSize;struct _PaperSize { gchar *description; gint width; gint height; PaperOrientation orientation;};const gchar *print_paper_units[] = { N_("points"), N_("millimeters"), N_("centimeters"), N_("inches"), N_("picas"), NULL};const gchar *print_paper_orientation[] = { N_("Portrait"), N_("Landscape"), NULL};PaperSize print_paper_sizes[] = { { N_("Custom"), 360, 720, PAPER_ORIENTATION_PORTRAIT }, { N_("Letter"), 612, 792, PAPER_ORIENTATION_PORTRAIT }, /* in 8.5 x 11 */ { N_("Legal"), 612, 1008, PAPER_ORIENTATION_PORTRAIT }, /* in 8.5 x 14 */ { N_("Executive"), 522, 756, PAPER_ORIENTATION_PORTRAIT }, /* in 7.25x 10.5 */ { "A0", 2384, 3370, PAPER_ORIENTATION_PORTRAIT }, /* mm 841 x 1189 */ { "A1", 1684, 2384, PAPER_ORIENTATION_PORTRAIT }, /* mm 594 x 841 */ { "A2", 1191, 1684, PAPER_ORIENTATION_PORTRAIT }, /* mm 420 x 594 */ { "A3", 842, 1191, PAPER_ORIENTATION_PORTRAIT }, /* mm 297 x 420 */ { "A4", 595, 842, PAPER_ORIENTATION_PORTRAIT }, /* mm 210 x 297 */ { "A5", 420, 595, PAPER_ORIENTATION_PORTRAIT }, /* mm 148 x 210 */ { "A6", 298, 420, PAPER_ORIENTATION_PORTRAIT }, /* mm 105 x 148 */ { "B3", 1001, 1417, PAPER_ORIENTATION_PORTRAIT }, /* mm 353 x 500 */ { "B4", 709, 1001, PAPER_ORIENTATION_PORTRAIT }, /* mm 250 x 353 */ { "B5", 499, 709, PAPER_ORIENTATION_PORTRAIT }, /* mm 176 x 250 */ { "B6", 354, 499, PAPER_ORIENTATION_PORTRAIT }, /* mm 125 x 176 */ { N_("Envelope #10"), 297, 684, PAPER_ORIENTATION_LANDSCAPE }, /* in 4.125 x 9.5 */ { N_("Envelope #9"), 279, 639, PAPER_ORIENTATION_LANDSCAPE }, /* in 3.875 x 8.875 */ { N_("Envelope C4"), 649, 918, PAPER_ORIENTATION_LANDSCAPE }, /* mm 229 x 324 */ { N_("Envelope C5"), 459, 649, PAPER_ORIENTATION_LANDSCAPE }, /* mm 162 x 229 */ { N_("Envelope C6"), 323, 459, PAPER_ORIENTATION_LANDSCAPE }, /* mm 114 x 162 */ { N_("Photo 6x4"), 432, 288, PAPER_ORIENTATION_PORTRAIT }, /* in 6 x 4 */ { N_("Photo 8x10"), 576, 720, PAPER_ORIENTATION_PORTRAIT }, /* in 8 x 10 */ { N_("Postcard"), 284, 419, PAPER_ORIENTATION_LANDSCAPE }, /* mm 100 x 148 */ { N_("Tabloid"), 792, 1224, PAPER_ORIENTATION_PORTRAIT }, /* in 11 x 17 */ { NULL, 0, 0, 0 }};static PaperSize *print_paper_size_nth(gint n){ PaperSize *ps = NULL; gint i = 0; while (i <= n && print_paper_sizes[i].description) { ps = &print_paper_sizes[i]; i++; } return ps;}static gint print_paper_size_lookup(gint n, gdouble *width, gdouble *height){ PaperSize *ps; gdouble w, h; ps = print_paper_size_nth(n); if (!ps) return FALSE; if (ps->orientation == PAPER_ORIENTATION_PORTRAIT) { w = ps->width; h = ps->height; } else { h = ps->width; w = ps->height; } if (width) *width = w; if (height) *height = h; return TRUE;}static gdouble print_paper_size_convert_units(gdouble value, PaperUnits src, PaperUnits dst){ gdouble ret; if (src == dst) return value; switch (src) { case PAPER_UNIT_MM: ret = value / 25.4 * 72.0; break; case PAPER_UNIT_CM: ret = value / 2.54 * 72.0; break; case PAPER_UNIT_INCH: ret = value * 72.0; break; case PAPER_UNIT_PICAS: ret = value * 12.0; break; case PAPER_UNIT_POINTS: default: ret = value; break; } switch (dst) { case PAPER_UNIT_MM: ret = ret / 72.0 * 25.4; break; case PAPER_UNIT_CM: ret = ret / 72.0 * 2.54; break; case PAPER_UNIT_INCH: ret = ret / 72.0; break; case PAPER_UNIT_PICAS: ret = ret / 12.0; break; case PAPER_UNIT_POINTS: default: break; } return ret;}static PaperUnits paper_unit_default(void){ const char *result;#if 0 /* this is not used because it is not even slightly portable */ #include <langinfo.h> result = nl_langinfo(_NL_MEASUREMENT_MEASUREMENT); if (result[0] == '2') return PAPER_UNIT_INCH;#endif#ifdef LC_MEASUREMENT result = setlocale(LC_MEASUREMENT, NULL);#else result = setlocale(LC_ALL, NULL);#endif if (result && (strstr(result, "_US") || strstr(result, "_PR")) ) { return PAPER_UNIT_INCH; } return PAPER_UNIT_CM;}/* *----------------------------------------------------------------------------- * the layout window *----------------------------------------------------------------------------- */static gint print_layout_page_count(PrintWindow *pw);static gint print_preview_unit(gdouble points){ return (int)(points / PRINT_PREVIEW_SCALE);}static void print_proof_size(PrintWindow *pw, gdouble *width, gdouble *height){ if (width) *width = pw->proof_width + PRINT_PROOF_MARGIN * 2; if (height) { gdouble h; h = pw->proof_height + PRINT_PROOF_MARGIN * 2; if (pw->text_fields != 0) h += PRINT_TEXT_PADDING; if (pw->text_fields & TEXT_INFO_FILENAME) h+= (gdouble)pw->text_points * 1.25; if (pw->text_fields & TEXT_INFO_DIMENSIONS) h+= (gdouble)pw->text_points * 1.25; if (pw->text_fields & TEXT_INFO_FILEDATE) h+= (gdouble)pw->text_points * 1.25; if (pw->text_fields & TEXT_INFO_FILESIZE) h+= (gdouble)pw->text_points * 1.25; *height = h; }}static void print_window_layout_status(PrintWindow *pw){ gint total; gchar *buf; total = print_layout_page_count(pw); pw->proof_page = CLAMP(pw->proof_page, 0, total - 1); buf = g_strdup_printf(_("page %d of %d"), pw->proof_page + 1, (total > 0) ? total : 1); gtk_label_set_text(GTK_LABEL(pw->page_label), buf); g_free(buf); gtk_widget_set_sensitive(pw->page_label, (total > 0)); gtk_widget_set_sensitive(pw->button_back, (pw->proof_page > 0)); gtk_widget_set_sensitive(pw->button_next, (pw->proof_page < total - 1)); gtk_widget_set_sensitive(pw->print_button, total > 0);}static void print_window_layout_render_stop(PrintWindow *pw){ if (pw->layout_idle_id != -1) { g_source_remove(pw->layout_idle_id); pw->layout_idle_id = -1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -