I am trying to convert a pdf to a docx using pdf2docx. The code is really simple, as I am just reading and trying to convert a pdf:
from pdf2docx import Converter
pdf_dir = 'pdf_to_convert.pdf'
pdf_dir = 'converted_document.docx'
cv = Converter(pdf_dir)
cv.convert(docx_dir, start = 0, end = None)
cv.close()
However, I get the following error stack:
[INFO] Start to convert pdf_to_convert.pdf
[INFO] [1/4] Opening document...
[INFO] [2/4] Analyzing document...
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [91], in <cell line: 2>()
1 cv = Converter(pdf_dir)
----> 2 cv.convert(docx_dir, start = 0, end = None)
3 cv.close()
File ~/.local/lib/python3.8/site-packages/pdf2docx/converter.py:329, in Converter.convert(self, docx_filename, start, end, pages, **kwargs)
327 self._convert_with_multi_processing(docx_filename, start, end, **settings)
328 else:
--> 329 self.parse(start, end, pages, **settings).make_docx(docx_filename, **settings)
331 logging.info('Terminated in %.2fs.', perf_counter()-t0)
File ~/.local/lib/python3.8/site-packages/pdf2docx/converter.py:112, in Converter.parse(self, start, end, pages, **kwargs)
100 def parse(self, start:int=0, end:int=None, pages:list=None, **kwargs):
101 '''Parse pages in three steps:
102 * open PDF file with ``PyMuPDF``
103 * analyze whole document, e.g. page section, header/footer and margin
(...)
110 kwargs (dict, optional): Configuration parameters.
111 '''
--> 112 return self.load_pages(start, end, pages) \
113 .parse_document(**kwargs) \
114 .parse_pages(**kwargs)
File ~/.local/lib/python3.8/site-packages/pdf2docx/converter.py:153, in Converter.parse_document(self, **kwargs)
149 '''Step 2 of converting process: analyze whole document, e.g. page section,
150 header/footer and margin.'''
151 logging.info(self._color_output('[2/4] Analyzing document...'))
--> 153 self._pages.parse(self.fitz_doc, **kwargs)
154 return self
File ~/.local/lib/python3.8/site-packages/pdf2docx/page/Pages.py:37, in Pages.parse(self, fitz_doc, **settings)
35 # init and extract data from PDF
36 raw_page = RawPageFactory.create(page_engine=fitz_doc[page.id], backend='PyMuPDF')
---> 37 raw_page.restore(**settings)
39 # check if any words are extracted since scanned pdf may be directed
40 if not words_found and raw_page.raw_text.strip():
File ~/.local/lib/python3.8/site-packages/pdf2docx/common/share.py:226, in debug_plot.<locals>.wrapper.<locals>.inner(*args, **kwargs)
224 def inner(*args, **kwargs):
225 # execute function
--> 226 objects = func(*args, **kwargs)
228 # check if plot page
229 page = args[0] # BasePage object
File ~/.local/lib/python3.8/site-packages/pdf2docx/page/RawPage.py:66, in RawPage.restore(self, **settings)
63 @debug_plot('Source Text Blocks')
64 def restore(self, **settings):
65 '''Initialize layout extracted with ``PyMuPDF``.'''
---> 66 raw_dict = self.extract_raw_dict(**settings)
67 super().restore(raw_dict)
68 return self.blocks
File ~/.local/lib/python3.8/site-packages/pdf2docx/page/RawPageFitz.py:36, in RawPageFitz.extract_raw_dict(self, **settings)
33 image_blocks = self._preprocess_images(**settings)
34 raw_dict['blocks'].extend(image_blocks)
---> 36 shapes, images = self._preprocess_shapes(**settings)
37 raw_dict['shapes'] = shapes
38 raw_dict['blocks'].extend(images)
File ~/.local/lib/python3.8/site-packages/pdf2docx/page/RawPageFitz.py:124, in RawPageFitz._preprocess_shapes(self, **settings)
122 '''Identify iso-oriented paths and convert vector graphic paths to pixmap.'''
123 paths = self._init_paths(**settings)
--> 124 return paths.to_shapes_and_images(
125 settings['min_svg_gap_dx'],
126 settings['min_svg_gap_dy'],
127 settings['min_svg_w'],
128 settings['min_svg_h'],
129 settings['clip_image_res_ratio'])
File ~/.local/lib/python3.8/site-packages/pdf2docx/shape/Paths.py:127, in Paths.to_shapes_and_images(self, min_svg_gap_dx, min_svg_gap_dy, min_w, min_h, clip_image_res_ratio)
124 for (bbox, inner_bboxes), paths in zip(groups, group_paths):
125 # all iso-oriented paths -> it's a table, but might contain svg in cell as well
126 if paths.is_iso_oriented:
--> 127 iso_shapes.extend(paths.to_shapes())
128 for svg_bbox in inner_bboxes:
129 images.append(ie.clip_page_to_dict(fitz.Rect(svg_bbox), clip_image_res_ratio))
File ~/.local/lib/python3.8/site-packages/pdf2docx/shape/Paths.py:72, in Paths.to_shapes(self)
69 for path in self._instances:
70 # consider iso-oriented path only
71 if not path.is_iso_oriented: continue
---> 72 shapes.extend(path.to_shapes())
73 return shapes
File ~/.local/lib/python3.8/site-packages/pdf2docx/shape/Path.py:338, in Path.to_shapes(self)
336 if self.is_fill:
337 fill_color = self.raw.get('fill', None)
--> 338 iso_shapes.extend(self._to_fills(fill_color))
340 return iso_shapes
File ~/.local/lib/python3.8/site-packages/pdf2docx/shape/Path.py:366, in Path._to_fills(self, color)
364 fills = []
365 for segments in self.items:
--> 366 fills.append(segments.to_fill(color))
367 return fills
File ~/.local/lib/python3.8/site-packages/pdf2docx/shape/Path.py:228, in Segments.to_fill(self, color)
217 def to_fill(self, color:list):
218 """Convert segment closed area to a ``Fill`` dict.
219
220 Args:
(...)
224 dict: ``Fill`` dict.
225 """
226 return {
227 'bbox' : list(self.bbox),
--> 228 'color': rgb_value(color)
229 }
File ~/.local/lib/python3.8/site-packages/pdf2docx/common/share.py:170, in rgb_value(components)
168 def rgb_value(components:list):
169 '''Gray/RGB/CMYK mode components to color value.'''
--> 170 num = len(components)
171 # CMYK mode
172 if num==4:
TypeError: object of type 'NoneType' has no len()
I am pretty sure it happens because my pdf has lots of shapes, backgrounds, images and tables. But how could I circumvent it? I do not really care if the results are poor, as long as I get something. Also I find it strange that the conversion fails because of some coloring error (see traceback).
Thanks!
I have tried to change the default parameters of Convert(), to no avail. I have also tried to reduce the size of the pdf by compressing it, but compression does not manage to reduce the size.
So, how I solved it: I have no idea what triggers the error. My intuition is that it has something to do with the colouring of tables. Well, the error stems from the function rgb_value(components:list). So what I did is edit that function so that it always returns 4278189825 (encoding for color white). It worked for my purposes, at least.