def draw(argv): password = '' info = trace_info() items, argv = getopt.getopt( argv, 'qp:o:F:R:r:w:h:fB:c:e:G:Is:A:DiW:H:S:T:U:XLvPl:y:NO:a') for option, value in items: if 0: pass elif option == '-q': state.quiet = 1 elif option == '-p': password = value elif option == '-o': state.output = value elif option == '-F': state.format_ = value elif option == '-R': state.rotation = float(value) elif option == '-r': state.resolution = float(value) state.res_specified = 1 elif option == '-w': state.width = float(value) elif option == '-h': state.height = float(value) elif option == '-f': state.fit = 1 elif option == '-B': state.band_height = int(value) elif option == '-c': state.out_cs = parse_colorspace(value) elif option == '-e': state.proof_filename = value elif option == '-G': state.gamma_value = float(value) elif option == '-I': state.invert += 1 elif option == '-W': state.layout_w = float(value) elif option == '-H': state.layout_h = float(value) elif option == '-S': state.layout_em = float(value) elif option == '-U': state.layout_css = value elif option == '-X': state.layout_use_doc_css = 0 elif option == '-O': state.spots = float(value) if not mupdf.FZ_ENABLE_SPOT_RENDERING: sys.stderr.write( 'Spot rendering/Overprint/Overprint simulation not enabled in this build\n' ) state.spots = SPOTS_NONE elif option == '-s': if 't' in value: state.showtime += 1 if 'm' in value: state.showmemory += 1 if 'f' in value: state.showfeatures += 1 if '5' in value: state.showmd5 += 1 elif option == '-A': state.alphabits_graphics = int(value) sep = value.find('/') if sep >= 0: state.alphabits_text = int(value[sep + 1:]) else: state.alphabits_text = state.alphabits_graphics elif option == '-D': state.uselist = 0 elif option == '-l': state.min_line_width = float(value) elif option == '-i': state.ignore_errors = 1 elif option == '-N': state.no_icc = 1 elif option == '-T': state.num_workers = int(value) elif option == '-L': state.lowmemory = 1 elif option == '-P': bgprint.active = 1 elif option == '-y': state.layer_config = value elif option == '-a': state.useaccel = 0 elif option == '-v': sys.stderr.write(f'mudraw version {mupdf.FZ_VERSION}\n') if not argv: usage() if state.num_workers > 0: if state.uselist == 0: sys.stderr.write( 'cannot use multiple threads without using display list\n') sys.exit(1) if state.band_height == 0: sys.stderr.write( 'Using multiple threads without banding is pointless\n') if bgprint.active: if state.uselist == 0: sys.stderr.write('cannot bgprint without using display list\n') sys.exit(1) if state.proof_filename: proof_buffer = mupdf.Buffer(state.proof_filename) state.proof_cs = mupdf.Colorspace(FZ_COLORSPACE_NONE, 0, None, proof_buffer) mupdf.set_text_aa_level(state.alphabits_text) mupdf.set_graphics_aa_level(state.alphabits_graphics) mupdf.set_graphics_min_line_width(state.min_line_width) if state.no_icc: mupdf.disable_icc() else: mupdf.enable_icc() if state.layout_css: buf = mupdf.Buffer(state.layout_css) mupdf.set_user_css(buf.string_from_buffer()) mupdf.set_use_document_css(state.layout_use_doc_css) # Determine output type if state.band_height < 0: sys.stderr.write('Bandheight must be > 0\n') sys.exit(1) state.output_format = OUT_PNG if state.format_: for i in range(len(suffix_table)): if state.format_ == suffix_table[i].suffix[1:]: state.output_format = suffix_table[i].format if state.spots == SPOTS_FULL and suffix_table[i].spots == 0: sys.stderr.write( f'Output format {suffix_table[i].suffix[1:]} does not support spot rendering.\nDoing overprint simulation instead.\n' ) state.spots = SPOTS_OVERPRINT_SIM break else: sys.stderr.write(f'Unknown output format {format}\n') sys.exit(1) elif state.output: suffix = state.output i = 0 while 1: if i == len(suffix_table): break s = suffix.find(suffix_table[i].suffix) if s != -1: suffix = suffix_table[i].suffix[s + 1:] state.output_format = suffix_table[i].format if state.spots == SPOTS_FULL and suffix_table[i].spots == 0: sys.stderr.write( 'Output format {suffix_table[i].suffix[1:]} does not support spot rendering\nDoing overprint simulation instead.\n' ) state.spots = SPOTS_OVERPRINT_SIM i = 0 else: i += 1 if state.band_height: if state.output_format not in (OUT_PAM, OUT_PGM, OUT_PPM, OUT_PNM, OUT_PNG, OUT_PBM, OUT_PKM, OUT_PCL, OUT_PCLM, OUT_PS, OUT_PSD): sys.stderr.write( 'Banded operation only possible with PxM, PCL, PCLM, PS, PSD, and PNG outputs\n' ) sys.exit(1) if state.showmd5: sys.stderr.write('Banded operation not compatible with MD5\n') sys.exit(1) for i in range(len(format_cs_table)): if format_cs_table[i].format == state.output_format: if state.out_cs == CS_UNSET: state.out_cs = format_cs_table[i].default_cs for j in range(len(format_cs_table[i].permitted_cs)): if format_cs_table[i].permitted_cs[j] == state.out_cs: break else: sys.stderr.write('Unsupported colorspace for this format\n') sys.exit(1) state.alpha = 1 if state.out_cs in (CS_MONO, CS_GRAY, CS_GRAY_ALPHA): state.colorspace = mupdf.Colorspace(mupdf.Colorspace.Fixed_GRAY) state.alpha = (state.out_cs == CS_GRAY_ALPHA) elif state.out_cs in (CS_RGB, CS_RGB_ALPHA): state.colorspace = mupdf.Colorspace(mupdf.Colorspace.Fixed_RGB) state.alpha = (state.out_cs == CS_RGB_ALPHA) elif state.out_cs in (CS_CMYK, CS_CMYK_ALPHA): state.colorspace = mupdf.Colorspace(mupdf.Colorspace.Fixed_CMYK) state.alpha = (state.out_cs == CS_CMYK_ALPHA) elif state.out_cs == CS_ICC: try: icc_buffer = mupdf.Buffer(state.icc_filename) state.colorspace = Colorspace(mupdf.FZ_COLORSPACE_NONE, 0, None, icc_buffer) except Exception as e: sys.stderr.write('Invalid ICC destination color space\n') sys.exit(1) if state.colorspace.m_internal is None: sys.stderr.write('Invalid ICC destination color space\n') sys.exit(1) state.alpha = 0 else: sys.stderr.write('Unknown colorspace!\n') sys.exit(1) if state.out_cs != CS_ICC: state.colorspace = mupdf.Colorspace(state.colorspace) else: # Check to make sure this icc profile is ok with the output format */ okay = 0 for i in range(len(format_cs_table)): if format_cs_table[i].format == state.output_format: for j in range(len(format_cs_table[i].permitted_cs)): x = format_cs_table[i].permitted_cs[j] if x in (CS_MONO, CS_GRAY, CS_GRAY_ALPHA): if state.colorspace.colorspace_is_gray(): okay = 1 elif x in (CS_RGB, CS_RGB_ALPHA): if state.colorspace.colorspace_is_rgb(): okay = 1 elif x in (CS_CMYK, CS_CMYK_ALPHA): if state.colorspace.colorspace_is_cmyk(): okay = 1 if not okay: sys.stderr.write( 'ICC profile uses a colorspace that cannot be used for this format\n' ) sys.exit(1) if state.output_format == OUT_SVG: # SVG files are always opened for each page. Do not open "output". pass elif state.output and (not state.output.startswith('-') or len(state.output) >= 2) and len(state.output) >= 1: if has_percent_d(state.output): state.output_file_per_page = 1 else: state.out = mupdf.Output(state.output, 0) else: state.quiet = 1 # automatically be quiet if printing to stdout if 0: # Windows specific code to make stdout binary. if state.output_format not in (OUT_TEXT, OUT_STEXT, OUT_HTML, OUT_XHTML, OUT_TRACE, OUT_XMLTEXT): setmode(fileno(stdout), O_BINARY) state.out = mupdf.Output(mupdf.Output.Fixed_STDOUT) state.filename = argv[0] if not state.output_file_per_page: file_level_headers() timing.count = 0 timing.total = 0 timing.min = 1 << 30 timing.max = 0 timing.mininterp = 1 << 30 timing.maxinterp = 0 timing.minpage = 0 timing.maxpage = 0 timing.minfilename = "" timing.maxfilename = "" timing.layout = 0 timing.minlayout = 1 << 30 timing.maxlayout = 0 timing.minlayoutfilename = "" timing.maxlayoutfilename = "" if state.showtime and bgprint.active: timing.total = gettime() fz_optind = 0 try: while fz_optind < len(argv): try: accel = None state.filename = argv[fz_optind] fz_optind += 1 state.files += 1 if not state.useaccel: accel = None # If there was an accelerator to load, what would it be called? else: accelpath = get_accelerator_filename(state.filename) # Check whether that file exists, and isn't older than # the document. atime = stat_mtime(accelpath) dtime = stat_mtime(state.filename) if atime == 0: # No accelerator pass elif atime > dtime: accel = accelpath else: # Accelerator data is out of date os.unlink(accelpath) accel = None # In case we have jumped up from below # Unfortunately if accel=None, SWIG doesn't seem to think of it # as a char*, so we end up in fz_open_document_with_stream(). # # If we try to avoid this by setting accel='', SWIG correctly # calls Document(const char *filename, const char *accel) => # fz_open_accelerated_document(), but the latter function tests # for NULL not "" so fails. # # So we choose the constructor explicitly rather than leaving # it up to SWIG. # if accel: doc = mupdf.Document(state.filename, accel) else: doc = mupdf.Document(state.filename) if doc.needs_password(): if not doc.authenticate_password(password): raise Exception( f'cannot authenticate password: {state.filename}') # Once document is open check for output intent colorspace state.oi = doc.document_output_intent() if state.oi.m_internal: # See if we had explicitly set a profile to render if state.out_cs != CS_ICC: # In this case, we want to render to the output intent # color space if the number of channels is the same if state.oi.colorspace_n( ) == state.colorspace.colorspace_n(): state.colorspace = state.oi layouttime = time.time() doc.layout_document(state.layout_w, state.layout_h, state.layout_em) doc.count_pages() layouttime = time.time() - layouttime timing.layout += layouttime if layouttime < timing.minlayout: timing.minlayout = layouttime timing.minlayoutfilename = state.filename if layouttime > timing.maxlayout: timing.maxlayout = layouttime timing.maxlayoutfilename = state.filename if state.layer_config: apply_layer_config(doc, state.layer_config) if fz_optind == len(argv) or not mupdf.is_page_range( argv[fz_optind]): drawrange(doc, "1-N") if fz_optind < len(argv) and mupdf.is_page_range( argv[fz_optind]): drawrange(doc, argv[fz_optind]) fz_optind += 1 bgprint_flush() if state.useaccel: save_accelerator(doc, state.filename) except Exception as e: if not state.ignore_errors: raise bgprint_flush() sys.stderr.write(f'ignoring error in {state.filename}\n') except Exception as e: bgprint_flush() sys.stderr.write( f'error: cannot draw \'{state.filename}\' because: {e}\n') state.errored = 1 if not state.output_file_per_page: file_level_trailers() if state.out: state.out.close_output() state.out = None if state.showtime and timing.count > 0: if bgprint.active: timing.total = gettime() - timing.total if state.files == 1: sys.stderr.write( f'total {timing.total:.0f}ms ({timing.layout:.0f}ms layout) / {timing.count} pages for an average of {timing.total / timing.count:.0f}ms\n' ) if bgprint.active: sys.stderr.write( f'fastest page {timing.minpage}: {timing.mininterp:.0f}ms (interpretation) {timing.min - timing.mininterp:.0f}ms (rendering) {timing.min:.0f}ms(total)\n' ) sys.stderr.write( f'slowest page {timing.maxpage}: {timing.maxinterp:.0f}ms (interpretation) {timing.max - timing.maxinterp:.0f}ms (rendering) {timing.max:.0f}ms(total)\n' ) else: sys.stderr.write( f'fastest page {timing.minpage}: {timing.min:.0f}ms\n') sys.stderr.write( f'slowest page {timing.maxpage}: {timing.max:.0f}ms\n') else: sys.stderr.write( f'total {timing.total:.0f}ms ({timing.layout:.0f}ms layout) / {timing.count} pages for an average of {timing.total / timing.count:.0f}ms in {state.files} files\n' ) sys.stderr.write( f'fastest layout: {timing.minlayout:.0f}ms ({timing.minlayoutfilename})\n' ) sys.stderr.write( f'slowest layout: {timing.maxlayout:.0f}ms ({timing.maxlayoutfilename})\n' ) sys.stderr.write( f'fastest page {timing.minpage}: {timing.min:.0f}ms ({timing.minfilename})\n' ) sys.stderr.write( f'slowest page {timing.maxpage}: {timing.max:.0f}ms ({timing.maxfilename})\n' ) if state.showmemory: sys.stderr.write( f'Memory use total={info.total} peak={info.peak} current={info.current}\n' ) return state.errored != 0
def draw(argv): global alphabits_graphics global alphabits_text global band_height global colorspace global files global fir global format_ global gamma_value global height global ignore_errors global invert global layer_config global layout_css global layout_em global layout_h global layout_use_doc_css global layout_w global lowmemory global min_line_width global no_icc global num_workers global num_workers global out global out_cs global output global output_file_per_page global output_format global password global proof_filename global quiet global resolution global res_specified global rotation global showfeatures global showmd5 global showmemory global showtime global spots global uselist global width info = trace_info() quiet = 0 items, argv = getopt.getopt( argv, 'qp:o:F:R:r:w:h:fB:c:e:G:Is:A:DiW:H:S:T:U:XLvPl:y:NO:') for option, value in items: if 0: pass elif option == '-q': quiet = 1 elif option == '-p': password = value elif option == '-o': output = value elif option == '-F': format_ = value elif option == '-R': rotation = float(value) elif option == '-r': resolution = float(output) res_specified = 1 elif option == '-w': width = float(value) elif option == '-h': height = float(value) elif option == '-f': fir = 1 elif option == '-B': band_height = int(value) elif option == '-c': out_cs = parse_colorspace(value) elif option == '-e': proof_filename = value elif option == '-G': gamma_value = float(value) elif option == '-I': invert += 1 elif option == '-W': layout_w = float(value) elif option == '-H': layout_h = float(value) elif option == '-S': layout_em = float(value) elif option == '-U': layout_css = value elif option == '-X': layout_use_doc_css = 0 elif option == '-O': spots = float(value) if not mupdf.FZ_ENABLE_SPOT_RENDERING: jlib.log( 'Spot rendering/Overprint/Overprint simulation not enabled in this build' ) spots = SPOTS_NONE elif option == '-s': if 't' in value: showtime += 1 if 'm' in value: showmemory += 1 if 'f' in value: showfeatures += 1 if '5' in value: showmd5 += 1 elif option == '-A': alphabits_graphics = int(value) sep = value.find('/') if sep >= 0: alphabits_text = int(value[sep + 1:]) else: alphabits_text = alphabits_graphics elif option == '-D': uselist = 0 elif option == '-l': min_line_width = float(value) elif option == '-i': ignore_errors = 1 elif option == '-N': no_icc = 1 elif option == '-T': num_workers = int(value) elif option == '-L': lowmemory = 1 elif option == '-P': bgprint.active = 1 elif option == '-y': layer_config = value elif option == '-v': print(f'mudraw version {mupdf.FZ_VERSION}') if not argv: usage() if num_workers > 0: if uselist == 0: printf('cannot use multiple threads without using display list') sys.exit(1) if band_height == 0: printf('Using multiple threads without banding is pointless') if bgprint.active: if uselist == 0: printf('cannot bgprint without using display list') sys.exit(1) if proof_filename: proof_buffer = mupdf.Buffer(proof_filename) proof_cs = mupdf.Colorspace(FZ_COLORSPACE_NONE, 0, None, proof_buffer) mupdf.set_text_aa_level(alphabits_text) mupdf.set_graphics_aa_level(alphabits_graphics) mupdf.set_graphics_min_line_width(min_line_width) if no_icc: mupdf.disable_icc() else: mupdf.enable_icc() if layout_css: buf = mupdf.Buffer(layout_css) mupdf.set_user_css(buf.string_from_buffer()) mupdf.set_use_document_css(layout_use_doc_css) # Determine output type if band_height < 0: print('Bandheight must be > 0') sys.exit(1) output_format = OUT_PNG if format_: jlib.log('{format=}') for i in range(len(suffix_table)): if format_ == suffix_table[i].suffix[1:]: output_format = suffix_table[i].format if spots == SPOTS_FULL and suffix_table[i].spots == 0: print( f'Output format {suffix_table[i].suffix[1:]} does not support spot rendering.' ) print('Doing overprint simulation instead.') spots = SPOTS_OVERPRINT_SIM break else: print(f'Unknown output format {format}') sys.exit(1) elif output: suffix = output i = 0 while 1: if i == len(suffix_table): break s = suffix.find(suffix_table[i].suffix) if s != -1: suffix = suffix_table[i].suffix[s + 1:] output_format = suffix_table[i].format_ if spots == SPOTS_FULL and suffix_table[i].spots == 0: print( 'Output format {suffix_table[i].suffix[1:]} does not support spot rendering' ) print('Doing overprint simulation instead.') spots = SPOTS_OVERPRINT_SIM i = 0 else: i += 1 if band_height: if output_format not in (OUT_PAM, OUT_PGM, OUT_PPM, OUT_PNM, OUT_PNG, OUT_PBM, OUT_PKM, OUT_PCL, OUT_PCLM, OUT_PS, OUT_PSD): print( 'Banded operation only possible with PxM, PCL, PCLM, PS, PSD, and PNG outputs' ) sys.exit(1) if showmd5: print('Banded operation not compatible with MD5') sys.exit(1) for i in range(len(format_cs_table)): if format_cs_table[i].format_ == output_format: if out_cs == CS_UNSET: out_cs = format_cs_table[i].default_cs for j in range(len(format_cs_table[i].permitted_cs)): if format_cs_table[i].permitted_cs[j] == out_cs: break else: print('Unsupported colorspace for this format') sys.exit(1) alpha = 1 if out_cs in (CS_MONO, CS_GRAY, CS_GRAY_ALPHA): colorspace = mupdf.Colorspace(mupdf.Colorspace.Fixed_GRAY) alpha = (out_cs == CS_GRAY_ALPHA) elif out_cs in (CS_RGB, CS_RGB_ALPHA): colorspace = mupdf.Colorspace(mupdf.Colorspace.Fixed_RGB) alpha = (out_cs == CS_RGB_ALPHA) elif out_cs in (CS_CMYK, CS_CMYK_ALPHA): colorspace = mupdf.Colorspace(mupdf.Colorspace.Fixed_CMYK) alpha = (out_cs == CS_CMYK_ALPHA) elif out_cs == CS_ICC: icc_buffer = mupdf.Buffer(icc_filename) colorspace = Colorspace(mupdf.FZ_COLORSPACE_NONE, 0, None, icc_buffer) alpha = 0 else: print('Unknown colorspace!') sys.exit(1) if out_cs != CS_ICC: colorspace = mupdf.Colorspace(colorspace) else: # Check to make sure this icc profile is ok with the output format */ okay = 0 for i in range(len(format_cs_table)): if format_cs_table[i].format == output_format: for j in range(len(format_cs_table[i].permitted_cs)): x = format_cs_table[i].permitted_cs[j] if x in (CS_MONO, CS_GRAY, CS_GRAY_ALPHA): if colorspace.colorspace_is_gray(): okay = 1 elif x in (CS_RGB, CS_RGB_ALPHA): if colorspace.colorspace_is_rgb(): okay = 1 elif x in (CS_CMYK, CS_CMYK_ALPHA): if colorspace.colorspace_is_cmyk(): okay = 1 if not okay: print( 'ICC profile uses a colorspace that cannot be used for this format' ) sys.exit(1) if output_format == OUT_SVG: # SVG files are always opened for each page. Do not open "output". pass elif output and (not output.startswith('-') or len(output) >= 2) and len(output) >= 1: if has_percent_d(output): output_file_per_page = 1 else: out = mupdf.Output(output, 0) else: quiet = 1 # automatically be quiet if printing to stdout if 0: # Windows specific code to make stdout binary. if output_format not in (OUT_TEXT, OUT_STEXT, OUT_HTML, OUT_XHTML, OUT_TRACE): setmode(fileno(stdout), O_BINARY) out = mupdf.Output(mupdf.Output.Fixed_STDOUT) filename = argv[0] if not output_file_per_page: file_level_headers() timing.count = 0 timing.total = 0 timing.min = 1 << 30 timing.max = 0 timing.mininterp = 1 << 30 timing.maxinterp = 0 timing.minpage = 0 timing.maxpage = 0 timing.minfilename = "" timing.maxfilename = "" if showtime and bgprint.active: timing.total = gettime() fz_optind = 0 while fz_optind < len(argv): filename = argv[fz_optind] fz_optind += 1 files += 1 doc = mupdf.Document(filename) if doc.needs_password(): if not doc.authenticate_password(password): raise Exception(f'cannot authenticate password: {filename}') # Once document is open check for output intent colorspace oi = doc.document_output_intent() if oi: # todo: fz_document_output_intent() can return NULL, and we don't handle this. # See if we had explicitly set a profile to render if out_cs != CS_ICC: # In this case, we want to render to the output intent # color space if the number of channels is the same if oi.colorspace_n() == colorspace.colorspace_n(): colorspace = oi doc.layout_document(layout_w, layout_h, layout_em) if layer_config: apply_layer_config(doc, layer_config) if fz_optind == len(argv) or not mupdf.is_page_range(argv[fz_optind]): drawrange(doc, "1-N") if fz_optind < len(argv) and mupdf.is_page_range(argv[fz_optind]): drawrange(doc, argv[fz_optind]) fz_optind += 1 bgprint_flush() if not output_file_per_page: file_level_trailers() if out: out.close_output() out = None if showtime and timing.count > 0: if bgprint.active: timing.total = gettime() - timing.total if files == 1: print( f'total {timing.total}ms / {timing.count} pages for an average of {timing.total / timing.count}ms' ) if bgprint.active: printf( f'fastest page {timing.minpage}: {timing.mininterp}ms (interpretation) {timing.min - timing.mininterp}ms (rendering) {timing.min}ms(total)' ) print( f'slowest page {timing.maxpage}: {timing.maxinterp}ms (interpretation) {timing.max - timing.maxinterp}ms (rendering) {timing.max}ms(total)' ) else: print(f'fastest page {timing.minpage}: {timing.min}ms') print(f'slowest page {timing.maxpage}: {timing.max}ms') else: print( f'total {timing.total}ms / {timing.count} pages for an average of {timing.total / timing.count}ms in {files} files' ) print( f'fastest page {timing.minpage}: {timing.min}ms ({timing.minfilename})' ) print( f'slowest page {timing.maxpage}: {timing.max}ms ({timing.maxfilename})' ) if showmemory: print( f'Memory use total={info.total} peak={info.peak} current={info.current}' ) return errored != 0