Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AssertionError when SingleImage is transformed from sequence #388

Closed
arminbashizade opened this Issue Jan 14, 2019 · 2 comments

Comments

Projects
None yet
2 participants
@arminbashizade
Copy link

arminbashizade commented Jan 14, 2019

I am trying to extract images from a pdf file and also resize them. Each page consists of a single image. I have tried this in multiple ways:

    with Image(filename='doc.pdf', resolution=density) as img:
        pages = img.sequence
        for i in range(len(pages)):
            pages[i].transform(resize='100x')
            Image(pages[i]).save(filename='doc-{}.png'.format(i))

also:

    with Image(filename='doc.pdf', resolution=density) as img:
        for page in img.sequence:
            page.transform(resize='100x')
        img.save(filename='doc.png')

but with both methods I get these messages, which are ignored, but I'm wondering what the problem is:

Exception AssertionError: AssertionError() in <bound method SingleImage.__del__ of <wand.sequence.SingleImage: a361bdf (100x265)>> ignored
Exception AssertionError: AssertionError() in <bound method SingleImage.__del__ of <wand.sequence.SingleImage: d0fa2ba (100x265)>> ignored
Exception AssertionError: AssertionError() in <bound method SingleImage.__del__ of <wand.sequence.SingleImage: 8fb6062 (100x265)>> ignored

However if I create a new Image from each SingleImage before I transform it, it works fine:

    with Image(filename='doc.pdf', resolution=density) as img:
        pages = img.sequence
        for i in range(len(pages)):
            with Image(pages[i]) as p:
                p.transform(resize='100x')
                p.save(filename='doc-{}.png'.format(i))
@emcconville

This comment has been minimized.

Copy link
Owner

emcconville commented Jan 15, 2019

Thanks for posting this issue. I'll explore solutions in the next couple of days.

... I'm wondering what the problem is(?)

On the very high-level. Sequence class holds each page/frame as a SingleImage instance. The SingleImage extends BaseImage for all the manipulative methods, and doesn't have any I/O methods. It is also a COPY of the image data/info, and changes are not automatically synced back to the original image. Originally the syncing would occur during SingleImage instances deletion, but this assumes all users would follow the format...

with Image(filename='doc.pdf', resolution=density) as img:
    for page in img.sequence:
        page.transform(resize='100x')
    img.save(filename='doc.png')

... and allow Python's internal FILO stack rules to clean-up. With previous improvements to efficiency & memory leak fixes, I think a few things are out-of-alignment. Definitely a bug.

For your use-case

I am trying to extract images from a pdf file and also resize them.

As you want to have output actions on each frame, you correctly implemented the following...

with Image(filename='doc.pdf', resolution=density) as img:
    for i, page in enumerate(img.sequence):
        with Image(page) as p:
            p.transform(resize='100x')
            p.save(filename='doc-{}.png'.format(i))

@emcconville emcconville added the bug label Jan 15, 2019

@emcconville emcconville added this to the 0.5.1 milestone Jan 15, 2019

@emcconville emcconville self-assigned this Jan 15, 2019

@emcconville

This comment has been minimized.

Copy link
Owner

emcconville commented Jan 15, 2019

Looks like the BaseImage.dirty flag needs to be reset after applied, and perhaps, only at time of context exit - not destroy.

diff --git a/wand/sequence.py b/wand/sequence.py
index a3a92b8..54f8a62 100644
--- a/wand/sequence.py
+++ b/wand/sequence.py
@@ -329,10 +329,11 @@ class SingleImage(BaseImage):
             library.MagickSetImageDelay(container.wand, delay)
         self._delay = delay
 
-    def destroy(self):
+    def __exit__(self, type, value, traceback):
         if self.dirty:
             self.container.sequence[self.index] = self
-        super(SingleImage, self).destroy()
+            self.dirty = False  # Reset dirty flag
+        super(SingleImage, self).__exit__(type, value, traceback)
 
     def __repr__(self):
         cls = type(self)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.