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

Fixed bug for drawing mask contour on a transparent background. #389

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

m000
Copy link

@m000 m000 commented Jun 5, 2018

I had problems generating images with mode='RGBA', background_color=None. The contour used when rendering the image was lacking a transparency channel. This should fix it.

@amueller
Copy link
Owner

amueller commented Jun 6, 2018

looks good, can you add a test?

The contour used was lacking a transparency channel.

Also fixed the conditions for plotting a contour.
Now contour_color=None or contour_width=0 means that no contour
will be plotted.
@m000 m000 force-pushed the master branch 2 times, most recently from 1c2dd8d to b612fe3 Compare June 6, 2018 16:51
@m000 m000 changed the title Fixed bug for generating images with transparent background. Fixed bug for drawing mask contour on a transparent background. Jun 6, 2018
@m000
Copy link
Author

m000 commented Jun 6, 2018

Should be good now.

mask = np.array(Image.open(mask_file))
w = WordCloud(mode='RGBA', background_color=None, contour_color='blue', contour_width=2, mask=mask,
max_words=50, width=800, height=800)
w.generate(THIS)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So does this give an error? You could probaby also just create an empty mask to reproduce it instead of loading one, right?

Copy link
Author

@m000 m000 Jun 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if what you describe works or not, but why would you be trying to draw a contour with an empty mask?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right maybe that's not the very best idea but you could just add a stripe to one side or something. The point is to make the test as simple and self-contained as possible. And if you can reproduce the error with a small numpy array that would be easier.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The image is in the repo, so it is adequately self-contained. Sure, someone with a better grasp of PIL can remove this dependency in the future.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mask = np.ones((100, 100))
mask[:, -10:] = 0

should do it, right?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually better

mask = np.zeros((100, 100, 3), dtype="ubyte")
mask[:, -10:] = 255

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup! Looks good. This would have taken me at least another 30' to figure out. Haven't worked with matrices and stuff for quite a long time.

w = WordCloud(mode='RGBA', background_color=None, contour_color='blue', contour_width=2, mask=mask,
max_words=50, width=800, height=800)
w.generate(THIS)
w.to_file(NamedTemporaryFile(suffix=".png").name)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's how the previously buggy code path is triggered. If you don't write to a file the contour is not drawn. The exception happens here:

ret = np.array(img) * np.invert(contour)
ValueError: operands could not be broadcast together with shapes (900,900,4) (900,900,3)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could just do to_image().

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Fixed that.

@m000 m000 force-pushed the master branch 4 times, most recently from c5966f4 to b06b8b3 Compare June 6, 2018 17:35
@amueller
Copy link
Owner

can you remind me what the reason was to change the default color?

@VergeDX
Copy link

VergeDX commented Jun 1, 2022

I rebase the patches to the currently stable branch 1.8.1:

diff --git a/wordcloud/wordcloud.py b/wordcloud/wordcloud.py
index 26b0d54..93dc6b1 100644
--- a/wordcloud/wordcloud.py
+++ b/wordcloud/wordcloud.py
@@ -311,7 +311,7 @@ class WordCloud(object):
                  max_font_size=None, font_step=1, mode="RGB",
                  relative_scaling='auto', regexp=None, collocations=True,
                  colormap=None, normalize_plurals=True, contour_width=0,
-                 contour_color='black', repeat=False,
+                 contour_color=None, repeat=False,
                  include_numbers=False, min_word_length=0, collocation_threshold=30):
         if font_path is None:
             font_path = FONT_PATH
@@ -1006,7 +1006,7 @@ class WordCloud(object):
 
     def _draw_contour(self, img):
         """Draw mask contour on a pillow image."""
-        if self.mask is None or self.contour_width == 0:
+        if self.mask is None or self.contour_color is None or self.contour_width == 0:
             return img
 
         mask = self._get_bolean_mask(self.mask) * 255
@@ -1024,12 +1024,14 @@ class WordCloud(object):
         contour = Image.fromarray(contour)
         contour = contour.filter(ImageFilter.GaussianBlur(radius=radius))
         contour = np.array(contour) > 0
-        contour = np.dstack((contour, contour, contour))
+        if img.mode == 'RGBA':
+            contour = np.dstack((contour, contour, contour, contour))
+        else:
+            contour = np.dstack((contour, contour, contour))
 
         # color the contour
         ret = np.array(img) * np.invert(contour)
-        if self.contour_color != 'black':
-            color = Image.new(img.mode, img.size, self.contour_color)
-            ret += np.array(color) * contour
+        color = np.array(Image.new(img.mode, img.size, self.contour_color))
+        ret += color * contour
 
         return Image.fromarray(ret)
diff --git a/wordcloud/wordcloud_cli.py b/wordcloud/wordcloud_cli.py
index 125a86f..03c7db6 100644
--- a/wordcloud/wordcloud_cli.py
+++ b/wordcloud/wordcloud_cli.py
@@ -126,7 +126,7 @@ def make_parser():
         dest='contour_width',
         help='if greater than 0, draw mask contour (default: 0)')
     parser.add_argument(
-        '--contour_color', metavar='color', default='black', type=str,
+        '--contour_color', metavar='color', default=None, type=str,
         dest='contour_color',
         help='use given color as mask contour color -'
              ' accepts any value from PIL.ImageColor.getcolor')

@Leo310
Copy link

Leo310 commented Jul 20, 2022

when will this be merged?

Leo310 added a commit to Leo310/word_cloud that referenced this pull request Sep 23, 2022
@orbsmiv
Copy link

orbsmiv commented Dec 19, 2023

Just adding another bump to this bug fix :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants