How to create high res JPEG with Wand from binary string

左心房为你撑大大i 提交于 2019-12-05 12:18:44

Why? I need to get this into 1 high res jpeg.

The PDF contains pages that ImageMagick considers individual images in a "stack". The library provides a wand.image.Image.sequance to work with each page.

However, to append all images into a single JPEG. You can either iterate over each page & stitch them together, or call C-API's method MagickAppendImages.

from wand.image import Image
from wand.api import library
import ctypes

# Map C-API not provided by wand library.
library.MagickAppendImages.argtypes = [ctypes.c_void_p, ctypes.c_int]
library.MagickAppendImages.restype = ctypes.c_void_p

with Image(filename="path_to_document.pdf", resolution=400) as image:
    # Do all your preprocessing first
    # Ether word directly on the wand instance, or iterate over each page.
    # ...
    # To write all "pages" into a single image.
    # Reset the stack iterator.
    library.MagickResetIterator(image.wand)                    
    # Call C-API Append method.
    resource_pointer = library.MagickAppendImages(image.wand,
                                                  True)        
    # Write C resource directly to disk.
    library.MagickWriteImages(resource_pointer,                
                              "output.jpeg".encode("ASCII"),
                              False)

Update:

I need to send the jpeg to an OCR api ...

Assuming your using OpenCV's python API, you'll only need to iterate over each page, and pass the image-file data to the OCR via numpy buffers.

from wand.image import Image
import numpy
import cv2

def ocr_process(file_data_buffer):
     """ Replace with whatever your OCR-API calls for """
     mat_instance = cv2.imdecode(file_data_buffer)
     # ... work ...

source_image="path_to_document.pdf"
with Image(filename=source_image, resolution=400) as img:
    for page in img.sequence:
        file_buffer = numpy.asarray(bytearray(page.make_blob("JPEG")),
                                    dtype=numpy.uint8)
        ocr_process(file_buffer)

so I was wondering if I could write the output to a file like object

Don't assume that python "image" objects (or underlining C structures) from different libraries are comparable with each other.

Without knowing the OCR api, I can't help you past the part, but I can suggest one of the following...

  • Use temporary intermediate files. (slower I/O, but easier to learn/develop/debug)

    with Image(filename=INPUT_PATH) as img:
        # work
        img.save(filename=OUTPUT_PATH)
    # OCR work on OUTPUT_PATH
    
  • Use file descriptors if the OCR API supports it. (Same as above)

    with open(INPUT_PATH, 'rb') as fd:
        with Image(file=fd) as img:
            # work
            # OCR work ???
    
  • Use blobs. (faster I/O but need a lot more memory)

    buffer = None
    with Image(filename=INPUT_PATH) as img:
        # work
        buffer = img.make_blob(FORMAT)
    if buffer:
        # OCR work ???
    

Even More Updates

Wrapping all the comments together, a solution might be...

from wand.image import Image
from wand.api import library
import ctypes
import requests

# Map C-API not provided by wand library.
library.MagickAppendImages.argtypes = [ctypes.c_void_p, ctypes.c_int]
library.MagickAppendImages.restype = ctypes.c_void_p

with Image(filename='path_to_document.pdf', resolution=400) as image:
    # ... Do pre-processing ...
    # Reset the stack iterator.
    library.MagickResetIterator(image.wand)
    # Call C-API Append method.
    resource_pointer = library.MagickAppendImages(image.wand, True)
    # Convert to JPEG.
    library.MagickSetImageFormat(resource_pointer, b'JPEG')
    # Create size sentinel.
    length = ctypes.c_size_t()
    # Write image blob to memory.
    image_data_pointer = library.MagickGetImagesBlob(resource_pointer,
                                                     ctypes.byref(length))
    # Ensure success
    if image_data_pointer and length.value:
        # Create buffer from memory address
        payload = ctypes.string_at(image_data_pointer, length.value)
        # Define local filename.
        payload_filename = 'my_hires_image.jpg'
        # Post payload as multipart encoded image file with filename.
        requests.post(THE_URL, files={'file': (payload_filename, payload)})

What about something like:

ok = Image(filename=file_path, resolution=400)
with ok.transform('2000x1000', '100%') as image:
   image.compression_quality = 100
   image.save()

or:

with ok.resize(2000, 1000)

related:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!