def add(self, im: pyvips.Image) -> pyvips.Image: """Use method which finds complementary color. Returns image """ text = pyvips.Image.text( self.text, width=im.width, dpi=300, font=f"{self.font}" ) text = text.rotate(self.rotate) # the position of the overlay in the image margin = 25 position = self.position if position == "top-left": x_pos = margin y_pos = margin elif position == "top-right": x_pos = im.width - text.width - margin y_pos = margin elif position == "bottom-right": x_pos = im.width - text.width - margin y_pos = im.height - text.height - margin elif position == "bottom-left": x_pos = margin y_pos = im.height - text.height - margin else: print(f"Incorrect watermark position: {position}") sys.exit(1) # find the non-alpha image bands if im.hasalpha(): no_alpha = im.extract_band(0, n=im.bands - 1) else: no_alpha = im # the pixels we will render the overlay on top of bg = no_alpha.crop(x_pos, y_pos, text.width, text.height) # mask the background with the text, so all non-text areas become zero, and find # the zero-excluding average avg = avgze(text.ifthenelse(bg, 0)) # for each band, find the opposing value mx = 255 if im.format == "uchar" else 65535 text_colour = [oppose(avg[i], mx) for i in range(len(avg))] # make an overlay ... we put solid colour into the image and set a faded version # of the text mask as the alpha overlay = bg.new_from_image(text_colour) overlay = overlay.bandjoin((text * self.opacity).cast("uchar")) # and composite that on to the original image im = im.composite(overlay, "over", x=x_pos, y=y_pos) return im
def add_to_image(self, im: pyvips.Image) -> pyvips.Image: """Add watermark to supplied image.""" LOG.info("Adding watermark '%s'", self.text) text = pyvips.Image.text( self.text, width=im.width, dpi=300, font=f"{self.font}" ) text = text.rotate(self.rotate) text = (text * self.opacity).cast("uchar") text = text.embed( self.x_margin, (im.height - text.height) - self.y_margin, im.width, im.height, ) if self.replicate: text = text.replicate( 1 + im.width / text.width, 1 + im.height / text.height ) text = text.crop(0, 0, im.width, im.height) # we want to blend into the visible part of the image and leave any alpha # channels untouched ... we need to split im into two parts # guess how many bands from the start of im contain visible colour information if im.hasalpha(): alpha = im.extract_band(im.bands - 1) im = im.extract_band(0, n=im.bands - 1) else: alpha = None if im.bands == 4: # cmyk text_color: Any = list(rgb_to_cmyk(self.fg_color)) elif im.bands == 3: # rgb text_color = list(self.fg_color) else: # mono text_color = rgb_to_grayscale(self.fg_color) LOG.info("Watermark fg_color: %s (original: %s)", text_color, self.fg_color) im = text.ifthenelse(text_color, im, blend=True) # reattach alpha if alpha: im = im.bandjoin(alpha) return im