Rmagick - image with transparent background from text - ruby

I am trying to create an image file from text using Rmagick in ruby. Additionally I need it's background transparent. My code:
canvas = Image.new(400, 60)
watermark_text = Draw.new
watermark_text.annotate(canvas, 0,0,0,0, text) do
self.gravity = WestGravity
self.pointsize = 50
self.font = "whatever.ttf"
self.fill = 'black'
self.stroke = "none"
end
canvas.write(#path)
It works, but the background of the image is white and I need it to be transparent. Any ideas? File is saved as png.

When you create an image, the default background is white. You can tell rmagick you want a different background:
canvas = Image.new(400, 60) do |c|
c.background_color= "Transparent"
end

Related

Hexapdf: trying to draw white box, but its not appearing

When I run my code, my white box does not appear. I need a white box to cover existing images, text, so I can add new text. If I change the color to background_color: [255,255,180], the box is a transparent yellow. However, I need a non-transparent white.
require 'hexapdf'
require 'pry'
doc = HexaPDF::Document.open('template.pdf')
pages = doc.pages
box = HexaPDF::Layout::Box.create(
width: 500, height: 500, content_box: true,
background_color: [255,255,255]
)
pages.each do |p|
canvas = p.canvas(type: :underlay)
box.draw(canvas, 20, 100)
end
doc.write("template_with_white_box.pdf")
You need to use canvas = p.canvas(type: :overlay) for this to work because the underlay canvas draws beneath the existing page whereas the overlay canvas draws above the existing page.

Rmagick setting opacity in watermark with transparency

I am trying to create a watermark with different opacity values (from 0 opaque value to 1 totally transparent).
I have the following method for RMagick in ruby:
# 0 = opaque (Magick::OpaqueOpacity) 1= transparent (Magick::TransparentOpacity)
def watermark(opacity = 0.99, size = 'm')
manipulate! do |img|
logo = Magick::Image.read("#{Rails.root}/app/assets/images/watermark#{size}.png").first
logo.alpha(Magick::ActivateAlphaChannel)
logo.opacity = (1 - opacity.to_f) * Magick::QuantumRange
img.alpha(Magick::ActivateAlphaChannel)
img = img.composite(logo, Magick::NorthWestGravity, 0, 0, Magick::OverCompositeOp)
end
end
My problem is that it seems to work, but the composite mode or the alpha composite or setting the opacity or alpha is failing, because I get a black transparency in the image. For example if my watermark is a totally transparent image with a text, that I put over a car image, then I get a more dark or nightly image with the watermark, so the background of the watermark it is not blending properly.
Any suggestions to set properly the opacity in the watermark image? Maybe some method to disolve the watermark?
EDIT: Adding image examples:
http://uppix.com/f-watermarkg53925b100016ab8e.png (watermark)
http://oi62.tinypic.com/2us8rxl.jpg (base image)
http://oi60.tinypic.com/2pt6mg3.jpg (composition)
Thanks to Neil Slater, I finally found the right solution. I need a combination of composite operation of DstIn + Over in my finalt result:
def watermark(opacity = 0.99, size = 'm')
manipulate! do |img|
logo = Magick::Image.read("#{Rails.root}/app/assets/images/watermark#{size}.png").first
logo.alpha(Magick::ActivateAlphaChannel)
white_canvas = Magick::Image.new(logo.columns, logo.rows) { self.background_color = "none" }
white_canvas.alpha(Magick::ActivateAlphaChannel)
white_canvas.opacity = Magick::QuantumRange - (Magick::QuantumRange * opacity)
# Important: DstIn composite operation (white canvas + watermark)
logo_opacity = logo.composite(white_canvas, Magick::NorthWestGravity, 0, 0, Magick::DstInCompositeOp)
logo_opacity.alpha(Magick::ActivateAlphaChannel)
# Important: Over composite operation (original image + white canvas watermarked)
img = img.composite(logo_opacity, Magick::NorthWestGravity, 0, 0, Magick::OverCompositeOp)
end
end

Is there a max image size (pixel width and height) within wx where png images lose there transparency?

Initially, I loaded in 5 .png's with transparent backgrounds using wx.Image() and every single one kept its transparent background and looked the way I wanted it to on the canvas (it kept the background of the canvas). These png images were about (200,200) in size. I proceeded to load a png image with a transparent background that was about (900,500) in size onto the canvas and it made the transparency a black box around the image. Next, I opened the image up with gimp and exported the transparent image as a smaller size. Then when I loaded the image into python the image kept its transparency. Is there a max image size (pixel width and height) within wx where png images lose there transparency? Any info would help. Keep in mind that I can't resize the picture before it is loaded into wxpython. If I do that, it will have already lost its transparency.
import wx
import os
def opj(path):
return apply(os.path.join, tuple(path.split('/')))
def saveSnapShot(dcSource):
size = dcSource.Size
bmp= wx.EmptyBitmap(size.width, size.height)
memDC = wx.MemoryDC()
memDC.SelectObject(bmp)
memDC.Blit(0, 0, size.width, size.height, dcSource, 0,0)
memDC.SelectObject(wx.NullBitmap)
img = bmp.ConvertToImage()
img.SaveFile('path to new image created', wx.BITMAP_TYPE_JPEG)
def main():
app = wx.App(None)
testImage = wx.Image(opj('path to original image'), wx.BITMAP_TYPE_PNG).ConvertToBitmap()
draw_bmp = wx.EmptyBitmap(1500, 1500)
canvas_dc = wx.MemoryDC(draw_bmp)
background = wx.Colour(208, 11, 11)
canvas_dc.SetBackground(wx.Brush(background))
canvas_dc.Clear()
canvas_dc.DrawBitmap(testImage,0, 0)
saveSnapShot(canvas_dc)
if __name__ == '__main__':
main()
I don't know if I got this right. But if I convert your example from MemoryDC to PaintDC, then I could fix the transparency issue. The key was to pass True to useMask in DrawBitmap method. If I omit useMask parameter, it will default to False and no transparency will be used.
The documentation is here: http://www.wxpython.org/docs/api/wx.DC-class.html#DrawBitmap
I hope this what you wanted to do...
import wx
class myFrame(wx.Frame):
def __init__(self, testImage):
wx.Frame.__init__(self, None, size=testImage.Size)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.testImage = testImage
self.Show()
def OnPaint(self, event):
dc = wx.PaintDC(self)
background = wx.Colour(255, 0, 0)
dc.SetBackground(wx.Brush(background))
dc.Clear()
#dc.DrawBitmap(self.testImage, 0, 0) # black background
dc.DrawBitmap(self.testImage, 0, 0, True) # transparency on, now red
def main():
app = wx.App(None)
testImage = wx.Image(r"path_to_image.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap()
Frame = myFrame(testImage)
app.MainLoop()
if __name__ == '__main__':
main()
(Edit) Ok. I think your original example can be fixed in a similar way
memDC.Blit(0, 0, size.width, size.height, dcSource, 0,0, useMask=True)
canvas_dc.DrawBitmap(testImage,0, 0, useMask=True)
Just making sure that useMask is True was enough to fix the transparency issue in your example, too.

flatten_images with transparent background using RMagick gem

Seems like I'd be able to find this, but can't turn up anything. Have a short script:
require 'rubygems'
require 'RMagick'
img = Magick::ImageList.new("public/images/dev_banner_background.png")
gc = Magick::Draw.new
img.annotate(gc, 0,0,15,130, "| #{ENV['SERVER_TYPE']} Server |") do
self.pointsize = 13
self.rotation = -45
self.kerning = 1
self.stroke = "#ffffff"
self.fill = "#ffffff"
end
picture = img.flatten_images
picture.write("public/images/dev_banner.png")
dev_banner_background.png is a small banner on a transparent background similar to Github's "Fork me on Github" banner.
Works well to overlay this text on the banner (want to overlay on dev/staging servers). But the resulting images has a white background. Assuming it's in the flatten_images call, but can't figure out how to make it flatten with transparency. Anyone?
Found it.
img = Magick::ImageList.new("public/images/dev_banner_background.png")
img.background_color = "none"
gc = Magick::Draw.new
I was trying to set background color in flatten_images, and in the annotate method. I didn't realize that ImageList had a background_color attribute directly, since I didn't see it in the list of instance methods and attributes. Maybe I just missed it.

How to select color of a specific pixel in Rails?

Is it possible to somehow do the following in rails?
Get the color of a specific pixel from a image (for example at location 10px by 10px)
Delete all occurrences of that color from the image (gets replaced with transparent pixels)
Crop image to exclude any outer transparent pixels
Any advise would be greatly appreciated!
Rails? No.
Ruby? Yes.
Check out RMagick: http://rmagick.rubyforge.org/
Here's the code of how I did it using RMagick (thanks Alex Wayne for pointing me to RMagick)...
require 'RMagick'
img = Magick::Image.read("sample.jpg").first
bgcolor = img.pixel_color(1,1)
img.format = "PNG"
img.fuzz = 0.05
img.trim!
img.resize_to_fit!(100, 40)
bg = Magick::Image.new(100,40) { self.background_color = bgcolor }
img = bg.composite(img, Magick::CenterGravity, Magick::OverCompositeOp)
img.write("modified.png")
For my initial requirement (to just remove the outer colors or blank borders), the following is all you need:
require 'RMagick'
img = Magick::Image.read("sample.jpg").first
img.trim!
img.write("sample.jpg")

Resources