The ctypes-based simple ImageMagick binding for Python

Overview

https://docs.wand-py.org/en/latest/_static/wand.png

Wand

Wand is a ctypes-based simple ImageMagick binding for Python, supporting 2.7, 3.3+, and PyPy. All functionalities of MagickWand API are implemented in Wand.

You can install the package from PyPI by using pip:

$ pip install Wand

Or would you like to enjoy the bleeding edge? Check out the head revision of the source code from the GitHub repository:

$ git clone git://github.com/emcconville/wand.git
$ cd wand/
$ python setup.py install

Docs

Recent version
https://docs.wand-py.org/
Development version

https://docs.wand-py.org/en/latest/

Documentation Status

Community

Website
http://wand-py.org/
GitHub
https://github.com/emcconville/wand
Package Index (Cheeseshop)

https://pypi.python.org/pypi/Wand

Latest PyPI version
Discord
https://discord.gg/BWQ25wB
Stack Overflow tag (Q&A)
http://stackoverflow.com/questions/tagged/wand
Continuous Integration (Travis CI)

https://travis-ci.org/emcconville/wand

Build Status
Continuous Integration (GitHub Actions)

https://github.com/emcconville/wand/actions

Build Status
Code Coverage

https://coveralls.io/r/emcconville/wand

https://coveralls.io/repos/github/emcconville/wand/badge.svg?branch=master
Comments
  • MagickWand shared library not found

    MagickWand shared library not found

    Exception information:

    Traceback (most recent call last):
      File "testss.py", line 1, in <module>
        from wand.image import Image
      File "/Users/hit9/spam/testfirfffff/venv/lib/python2.7/site-packages/wand/image.py", line 20, in <module>
        from .api import MagickPixelPacket, libc, libmagick, library
      File "/Users/hit9/spam/testfirfffff/venv/lib/python2.7/site-packages/wand/api.py", line 156, in <module>
        'Try to install:\n  ' + msg)
    ImportError: MagickWand shared library not found.
    You probably had not installed ImageMagick library.
    Try to install:
      brew install imagemagick
    

    I am using OSX10.8

    And I installed imagemagick via brew:

    $ brew install imagemagick
    Warning: imagemagick-6.8.6-3 already installed
    

    And here is my result run ls in /usr/local/lib :

    $ ls -l  /usr/local/lib/ | grep libMagick
    lrwxr-xr-x   1 hit9  admin       59 Aug 22 11:04 libMagick++-6.Q16.1.dylib -> ../Cellar/imagemagick/6.8.6-3/lib/libMagick++-6.Q16.1.dylib
    lrwxr-xr-x   1 hit9  admin       57 Aug 22 11:04 libMagick++-6.Q16.dylib -> ../Cellar/imagemagick/6.8.6-3/lib/libMagick++-6.Q16.dylib
    lrwxr-xr-x   1 hit9  admin       54 Aug 22 11:04 libMagick++-6.Q16.la -> ../Cellar/imagemagick/6.8.6-3/lib/libMagick++-6.Q16.la
    lrwxr-xr-x   1 hit9  admin       61 Aug 22 11:04 libMagickCore-6.Q16.1.dylib -> ../Cellar/imagemagick/6.8.6-3/lib/libMagickCore-6.Q16.1.dylib
    lrwxr-xr-x   1 hit9  admin       59 Aug 22 11:04 libMagickCore-6.Q16.dylib -> ../Cellar/imagemagick/6.8.6-3/lib/libMagickCore-6.Q16.dylib
    lrwxr-xr-x   1 hit9  admin       56 Aug 22 11:04 libMagickCore-6.Q16.la -> ../Cellar/imagemagick/6.8.6-3/lib/libMagickCore-6.Q16.la
    lrwxr-xr-x   1 hit9  admin       61 Aug 22 11:04 libMagickWand-6.Q16.1.dylib -> ../Cellar/imagemagick/6.8.6-3/lib/libMagickWand-6.Q16.1.dylib
    lrwxr-xr-x   1 hit9  admin       59 Aug 22 11:04 libMagickWand-6.Q16.dylib -> ../Cellar/imagemagick/6.8.6-3/lib/libMagickWand-6.Q16.dylib
    lrwxr-xr-x   1 hit9  admin       56 Aug 22 11:04 libMagickWand-6.Q16.la -> ../Cellar/imagemagick/6.8.6-3/lib/libMagickWand-6.Q16.la
    lrwxr-xr-x   1 hit9  admin       42 Aug 22 11:42 libMagickWand.dylib -> /usr/local/lib/libMagickWand-6.Q16.1.dylib
    

    I noticed there was a few issues similar to this. But I tried the solutions, and issue still exists. Hope your solution, thanks.

    bug 
    opened by hit9 37
  • mountain lion install problem

    mountain lion install problem

    Hello,

    Maybe I'm missing a step, but I got the same result on multiple machines:

    sudo port install ImageMagick => successful sudo easy_install wand => successful

    then in python interactive mode: from wand.image import Image

    throws error:

    Traceback (most recent call last): File "", line 1, in File "build/bdist.macosx-10.8-intel/egg/wand/image.py", line 19, in File "build/bdist.macosx-10.8-intel/egg/wand/api.py", line 266, in ImportError: MagickWand shared library not found or incompatible

    Am I missing a step?

    Thanks!

    bug dist 
    opened by scottgwald 28
  • Refactor C-API loading, and ImageMagick 7 Support

    Refactor C-API loading, and ImageMagick 7 Support

    This is a work-in-progress, and should not be merged. I'm opening this pull request for greater visibility, and seek testing help.

    This merge request reworked all C-API method mappings into a directory/module structure mimicking ImageMagick's C headers.

    The primary benefit was to reduce the complexity of the unorganized wand.api.library, and to incorporate all MagickWand 6/7 methods.

    The secondary goal is to include ImageMagick 7 support. For the most part, this has been completed with a few minor TODOs.

    Overview of Changes

    • C-API methods have been moved to the following structure.
      wand.api.cdefs
                    .core              All MagickCore definitions.
                    .drawing_wand      <drawing-wand.h> methods.
                    .magick_image      <magick-image.h> methods.
                    .magick_property   <magick-property.h> methods.
                    .magick_wand       <magick-wand.h> methods.
                    .pixel_iterator    <pixel-iterrator.h> methods.
                    .pixel_wand        <pixel-wand.h> methods.
                    .structures        Collection of ctypes.Structure definitions.
                    .wandtypes         Ctype portability wrappers like `c_magick_char_p'
      
    • PixelInfo replaces MagickPixelPacket
    • HDRI support
    • Implemented MagickSetImageChannelMask to replace Magick{XXXX}Channel methods.

    Outstanding Items

    • [x] Rewrite wand.image.Image.transform as MagickTransformImage has been removed in IM 7.
    • [x] Revisite all methods/documentation for MagickCompositeImage. IM 7 is now more "aware" of dynamic channels; so naturally, behavior around Image.composite_channel, Image.composite, Image.transparentize, and Image.watermark should be reviewed.
    • [x] Same for Image.alpha_channel property.
    • [x] Rewrite regressions test marked XFAIL
    • [ ] Documentation. Including all "?.?.?" version placeholders.

    Help with...

    I personally have run out of free time to finish this effort, and would love some help of the following.

    • Performance & Architecture Design. With all MagickWand methods mapped, is wand load time traumatically affected? Is python-caching working in an optimized manner?
    • Regression testing & CI. Ensure ImageMagick-6 continues to work as expected, and/or update Travis builds to include ImageMagick-7 + delegates.
    opened by emcconville 24
  • Memory leak with sequences

    Memory leak with sequences

    The following code eats all your memory in a matter of seconds:

    from wand.color import Color
    from wand.image import Image
    
    while True:
        ri = Image(width=1000, height=1000, background=Color('red'))
        bi = Image(width=1000, height=1000, background=Color('blue'))
        gi = Image(width=1000, height=1000, background=Color('green'))
    
        container = Image(width=1000, height=1000)
        container.sequence.append(ri)
        container.sequence.append(bi)
        container.sequence.append(gi)
    
        container.format = 'gif'
        container.save(filename='/dev/null')
    
        ri.destroy()
        bi.destroy()
        gi.destroy()
        for frame in container.sequence:
            frame.destroy()
        container.destroy()
    
        print('saved')
    

    Is it a bug? How can I destroy all the images so the memory is freed? (I'm supposedly destroying them all, but it's not working)

    bug 
    opened by wodim 21
  • Fully integrate DrawingWand C-API

    Fully integrate DrawingWand C-API

    Originally a PU for adding a few methods I needed for whatever project, this drawing_pu turned into a general effort to integrate all ImageMagick's drawing wand methods. This request is open for code-review, feedback, and improved documents.

    Drawing API Integration Status

    • [x] ClearDrawingWand
    • [x] CloneDrawingWand
    • [x] DestroyDrawingWand
    • [x] DrawAffine
    • [x] DrawAnnotation
    • [x] DrawArc
    • [x] DrawBezier
    • [x] DrawCircle
    • [x] DrawClearException
    • [x] DrawComposite
    • [x] DrawColor
    • [x] DrawComment
    • [x] DrawEllipse
    • [x] DrawGetBorderColor
    • [x] DrawGetClipPath
    • [x] DrawGetClipRule
    • [x] DrawGetClipUnits
    • [x] DrawGetException
    • [ ] DrawGetExceptionType (Never needed as python manages exceptions)
    • [x] DrawGetFillColor
    • [x] DrawGetFillOpacity
    • [x] DrawGetFillRule
    • [x] DrawGetFont
    • [x] DrawGetFontFamily
    • [x] DrawGetFontResolution
    • [x] DrawGetFontSize
    • [x] DrawGetFontStretch
    • [x] DrawGetFontStyle
    • [x] DrawGetFontWeight
    • [x] DrawGetGravity
    • [x] DrawGetOpacity
    • [x] DrawGetStrokeAntialias
    • [x] DrawGetStrokeColor
    • [x] DrawGetStrokeDashArray
    • [x] DrawGetStrokeDashOffset
    • [x] DrawGetStrokeLineCap
    • [x] DrawGetStrokeLineJoin
    • [x] DrawGetStrokeMiterLimit
    • [x] DrawGetStrokeOpacity
    • [x] DrawGetStrokeWidth
    • [x] DrawGetTextAlignment
    • [x] DrawGetTextAntialias
    • [x] DrawGetTextDecoration
    • [x] DrawGetTextDirection
    • [x] DrawGetTextEncoding
    • [x] DrawGetTextKerning
    • [x] DrawGetTextInterlineSpacing
    • [x] DrawGetTextInterwordSpacing
    • [x] DrawGetVectorGraphics
    • [x] DrawGetTextUnderColor
    • [x] DrawLine
    • [x] DrawMatte
    • [x] DrawPathClose
    • [x] DrawPathCurveToAbsolute
    • [x] DrawPathCurveToRelative
    • [x] DrawPathCurveToQuadraticBezierAbsolute
    • [x] DrawPathCurveToQuadraticBezierRelative
    • [x] DrawPathCurveToQuadraticBezierSmoothAbsolute
    • [x] DrawPathCurveToQuadraticBezierSmoothRelative
    • [x] DrawPathCurveToSmoothAbsolute
    • [x] DrawPathCurveToSmoothRelative
    • [x] DrawPathEllipticArcAbsolute
    • [x] DrawPathEllipticArcRelative
    • [x] DrawPathFinish
    • [x] DrawPathLineToAbsolute
    • [x] DrawPathLineToRelative
    • [x] DrawPathLineToHorizontalAbsolute
    • [x] DrawPathLineToHorizontalRelative
    • [x] DrawPathLineToVerticalAbsolute
    • [x] DrawPathLineToVerticalRelative
    • [x] DrawPathMoveToAbsolute
    • [x] DrawPathMoveToRelative
    • [x] DrawPathStart
    • [x] DrawPoint
    • [x] DrawPolygon
    • [x] DrawPolyline
    • [x] DrawPopClipPath
    • [x] DrawPopDefs
    • [x] DrawPopPattern
    • [x] DrawPushClipPath
    • [x] DrawPushDefs
    • [x] DrawPushPattern
    • [x] DrawRectangle
    • [x] DrawResetVectorGraphics
    • [x] DrawRotate
    • [x] DrawRoundRectangle (Integrate with rectangle method)
    • [x] DrawScale
    • [x] DrawSetBorderColor
    • [x] DrawSetClipPath
    • [x] DrawSetClipRule
    • [x] DrawSetClipUnits
    • [x] DrawSetFillColor
    • [x] DrawSetFillOpacity
    • [x] DrawSetFontResolution
    • [x] DrawSetOpacity
    • [x] DrawSetFillPatternURL
    • [x] DrawSetFillRule
    • [x] DrawSetFont
    • [x] DrawSetFontFamily
    • [x] DrawSetFontSize
    • [x] DrawSetFontStretch
    • [x] DrawSetFontStyle
    • [x] DrawSetFontWeight
    • [x] DrawSetGravity
    • [x] DrawSetStrokeColor
    • [x] DrawSetStrokePatternURL
    • [x] DrawSetStrokeAntialias
    • [x] DrawSetStrokeDashArray
    • [x] DrawSetStrokeDashOffset
    • [x] DrawSetStrokeLineCap
    • [x] DrawSetStrokeLineJoin
    • [x] DrawSetStrokeMiterLimit
    • [x] DrawSetStrokeOpacity
    • [x] DrawSetStrokeWidth
    • [x] DrawSetTextAlignment
    • [x] DrawSetTextAntialias
    • [x] DrawSetTextDecoration
    • [x] DrawSetTextDirection
    • [x] DrawSetTextEncoding
    • [x] DrawSetTextKerning
    • [x] DrawSetTextInterlineSpacing
    • [x] DrawSetTextInterwordSpacing
    • [x] DrawSetTextUnderColor
    • [x] DrawSetVectorGraphics
    • [x] DrawSkewX
    • [x] DrawSkewY
    • [x] DrawTranslate
    • [x] DrawSetViewbox
    • [x] IsDrawingWand
    • [x] NewDrawingWand
    • [ ] ~~~PeekDrawingWand~~~ (requires building DrawInfo struct, and this is not helpful until other drawing-info methods are exposed to the C-API)
    • [x] PopDrawingWand
    • [x] PushDrawingWand

    Original PU Overview

    • Created PointInfo struct reference in API type casting.
    • Assigned / mapped arguments for wand library methods.
    • Completed initial unit test & documentation.

    Examples

    Drawing.polygon

    with Image(filename="crosshatch.png") as img:
        with Drawing() as draw:
            draw.fill_color = Color("#fff")
            draw.stroke_color = Color("#000")
            draw.stroke_width = 2
            points = [(5,5),(45,40),(45,10),(5,45)]
            draw.polygon(points)
            draw.draw(img)
            img.save(filename="polygon.png")
    

    Drawing.polygon

    Drawing.polyline

    with Image(filename="crosshatch.png") as img:
        with Drawing() as draw:
            draw.fill_color = Color("transparent")
            draw.stroke_color = Color("#000")
            draw.stroke_width = 2
            points = [(5,5),(45,40),(45,10),(5,45)]
            draw.polyline(points)
            draw.draw(img)
            img.save(filename="polyline.png")
    

    Drawing.polyline

    Drawing.bezier

    with Image(filename="crosshatch.png") as img:
        with Drawing() as draw:
            draw.fill_color = Color("transparent")
            draw.stroke_color = Color("#000")
            draw.stroke_width = 2
            points = [(5,5), (0,50), (50,0), (45,45)]
            draw.bezier(points)
            draw.draw(img)
            img.save(filename="bezier.png")
    

    Drawing.bezier

    opened by emcconville 20
  • Support color map / palette manipulation

    Support color map / palette manipulation

    The "colorMap" and "colorMapSize" attributes of the Image class are not available for reading / writing (or I missed them in the docs) so you can't get / set the palette of an image.

    opened by HorstBaerbel 17
  • Inconsistent behavior when dealing with alpha channels and tiffs

    Inconsistent behavior when dealing with alpha channels and tiffs

    This is related to #468 so if you want to close this and re-open that, that's fine by me.

    I'm using wand 0.6.2, and when I use the PDF still attached to #468 , and run that example code I posted, (I tried both setting alpha_channel to off and False) I get something far weirder (see attached). The original fix that was posted to stackoverflow also no longer works (but I think that's expected because you now handle it internally).

    Some sample code:

    This works:

    
    with Image(filename='5-page-pdf.pdf') as img:
        img.type = "grayscale"
        img.format = "tiff"
        img.compression = "lzw"
        img.alpha_channel = 'off'
        img.save(filename="test.tiff")
    
    

    This does not:

    
    with Image(filename='5-page-pdf.pdf') as img:
        img.type = "grayscale"
        img.format = "tiff"
        img.compression = "lzw"
        img.alpha_channel = False
        img.save(filename="test.tiff")
    
    

    I've noticed that some TIFF viewers enhance images more than others, the Preview application on macOS is pretty barebones and doesn't do anything to make the TIFF nicer, so the difference between the working and non working examples is that the non working example only has the first and last page with the alpha channel correctly set to off. (When Windows loads the TIFF using Windows Photo Viewer, it looks correct, but I believe its not showing the raw tiff). Not a major deal, I can just use "off", I just expected False to work based on the docs.

    This also does not work, but the result is far weirder and likely a bug (TIFF output also attached):

    
    blob = Image(filename='5-page-pdf.pdf').make_blob()
    
    with Image(blob=blob) as img:
        img.type = "grayscale"
        img.format = "tiff"
        img.compression = "lzw"
        img.alpha_channel = 'off'
        img.save(filename="test.tiff")
    
    

    As you can see, the alpha channel is removed, but each page is scaled down and repeated 3 times horizontally on its respective page. Very bizarre

    The tiff showing the difference between "off" and False. (The version using off looks correct so I didnt bother posting it).

    The tiff showing the result of loading an image as a blob and then trying to remove the alpha channel

    doc upstream-issue 
    opened by bmoscon 16
  • No way to change image colorspace

    No way to change image colorspace

    I am using wand to convert a CMYK PDF to an sRGB png.

    Here's a sample CMYK PDF: https://dl.dropboxusercontent.com/u/15672/dndel/in.pdf (sorry, github doesn't allow me to add a pdf directly to an issue).

    When I use imagemagick on the command line:

    convert in.pdf out1.png
    

    I get: out1

    which is bad. Instead, I have to change the colorspace, so if I do

    convert -colorspace sRGB in.pdf out2.png
    

    I get: out2

    which is good.

    As far as I can tell, there's no way to set colorspace in Wand.

    When I run

    from wand.image import Image
    
    with Image(filename='in.pdf') as img:
        with img.convert('png') as converted:
            converted.save(filename='out3.png')
    

    I get the same as the first convert: out3

    It would be nice if Wand supported colorspace-- many PDFs and other print documents use CMYK.

    bug 
    opened by srubin 16
  • Fix travis tests

    Fix travis tests

    I think these requirements conflict with the setup.py ones.

    https://github.com/pypa/pip/issues/1197 <- I added the test deps to extras_require so pip install -e .[test] works as expected.

    opened by orf 15
  • Support numpy's __array_interface__

    Support numpy's __array_interface__

    It would be nice if you could provide a wand image to numpy.asarray() and have it automatically create a properly sized and shaped numpy matrix.

    Right now if you try to pass an image in, things bog down and 100% CPU is used. I suspect this is due to the iteration interface on wand.image.Image creating a Color object for every pixel.

    To support this, Wand would need to have a __array_interface__ property which returned some information about the data. You can find some information on the interface at http://scipy-lectures.github.com/advanced/advanced_numpy/index.html#array-interface-protocol

    Basically, I think something like this would work, at least for raw RGB:

    with Image.open(filename="/tmp/some.jpg") as img:
        array = numpy.asarray(img)
    

    And the __array_interface__ would be something like:

    @property
    def __array_interface__(self):
        return dict(data=self.make_blob("RGB"),
                    shape=(self.width, self.height, 3),
                    typestr="|u1")
    

    You might want to use the image's internal format so you could support things like RGBA; I'm not sure what the right thing to do here is. (And in that case, shape would be 4 for the third argument.)

    enhance 
    opened by joeshaw 15
  • Sequences api

    Sequences api

    A new Sequence object is created as image.sequence property in Image constructor.

    Here are some use cases of api:

    >>> # Load 4-imaged apple's icon
    >>> import requests
    >>> r = requests.get('http://apple.com/favicon.ico')
    >>> from wand.image import Image
    >>> img = Image(blob=r.content, format='ico')
    >>> # Get sequenses length
    >>> print len(img.sequence)
    4
    >>> # Print images sizes at sequence
    >>> for i in img.sequence:
    ...     print (i, img.size)
    ...     
    ... 
    (0L, (32L, 32L))
    (1L, (16L, 16L))
    (2L, (32L, 32L))
    (3L, (16L, 16L))
    >>> # Set third image as current (every changes would be applied to it)
    >>> img.sequence.index = 2
    >>> # Delete all images exept the first one
    >>> for i in range(3, 0, -1):
    ...     img.sequence.index = i
    ...     del img.sequence.index
    ...     
    ... 
    >>> print len(img.sequence)
    1
    >>> # Append a copy of our image before current image
    >>> img2 = img.clone()
    >>> img.sequence.append(img.clone(), True)
    >>> print(len(img.sequence))
    2
    
    enhance 
    opened by wronglink 15
  • Switch from py.path to pathlib/pathlib2

    Switch from py.path to pathlib/pathlib2

    Hi, In addition to https://github.com/emcconville/wand/pull/607, py.local is deprecated and pathlib or pathlib2 should be used instead of this: https://github.com/emcconville/wand/blob/3eeb75734ac6b6f4d703ba3562c517a20b19be3c/tests/conftest.py#L11

    From the pytest doc:

    The tmpdir and tmpdir_factory fixtures are similar to tmp_path and tmp_path_factory, but use/return legacy py.path.local_ objects rather than standard :class:pathlib.Path objects.

    From the py doc:

    Note: The ‘py’ library is in “maintenance mode” and so is not recommended for new projects. Please check out pathlib or pathlib2 for path operations.

    opened by sbraz 2
  • Drawing Rounded Rectangle does not work if pyplot used / or

    Drawing Rounded Rectangle does not work if pyplot used / or "unlucky dimensions" entered

    I'm running Ubuntu 21.10, Python 3.9.7 and Wand 0.6.7. There is an issue if my python code first does some pyplot stuff and then drawing an rounded rectangle using wand.

    The following code does not throw any error message, however the resulting file output.png is empty (NO green rectangle is drawn):

    from wand.image import Image
    from wand.drawing import Drawing
    from wand.color import Color
    
    # do some pyplot stuff
    import matplotlib.pyplot as plt
    plt.plot([1, 2, 3, 4])
    
    # Do some wand stuff
    img = Image(width=850, height=600) # This dimension does NOT work
    with Drawing() as drw:
    	drw.fill_color = Color('green')
    	drw.rectangle(left=0,
    				top=0,
    				width=img.width,
    				height=img.height,
    				radius=img.width*0.05)
    	drw(img)
    img.save(filename='output.png')
    

    Now the strange part. The code works fine if I remove seemingly unrelated pyplot stuff at the beginning:

    from wand.image import Image
    from wand.drawing import Drawing
    from wand.color import Color
    
    # Do some wand stuff
    img = Image(width=850, height=600) # This dimension does NOT work
    with Drawing() as drw:
    	drw.fill_color = Color('green')
    	drw.rectangle(left=0,
    				top=0,
    				width=img.width,
    				height=img.height,
    				radius=img.width*0.05)
    	drw(img)
    img.save(filename='output.png')
    

    Now the super crazy thing: I don't need to remove the pyplot stuff, because I can also make the code running by simply changing the dimensions:

    from wand.image import Image
    from wand.drawing import Drawing
    from wand.color import Color
    
    # do some pyplot stuff
    import matplotlib.pyplot as plt
    plt.plot([1, 2, 3, 4])
    
    # Do some wand stuff
    #img = Image(width=850, height=600) # This dimension does not work
    img = Image(width=800, height=600) # This dimension does work
    with Drawing() as drw:
    	drw.fill_color = Color('green')
    	drw.rectangle(left=0,
    				top=0,
    				width=img.width,
    				height=img.height,
    				radius=img.width*0.05)
    	drw(img)
    img.save(filename='output.png')
    

    Thanks for your help!

    seeking-help 
    opened by reisenmachtfreude 1
  • OUTLINE missing pt.2(seeking help)

    OUTLINE missing pt.2(seeking help)

    Ref: https://github.com/emcconville/wand/issues/564

    I think the following codes are messing with outline.

    ##########   main func for image rendering   ##############
    
    def export_caption(caption, filename):
        '''Creates a .png file <filename> suitable for bdsup2sub that displays
        the given caption.'''
        img = Image(width=XSIZE, height=YSIZE)
        # by default wand will use the text's baseline as y-coord which is bad,
        # because we'd never know where we end, so set the gravity to north_west
        # Beware: it seems like if we set text_alignment='center' so we could
        # use wand's multiline text feature the gravity setting will be lost
        # irrevocably, so we need to deal with multiline captions ourselves
        img.gravity = 'north_west'
        box = Drawing()
        # Color() handles 'none' by itself, case-independently
        box.fill_color = Color(OPTS.BOXCOLOR)
    
        draw = Drawing()
        draw.fill_color = Color(OPTS.FILLCOLOR)
        draw.font = FONT
        draw.font_size = FONTSIZE
        draw.text_encoding = ENCODING
        if OPTS.ANTIALIASING:
            draw.text_antialias = True
        else:
            draw.text_antialias = False
        if OUTLINEWIDTH:
            draw.stroke_color = "BLACK"
            draw.stroke_width = OUTLINEWIDTH
            if OPTS.ANTIALIASING:
                draw.stroke_antialias = True
            else:
                draw.stroke_antialias = False
    
        lines = [line.strip() for line in caption.splitlines() if line.strip()]
    
        # padding for the text's bounding box
        padx, pady = BOXPADDING
    
        # calculate the max. allowed text width, and don't forget the outline but
        # ignore the box; keep a few extra px. (1% of XSIZE) in reserve,
        # just to be on the safe side in case we have rounding errors
        max_textwidth = int(round(XSIZE * MAXLINESIZE / 100)) - \
                        2 * OUTLINEWIDTH - int(round(0.01 * XSIZE))
    
        # now loop through the list of strings, calculate each string's width and
        # if necessary split it in two;
        # repeat this until no line needs to be wrapped
        lines, wmax, line_widths = fix_caption(lines, max_textwidth, img, draw)
    
        # collect info for which lines we need y box padding;
        # this seems useful to avoid a too big offset between text lines,
        # which may look odd, esp. when the box is transparent
        i = 0
        padinfo = []
        for lw in line_widths:
            a, b, c = 0, 0, 0 # top padding, bottom padding, Y incr. of next line
            if i == 0:
                # the first line needs top padding
                a = pady
            elif line_widths[i-1] < lw:
                # previous line is smaller, so we need top padding
                a = pady
            if i == len(line_widths) - 1:
                # the last line needs bottom padding
                b = pady
            elif line_widths[i+1] < lw:
                # next line is smaller, so we need bottom padding
                b = pady
            elif line_widths[i+1] > lw:
                # next line is bigger, shift the Y-increment by pady
                c = pady
            i += 1
            padinfo.append((a, b, c))
    
        # width of the box == max. textwidth + 2* (boxpad + outline width)
        wmax = wmax + 2*padx + 2*OUTLINEWIDTH
    
        # now all lines should be safe to fit on the screen,
        # so start drawing
        Y = 0
        i = 0
        bottom = 0
        for line in lines:
            s = line.strip()
            m = draw.get_font_metrics(img, line)
            w, h = int(m.text_width), int(m.text_height)
    
            # make sure the smaller line appears centered relative to the
            # bigger line
            if wmax > XSIZE:
                # may happen if an insane x box padding was given;
                # make sure the text will be centered anyway, the excess box
                # will be chopped off later
                X = int((XSIZE - w) / 2)
            else:
                X = int((wmax - w) / 2)
    
            a, b, c = padinfo[i]
            # draw the bounding box
            if OPTS.BOXCOLOR.lower() != 'none':
                box.rectangle(X - OUTLINEWIDTH - padx,
                              Y - OUTLINEWIDTH - a,
                              X + w + OUTLINEWIDTH + padx,
                              Y + h + OUTLINEWIDTH + b)
                box(img)
    
            # draw the text and shift the Y position to the correct
            # coordinate for the following line (if any)
            draw.text(X, Y, s)
            draw(img)
    
            # store bottom Y coord
            bottom = Y + h + OUTLINEWIDTH + b
            Y = bottom + c + OUTLINEWIDTH + 2 # 1 px. extra so the boxes won't overlap
            i += 1
    
        x0, y0, x1, y1 = 0, 0, wmax + 1, bottom + 1
        # cut the text box from the surrounding void
        if y1 > YSIZE:
            # may happen if the font is too big or an insane y boxpadding is set
            printerror('\nError: generated subtitle image exceeds screen height')
            printerror('The offending subtitle text was:')
            for line in caption.splitlines():
                printerror('    ' + line)
            printerror('This subtitle will not look as expected.')
            y1 = YSIZE
    
        if x1 > XSIZE:
            # may happen if the user set insane boxpadding values, making
            # it impossible to wrap the text to fit into one line
            printerror('\nError: generated subtitle image exceeds screen width')
            printerror('The offending subtitle text was:')
            for line in caption.splitlines():
                printerror('    ' + line)
            printerror('This subtitle may not look as expected.')
            x1 = XSIZE
    
        img.crop(x0, y0, x1, y1)
    
        # write file and return the size for our xml content
        img.format = 'png'
        img.save(filename=filename)
        box.destroy()
        draw.destroy()
        img.destroy()
        return wmax+1, bottom+1
    
    

    Whole file: srt2vobsub.zip

    opened by OilSubjectLoss7 0
  • Deskew method errors out when running in docker(linux)

    Deskew method errors out when running in docker(linux)

    I am ending up with an error when I use the below code when its run in docker.

    try:
         with skew(blob=img_png) as img_png_1:           
             img_png_1.deskew(0.5 * img_png_1.quantum_range)
             pil_image = Image.open(io.BytesIO(img_png_1.make_blob("png")))            
             img_png = image_to_byte_array(pil_image)            
         log.info("Corrected the Skewness for %s", file_name)
     except Exception as e:
         log.exception(f'Exception:{e} occured while Corrected the Skewness for {file_name}')
         pass
    

    Error Message: wand.exceptions.WandRuntimeError: MagickReadImage returns false, but did not raise ImageMagick exception. This can occur when a delegate is missing, or returns EXIT_SUCCESS without generating a raster.

    When I run this in local windows, I don't see any error, but failed in docker(linux). It keeps working for few images and fails for few. Please advice.

    seeking-help 
    opened by uday-felix 4
  • Importing wand takes 700ms on Ubuntu (and can't be avoided via environment)

    Importing wand takes 700ms on Ubuntu (and can't be avoided via environment)

    In Ubuntu 18.04 LTS, the libmagickwand-6.q16-3 package installs the wand libraries at:

    • /usr/lib/x86_64-linux-gnu/libMagickCore-6.Q16.so.3
    • /usr/lib/x86_64-linux-gnu/libMagickWand-6.Q16.so.3

    import wand finds these, but it takes ~700ms to do because it runs ctypes.find_library (apparently several times?)

    Looking at the source code, it seemed like we could avoid this by setting MAGICK_HOME and WAND_MAGICK_LIBRARY_SUFFIX in our containers.

    However, this doesn't actually help because wand hardcodes the .so extension, and .so.3 doesn't match.

    Perhaps wand should handle a couple of environment variables containing the full paths to the libraries?

    opened by craigds 4
  • Wand silently crashes if hugging face transformers library is imported immediately before Wand import

    Wand silently crashes if hugging face transformers library is imported immediately before Wand import

    The following code behaves as expected:

    from wand.image import Image # MUST BE RUN BEFORE `from transformers import ... ` or will produce silent failure
    from transformers import PreTrainedTokenizer # MUST BE RUN AFTER `from wand.image import... ` or will produce silent failure
    
    with Image(filename='/path/to/filename.pdf') as wand_img:
        for page in wand_img.sequence:
            page_img = Image(page)
            print('foo')
    

    However, if the libraries are imported in the opposite order, Wand will silently terminate on line 6:

    from transformers import PreTrainedTokenizer # MUST BE RUN AFTER `from wand.image import... ` or will produce silent failure
    from wand.image import Image # MUST BE RUN BEFORE `from transformers import ... ` or will produce silent failure
    
    with Image(filename='/path/to/filename.pdf') as wand_img:
        for page in wand_img.sequence:
            page_img = Image(page) # crashes
            print('foo')
    

    transformers version 4.6.1 Wand version 0.6.6

    opened by matoles 5
Releases(0.6.10)
Owner
Eric McConville
Lead Software Engineer focusing on web applications, system architecture, content delivery, and resource management.
Eric McConville
Simple Python / ImageMagick script to package images into WAD3s for use as GoldSrc textures.

WADs Out For [The] Ladies Simple Python / ImageMagick script to package images into WAD3s for use as GoldSrc textures. Development mostly focused on L

null 5 Apr 9, 2022
python binding for libvips using cffi

README PyPI package: https://pypi.python.org/pypi/pyvips conda package: https://anaconda.org/conda-forge/pyvips We have formatted docs online here: ht

libvips 467 Dec 30, 2022
Python binding to Skia Graphics Library

Skia python binding Python binding to Skia Graphics Library. Binding based on pybind11. Currently, the binding is under active development. Install Bi

Kota Yamaguchi 170 Jan 6, 2023
Simple Python image processing & automatization project for a simple web based game

What is this? Simple Python image processing & automatization project for a simple web based game Made using only Github Copilot (except the color and

SGeri 2 Aug 15, 2022
GTK and Python based, simple multiple image editor tool

System Monitoring Center GTK3 and Python3 based, simple multiple image editor tool. Note: Development of this application is not completed yet. The ap

Hakan Dündar 1 Feb 2, 2022
A python based library to help you create unique generative images based on Rarity for your next NFT Project

Generative-NFT Generate Unique Images based on Rarity A python based library to help you create unique generative images based on Rarity for your next

Kartikay Bhutani 8 Sep 21, 2022
MaryJane is a simple MJPEG server written in Python.

MaryJane is a simple MJPEG server written in Python.

bootrino 152 Dec 13, 2022
Simple to use image handler for python sqlite3.

SQLite Image Handler Simple to use image handler for python sqlite3. Functions Function Name Parameters Returns init databasePath : str tableName : st

Mustafa Ozan Çetin 7 Sep 16, 2022
A simple python script to reveal the contents of a proof of vaccination QR code.

vaxidecoder A simple python script to reveal the contents of a proof of vaccination QR code. It takes a QR code image as input, and returns JSon data.

Hafidh 2 Feb 28, 2022
Sombra is simple Raytracer written in pure Python.

Sombra Sombra is simple Raytracer written in pure Python. It's main purpose is to help understand how raytracing works with a clean code. If you are l

Hernaldo Jesus Henriquez Nuñez 10 Jul 16, 2022
Simple Python package to convert an image into a quantized image using a customizable palette

Simple Python package to convert an image into a quantized image using a customizable palette. Resulting image can be displayed by ePaper displays such as Waveshare displays.

Luis Obis 3 Apr 13, 2022
Python-based tools for document analysis and OCR

ocropy OCRopus is a collection of document analysis programs, not a turn-key OCR system. In order to apply it to your documents, you may need to do so

OCRopus 3.2k Jan 4, 2023
Nanosensor Image Processor (NanoImgPro), a python-based image analysis tool for dopamine nanosensors

NanoImgPro Nanosensor Image Processor (NanoImgPro), a python-based image analysis tool for dopamine nanosensors NanoImgPro.py contains the main class

null 1 Mar 2, 2022
Image-Viewer is a Windows image viewer based on Python 3.

Image-Viewer Hi! Image-Viewer is a Windows image viewer based on Python 3. Using You must download Image-Viewer.exe from the root of the repository. T

null 2 Apr 18, 2022
Seaborn-image is a Python image visualization library based on matplotlib and provides a high-level API to draw attractive and informative images quickly and effectively.

seaborn-image: image data visualization Description Seaborn-image is a Python image visualization library based on matplotlib and provides a high-leve

null 48 Jan 5, 2023
starfish is a Python library for processing images of image-based spatial transcriptomics.

starfish: scalable pipelines for image-based transcriptomics starfish is a Python library for processing images of image-based spatial transcriptomics

null 199 Dec 8, 2022
Gaphor is the simple modeling tool

Gaphor Gaphor is a UML and SysML modeling application written in Python. It is designed to be easy to use, while still being powerful. Gaphor implemen

Gaphor 1.3k Dec 31, 2022
MyPaint is a simple drawing and painting program that works well with Wacom-style graphics tablets.

MyPaint A fast and dead-simple painting app for artists Features Infinite canvas Extremely configurable brushes Distraction-free fullscreen mode Exten

MyPaint 2.3k Jan 1, 2023
A simple programming language for manipulating images.

f-stop A simple programming language for manipulating images. Examples OPEN "image.png" AS image RESIZE image (300, 300) SAVE image "out.jpg" CLOSE im

F-Stop 6 Oct 27, 2022