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
Cat avatars for adult independent users

Cat avatars for adult independent users Samples (Natasha, wake up!) Usage Check values from https://shantichat.github.io/avacats/index.json: { "sizes"

4 Nov 05, 2021
A Robust Avatar Generator with a huge number of templates

CoolAvatars Welcome to this repository of CoolAvatars. Using this project, you can generate cool avatars not only from the samples present in my image

RAVI PRAKASH 5 Oct 12, 2021
This projects aim is to simulate flowers(Gerbera Daisy) phyllotaxis.

phyllotaxis This projects aim is to simulate flowers(Gerbera Daisy) phyllotaxis. Take a look at the arrangement of this flower's seeds, this project's

amirsalar 3 Dec 10, 2021
Pyconvert is a python script that you can use to convert image files to another image format! (eg. PNG to ICO)

Pyconvert is a python script that you can use to convert image files to another image format! (eg. PNG to ICO)

1 Jan 16, 2022
The ctypes-based simple ImageMagick binding for Python

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

Eric McConville 1.2k Dec 30, 2022
Py3D - A 3d rendering engine written entirely in python

Py3D is a 3d rendering engine written entirely in python. It is a simple and eas

1up Community 2 Nov 14, 2022
a lite weight photo editor written in python for day to day photo editing!

GNU-PhotoShop A lite weight Photo editing Program (currently CLI only) written in python3 for day to day photo editing. Disclaimer : Currently we don'

Kunal Sharma 5 May 30, 2022
A Gtk based Image Selector with Preview

gtk-image-selector This is an attempt to restore Gtk Image Chooser "lost functionality": displaying an image preview when selecting images... This is

Spiros Georgaras 2 Sep 28, 2022
Simple utility to tinker with OPlus images

OPlus image utilities Prerequisites Linux running kernel 5.4 or up (check with uname -r) Image rebuilding Used to rebuild read-only erofs images into

Wiley Lau 15 Dec 28, 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 06, 2023
A collection of python scripts which help you programatically create PNGs or GIFs

A collection of python scripts which help you programatically create PNGs or GIFs and their Metadata in bulk with custom rarity rates, upload them to OpenSea & list them for sale.

Tom 30 Dec 24, 2022
DP2 graph edit codes.

必要なソフト・パッケージ Python3 Numpy JSON Matplotlib 動作確認環境 MacBook Air M1 Python 3.8.2 (arm64) Numpy 1.22.0 Matplotlib 3.5.1 JSON 2.0.9 使い方 draw_time_histgram(

1 Feb 19, 2022
Image Reading, Metadata Conversion, and Image Writing for Microscopy Images in Python

AICSImageIO Image Reading, Metadata Conversion, and Image Writing for Microscopy Images in Pure Python Features Supports reading metadata and imaging

Allen Institute for Cell Science - Modeling 137 Dec 14, 2022
Me cleaner - Tool for partial deblobbing of Intel ME/TXE firmware images

me_cleaner me_cleaner is a Python script able to modify an Intel ME firmware image with the final purpose of reducing its ability to interact with the

Nicola Corna 4.1k Jan 08, 2023
ProsePainter combines direct digital painting with real-time guided machine-learning based image optimization.

ProsePainter Create images by painting with words. ProsePainter combines direct digital painting with real-time guided machine-learning based image op

Morphogen 276 Dec 17, 2022
Maze generator with most popular shapes - hexagon, triangle, square

Maze-Generator Maze generator with most popular shapes - hexagon, triangle, square (sqaure not implemented yet): Theory: Planar Graph https://en.wikip

Kacper Plesiak 2 Dec 28, 2021
Image Processing HighPass Filter With Python

Image_Processing_HighPassFilter High Pass Filter take the high frequency and ignore the low frequency High Pass Filter can be use to sharpening an ima

Felix Pratamasan 1 Dec 27, 2021
Javascript image annotation tool based on image segmentation.

JS Segment Annotator Javascript image annotation tool based on image segmentation. Label image regions with mouse. Written in vanilla Javascript, with

Kota Yamaguchi 513 Nov 15, 2022
Magic-Square - Creates a magic square by randomly generating a list until the list happens to be a magic square

Magic-Square Creates a magic square by randomly generating a list until the list happens to be a magic square. Done as simply as possible... Frequentl

Nick 2 Jan 01, 2022
Change the image one color channel at a time.

Building-a-Contact-Sheet This hands-on Project is in Python 3 Programming Specialization offered by University of Michigan via Coursera. change the im

Eszter Pai 1 Jan 03, 2022