{"record":{"id":"e7095eb5839df3f0","repo":"docusealco/docuseal","slug":"failed-to-get-image-matrix","errorCode":null,"errorMessage":"Failed to get image matrix","messagePattern":"Failed to get image matrix","errorType":"exception","errorClass":"Pdfium::PdfiumError","httpStatus":null,"severity":"error","filePath":"lib/pdfium.rb","lineNumber":1434,"sourceCode":"      bounds_ptrs = Array.new(4) { FFI::MemoryPointer.new(:float) }\n      matrix_ptr = FFI::MemoryPointer.new(:float, 6)\n\n      Pdfium.FPDFPage_CountObjects(@page_ptr).times do |index|\n        object_ptr = Pdfium.FPDFPage_GetObject(@page_ptr, index)\n\n        next if object_ptr.null?\n        next unless Pdfium.FPDFPageObj_GetType(object_ptr) == FPDF_PAGEOBJ_IMAGE\n        next if Pdfium.FPDFPageObj_GetBounds(object_ptr, *bounds_ptrs).zero?\n\n        obj_left, obj_bottom, obj_right, obj_top = bounds_ptrs.map(&:read_float)\n\n        overlapping = rect_bounds.select do |left, bottom, right, top|\n          obj_left < right && obj_right > left && obj_bottom < top && obj_top > bottom\n        end\n\n        next if overlapping.empty?\n\n        raise PdfiumError, 'Failed to get image matrix' if Pdfium.FPDFPageObj_GetMatrix(object_ptr, matrix_ptr).zero?\n\n        matrix = matrix_ptr.read_array_of_float(6)\n\n        next if ((matrix[0] * matrix[3]) - (matrix[1] * matrix[2])).abs < 1e-9\n\n        bitmap = extract_image_bitmap(object_ptr)\n        pixel_rects = image_pixel_rects(matrix, bitmap[:width], bitmap[:height], overlapping)\n\n        next if pixel_rects.empty?\n\n        jpeg = yield(bitmap, pixel_rects)\n\n        load_image_jpeg(object_ptr, jpeg) if jpeg\n      end\n    end\n\n    def extract_image_bitmap(object_ptr)\n      bitmap_ptr = Pdfium.FPDFImageObj_GetBitmap(object_ptr)","sourceCodeStart":1416,"sourceCodeEnd":1452,"githubUrl":"https://github.com/docusealco/docuseal/blob/004a22c1c88109c7ba0b567df011a8cb13894001/lib/pdfium.rb#L1416-L1452","documentation":"Raised in redact_image_objects when FPDFPageObj_GetMatrix returns 0 for an image object that overlaps a redaction rect. The matrix is needed to map pixel-space redaction regions back onto the image, so a zero return stops pixel-level image redaction for that object. There is no check_last_error; the failure is rare and usually means a malformed image object or a pdfium build gap for that object variant.","triggerScenarios":"Calling redact with an image_processor block on pages containing images with missing or broken transformation matrices: inline images, unusual XObject dictionaries, generator-specific image objects.","commonSituations":"Image-redaction features on scanned or fax-derived PDFs and PDFs from niche producers.","solutions":["Rescue per image and skip it; text and rect redaction still apply","Fall back to covering the overlapping area with an opaque drawn rect","Pre-process the PDF through ghostscript to normalize image XObjects","Update libpdfium"],"exampleFix":"# before\npage.redact(rects) { |bitmap, pixel_rects| blacken(bitmap, pixel_rects) }\n\n# after - one bad image must not kill the page\nbegin\n  page.redact(rects) { |bitmap, pixel_rects| blacken(bitmap, pixel_rects) }\nrescue Pdfium::PdfiumError => e\n  raise unless e.message == 'Failed to get image matrix'\n  page.redact(rects) # retry without image processor: rects still cover the area\nend","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"begin\n  page.redact(rects) { |bitmap, pr| pixel_blacken(bitmap, pr) }\nrescue Pdfium::PdfiumError => e\n  raise unless e.message == 'Failed to get image matrix'\n  page.redact(rects) # rect-cover fallback still hides the region\nend","preventionTips":["Treat pixel-level image redaction as best-effort; always draw the cover rect as the safety net","Test image redaction against faxed and stencil-heavy documents","Update libpdfium alongside application releases"],"tags":["pdfium","redaction","images","pdf-objects","ruby"],"backgroundTag":"pdf-object-manipulation-failed","analyzedSha":"004a22c1c88109c7ba0b567df011a8cb13894001","analyzedAt":"2026-08-21T13:38:23.343Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}