wmjordan/PDFPatcher · error · MuException

无法渲染页面:{(page.PageNumber + 1).ToText()}

Error message

无法渲染页面:{(page.PageNumber + 1).ToText()}

What it means

Thrown as a MuException when MuPDF's Pixmap.Create returns null while allocating the output pixmap for a page render in InternalRenderPage. Pixmap.Create fails when the computed BBox has non-positive dimensions after rounding, when the requested area is too large to allocate, or when the resolved colorspace is invalid. The message reports the 1-based page number (page.PageNumber + 1). Note this fires only at allocation time; later drawing errors surface from page.RunContents/RunAnnotations.

Source

Thrown at App/Processor/Mupdf/MuPDFExtensions.cs:151

		return StringBuilderCache.GetStringAndRelease(sb);
	}

	#region 渲染页面
	public static Bitmap RenderBitmapPage(this Page page, int width, int height, ImageRendererOptions options, Cookie cookie) {
		using var pix = InternalRenderPage(page, width, height, options, cookie);
		return pix?.ToBitmap(options);
	}

	static Pixmap InternalRenderPage(Page page, int width, int height, ImageRendererOptions options, Cookie cookie) {
		var b = page.Bound;
		if (b.Width == 0 || b.Height == 0) {
			return null;
		}
		var ctm = CalculateMatrix(page, width, height, options);
		var bbox = width > 0 && height > 0 ? new BBox(0, 0, width, height) : b.Transform(ctm).Round();

		var pix = Pixmap.Create(((ColorspaceKind)options.ColorSpace).SubstituteDefault(ColorspaceKind.RGB), bbox)
			?? throw new MuException($"无法渲染页面:{(page.PageNumber + 1).ToText()}");
		pix.Clear(0xFF);
		try {
			using var dev = Device.NewDraw(pix, Matrix.Identity);
			if (options.LowQuality) {
				dev.EnableDeviceHints(DeviceHints.DontInterpolateImages | DeviceHints.NoCache);
			}
			if (cookie.IsCancellationPending) {
				goto CANCEL;
			}
			page.RunContents(dev, ctm, cookie);
			if (!options.HideAnnotations) {
				page.RunAnnotations(dev, ctm, cookie);
				page.RunWidgets(dev, ctm, cookie);
			}
			dev.Close();

			if (cookie.IsCancellationPending) {
				goto CANCEL;

View on GitHub (pinned to 4782bbd9ad)

Solutions

  1. Clamp width/height and DPI before calling RenderBitmapPage so the resulting pixmap (width*height*components bytes) stays within memory limits.
  2. If you pass height==0 (as Worker.cs does), verify the page Bound is non-degenerate and that ImageWidth * (Bound.Height/Bound.Width) is a positive, finite number.
  3. Wrap the RenderBitmapPage call in try/catch(MuException) and treat the page as unrenderable (skip / show placeholder) rather than aborting the batch.
  4. Validate that options.ColorSpace maps to a real ColorspaceKind before rendering; pass a known colorspace (RGB/Gray/BGR).

Example fix

// before
using var bmp = p.RenderBitmapPage(options.ImageWidth, 0, options, cookie);

// after
var bound = p.Bound;
var h = bound.Width > 0 ? (int)Math.Round(options.ImageWidth * bound.Height / bound.Width) : 0;
if (options.ImageWidth <= 0 || h <= 0 || (long)options.ImageWidth * h > 100_000_000) {
    Tracker.TraceMessage($"跳过无法渲染的页面:尺寸异常 ({options.ImageWidth}x{h})");
    continue;
}
using var bmp = p.RenderBitmapPage(options.ImageWidth, h, options, cookie);
Defensive patterns

Strategy: try-catch

Validate before calling

var bound = page.Bound;
if (bound.Width <= 0 || bound.Height <= 0) return null; // degenerate page
int w = width > 0 ? width : (int)Math.Round(bound.Width * options.ScaleRatio * options.Dpi / 72);
int h = height > 0 ? height : (int)Math.Round(bound.Height * options.ScaleRatio * options.Dpi / 72);
if (w <= 0 || h <= 0 || (long)w * h > 50_000_000) return null; // too small or too large to allocate

Try / catch

Bitmap bmp = null;
try {
    bmp = page.RenderBitmapPage(width, height, options, cookie);
}
catch (MuException ex) when (!cookie.IsCancellationPending) {
    Tracker.TraceMessage($"渲染第 {page.PageNumber + 1} 页失败:{ex.Message}");
    bmp = null; // skip / placeholder
}
if (bmp == null && cookie.IsCancellationPending) return null;

Prevention

When it happens

Trigger: RenderBitmapPage(page,width,height,options,cookie) -> InternalRenderPage -> Pixmap.Create(colorspace, bbox) returns null. Two bbox paths: when width>0 && height>0 the bbox is literally (0,0,width,height) so an enormous explicit width/height causes allocation failure; otherwise bbox = b.Transform(ctm).Round() which can round to a degenerate rectangle. Worker.cs calls RenderBitmapPage(options.ImageWidth, 0, ...) so height==0 forces the transform-round path, and a near-zero or negative rounded bbox yields null.

Common situations: Rendering at very high DPI or very large explicit ImageWidth against a big page (pixmap exceeds available memory); a page whose MediaBox/CropBox is tiny or rotated such that the scaled+rounded bbox collapses to zero area; corrupted page geometry where Bound.Width/Height passed the early guard but the transform still degenerates; passing a colorspace option value outside the valid ColorspaceKind enum so SubstituteDefault cannot resolve it.

Related errors


AI-assisted analysis of wmjordan/PDFPatcher@4782bbd9ad (2026-08-13). Data as JSON: /api/errors/8625ddc4f0305227. Report an issue: GitHub.