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
kikuchipy is an open-source Python library for processing and analysis of electron backscatter diffraction (EBSD) patterns

kikuchipy is an open-source Python library for processing and analysis of electron backscatter diffraction (EBSD) patterns. The library builds on the

pyxem 53 Dec 29, 2022
Python Image Morpher (PIM) is a program that can take two images and blend them to whatever extent or precision that you like

Python Image Morpher (PIM) is a program that can take two images and blend them to whatever extent or precision that you like! It is designed to emulate some of Python's OpenCV image processing from

David Dowd 108 Dec 19, 2022
Open source software for image correlation, distance and analysis

Douglas-Quaid Project Open source software for image correlation, distance and analysis. Strongly related to : Carl-Hauser Problem statement (@CIRCL)

Dominik Dancs 2 May 01, 2022
vsketch is a Python generative art toolkit for plotters

Generative plotter art environment for Python

Antoine Beyeler 380 Dec 29, 2022
Multiparametric Image Analysis

Documentation The documentation is available on populse_mia's website here Installation From PyPI, for users By cloning the package, for developers Fr

Populse 9 Dec 14, 2022
⚡ZenGL is a minimalist Python module providing exactly one way to render scenes with OpenGL.

ZenGL is a minimalist Python module providing exactly one way to render scenes with OpenGL.

Szabolcs Dombi 133 Dec 17, 2022
Fuzzware is a project for automated, self-configuring fuzzing of firmware images

Fuzzware Fuzzware is a project for automated, self-configuring fuzzing of firmware images. The idea of this project is to configure the memory ranges

190 Dec 21, 2022
Polyfoto - Create image mosaics.

Polyfoto Create image mosaics. Showcase "Before and After Science" by Brian Eno "Scott 3" by Scott Walker Installation Clone this repository to your l

Shane Drabing 149 Dec 25, 2022
Extract the ISO 11146 beam size from an image file

laserbeamsize Simple and fast calculation of beam sizes from a single monochrome image based on the ISO 11146 method of variances. Some effort has bee

Scott Prahl 21 Jan 06, 2023
Python library for ascii graphics

Python library for ascii graphics

Anton 6 Oct 20, 2021
A quick and dirty QT Statusbar implementation for grabbing GIFs from Tenor, since there is no offical or unofficial one I found. This was intended for use under Linux, however it was also functional enough on MacOS.

Statusbar-TenorGIF App for Linux A quick and dirty QT Statusbar implementation for grabbing GIFs from Tenor, since there is no offical one and I didnt

Luigi DaVinci 1 Nov 01, 2021
SALaD (Semi-Automatic Landslide Detection) is a landslide mapping system

SALaD (Semi-Automatic Landslide Detection) is a landslide mapping system. SALaD utilizes Object-based Image Analysis and Random Forest to map landslides.

NASA 14 Jan 04, 2023
Group of interfaces interesting for users

Project: Interface to create GIF animation based on Fourier Series.

5 Aug 17, 2021
A script to generate a profile picture and a banner that show the same image on Discord.

Discord profile picture & banner generator A script to generate a profile picture and a banner that show the same image on Discord. Installation / Upd

Victor B. 9 Nov 27, 2022
MikuMikuRig是一款集生成控制器,自动导入动画,自动布料为一体的blender插件

Miku_Miku_Rig MikuMikuRig是一款集生成控制器,自动导入动画,自动布料为一体的blender插件。 MikumiKurig is a Blender plugin that can generates rig, automatically imports animations

小威廉伯爵 342 Dec 29, 2022
Python Interface of P3D

pyp3d 介绍: pyp3d是一个可在python上使用的工具包,它提供了一种可使用python脚本驱动创建模型的方法,为三维建模提供了全新的思路。 pyp3d中定义了一系列建模相关的必要的数据类型,例如球体、圆锥台、四棱锥台、 拉伸体、圆角管等几何体,pyp3d还提供了许多函数来实现放置集合体、

20 Sep 07, 2022
:rocket: A minimalist comic reader

Pynocchio A minimalist comic reader Features | Installation | Contributing | Credits This screenshots contains a page of the webcomic Pepper&Carrot by

Michell Stuttgart 73 Aug 02, 2022
Computational Xmas Tree lights!

Computational Xmas Tree This repo contains the code for the computational illumination of a Christmas Tree! It is based on the work by Matt Parker fro

GSD6338 146 Dec 23, 2022
GIMP script to export bitmap as GRAPHICS 4 file (aka SCREEN 5)

gimpfu-msx-gr4.py GIMP script to export bitmap as GRAPHICS 4 file (aka SCREEN 5). GRAPHICS 4 specs are: 256x212 (or 256x192); 16 color palette (from 5

Pedro de Medeiros 4 Oct 17, 2022
Snowfall - helpful image handling utils - abstracts various file and opencv and pil features into result oriented functions

snowfall helpful image handling utils - abstracts various file and opencv and pil features into result oriented functions usage examples: from image_h

Less Wright 2 Jan 09, 2022