Programmatically determine background of image (logos, etc) and make transparent? - vb.net

I'm attempting to write a solution so that my user's can "watermark" their Images with their Company Logo. I've got the actual watermarking part done and working so now I'm creating the "upload logo" feature so that they can provide me with the Logo they wish to appear watermarked onto their Images.
I'm using VB.NET and this will probably end up in a Web Service that accepts the Logo JPG file, and returns the "altered" Logo. What I need to happen in this Web Service is:
1) Gray-scale the image. Which I have working as well, thanks to this article.
2) Make the background transparent (so the logo looks clean when watermarked onto an image). This is where I'm stuck.
I think for the most part, any logos that are uploaded will have a generic white background but I can't assume that. Is there a way to somehow detect the background of an image or the background colors, so that I may make those colors transparent?
I've downloaded and ran this project from code.google.com, called Transpoint, which is pretty much what I need except I won't be able to have this as a stand-alone app. Also, I think this is written in Python which is foreign to me.
So basically what I need is just a way to determine the background on an Image (if that's even possible?) or even just the background colors so that I may make them transparent. Any help/advice/suggestions would be greatly appreciated!
Thanks,
Lloyd

You could do something like reading the upper-left pixel and assuming that that pixel is representative of the background color, and then iterating through the image and setting the alpha value of each matching pixel (matching by color) to 0.
I can pretty much guarantee you, however, that the result will be awful. For transparency to work properly and look good, the image needs to support partial transparency, such that some pixels are completely transparent whereas some are only partially transparent. Any algorithm that takes a non-transparent image and sets only one color in the image to fully transparent is going to end up with jagged edges.
Most companies I've ever dealt with have versions of their logos done by professional artists, with smooth, partial transparency. You'd be much better off just requiring customers to submit a logo with transparency than trying to make a non-transparent image into a transparent one with code. Sorry, but this just doesn't work.

I think this would actually work (sorry it's just a description):
Assuming the upper-left corner pixel is the image's background color, you could iterate through each pixel in the image and set the alpha to 0 if the pixel color matches the background color (either exactly or within some threshold color distance). This would then leave you with an image with a transparent background but jagged edges when you re-draw it on a different-color background. Also, if the background color is present anywhere inside the image itself, it will be turned transparent, which you don't want.
To fix the latter problem, your algorithm should start scanning each row of the image from left to right, and stop when it reaches a non-background color pixel; at this point it should start on the same row and scan right to left until reaching a non-bg pixel.
To fix the edges, you can just blur the alpha values of the bitmap. Basically, you re-calculate the alpha value of each pixel as the average of 9 pixels (itself and the 8 pixels surrounding it, and just the alpha values - not the rgb values). To prevent sequencing artifacts, you would have a temporary array to store the averaged pixel values, which you would then copy back into the image's alpha values at the end of the process.
Also, there's probably one or more third-party tools that do this (is LEAD Tools still around?).

#MusiGenesis (and anyone else who may be interested) here is what I did to (kind of) solve my problem. I basically followed the first half of your idea. I've created a function that will accept a bitmap, check each pixel against the first pixel at (0,0) - using a threshold of 10 for each RGB color. For each color within that threshold, the pixel is made transparent. Here is my code, which seems to work alright for the few images I've tried it with:
Private Function TransparifyBackground(ByVal bmp As Bitmap) As Bitmap
Dim temp As Color
Dim background As Color = bmp.GetPixel(0, 0) 'top left will be assumed background color
For y As Integer = 0 To bmp.Height - 1
For x As Integer = 0 To bmp.Width - 1
'get the pixel for this position:
temp = bmp.GetPixel(x, y)
If ColorsMatch(background, temp) Then
'Make the Alpha value 50 for each pixel, leaving the other colors
Dim newColor As New Color
newColor = Color.Transparent
bmp.SetPixel(x, y, newColor)
End If
Next
Next
Return bmp
End Function
Private Function ColorsMatch(ByVal background As Color, ByVal temp As Color) As Boolean
Dim nThreshold As Integer = 10
Dim temp_R As Integer = CInt(temp.R)
Dim temp_G As Integer = CInt(temp.G)
Dim temp_B As Integer = CInt(temp.B)
Dim R As Integer = CInt(background.R)
Dim G As Integer = CInt(background.G)
Dim B As Integer = CInt(background.B)
'check the difference of each value against our threshold:
If ((temp_R - R) < nThreshold) AndAlso ((temp_G - G) < nThreshold) AndAlso ((temp_B < B) < nThreshold) Then
Return True
Else
Return False
End If
End Function

Related

How to determine a control size in twips?

I'm developing VB.net application in MS Visual Studio 2019 (community Edition) in which I programatically paste an image from the clipboard into a Richtextbox.
I need to add an option to force that image to completely fill the control's visible area.
Examining the richtext which results from pasting the image, and then again after I've manually dragged the image to resize it to fill the control, it looks like all I need to do is change the picwgoal and pichgoal rtf tags for the image to the dimensions of the control.
The problem is that picwgoal and pichgoal are in twips.
So my question is: Is there a reliable way to dynamically calculate a control's dimensions in twips from it's pixel width and height, such that it will work when the app runs in various resolutions/scaling ?
I understand that the TwipsPerPixelX method is obsolete and not compatable with 64 bit processes.
Thanks in advance.
..Think I've worked it out myself
..Think I've worked it out myself
assuming a point is always 1/72 inches and a point is 20 twips..
Dim g = Me.CreateGraphics()
Dim RTBxTwips = (RTB.Width * 72 / g.DpiX) * 20
Dim RTByTwips = (RTB.Height * 72 / g.DpiY) * 20
g.Dispose()
..seems to give results equal to the picwgoal and pichgoal tags for an image resized to the controls visible area

vb.net- How to make any picture in a picture box round in shape

I am making an application in vb.net that has a good user interface, including the your account icon that includes a picture box. My question is that how can i make that image in the picture box round in shape?
Like This:
https://drive.google.com/open?id=1rUBq68ULDkTiFFv2uEiV_oQIh3wQIfhd
I wouldn't normally provide code for a question that doesn't show an attempt but there are a few steps in the answer and it was easier to just write the code myself than explain them. E.g.
'Get the original image.
Dim originalImage = PictureBox1.Image
'Create a new, blank image with the same dimensions.
Dim croppedImage As New Bitmap(originalImage.Width, originalImage.Height)
'Prepare to draw on the new image.
Using g = Graphics.FromImage(croppedImage)
Dim path As New GraphicsPath
'Create an ellipse that fills the image in both directions.
path.AddEllipse(0, 0, croppedImage.Width, croppedImage.Height)
Dim reg As New Region(path)
'Draw only within the specified ellipse.
g.Clip = reg
g.DrawImage(originalImage, Point.Empty)
End Using
'Display the new image.
PictureBox2.Image = croppedImage
That will create an elliptical image with the same width and height as the original. If the original is square then the final will be circular. If you want a circle regardless of the aspect ratio of the original then you'll have to manipulate that in the appropriate manner.
Though i see that you already found out the solution to your question, however here's a very simple workaround.
Assuming, your project is in WinForms, and you are using Picture Box control. The easiest way to achieve the round-image-look is to set the Image property of the PictureBox to an image that is round-shaped and is blank/transparent in the middle and white on the outside. Then , whatever image you set as a BackgroundImage , it will appear round-ish.
Here's a sample round-transparent image for you which you can set as Image(make sure to set SizeMode to stretch) and then set any picture as BackgroundImage.

Capture color from picturebox

I'm attempting to capture the color of the color(s) primarily used in an icon within a picturebox. An example of this effect is how the windows taskbar (windows 7 and onwards) designates the background color of the application's icon square. I'm just not sure how to go about achieving this effect.
If you can get that into a System.Drawing.Bitmap you can loop over all of the pixels and then count them (group by color). With a lot of colors there could be pixels that are just slightly different that it will count as unique. Linq can also help group those things.
Here is a rough example of how to do it. This uses a WinForms PictureBox that already has an image loaded into it.
' Get a Bitmap from the PictureBox
Dim bm As Bitmap = PictureBox1.Image
Dim colorList As New List(Of System.Drawing.Color)
' One entry for every pixel (so this could get large with a large image)
For x As Integer = 0 To bm.Width - 1
For y As Integer = 0 To bm.Height - 1
colorList.Add(bm.GetPixel(x, y))
Next
Next
' Get the groups of colors with the count of each color that exists and sort them in
' decending order so you know the first one is the most used color
Dim groups = colorList.GroupBy(Function(value) value).OrderByDescending(Function(g) g.Count)
' You can loop over the groups and get their counts this way grp(0) is a color
For Each grp In groups
MsgBox(grp(0).Name & " - " & grp.Count)
Next
I just put them in order, you can pick out the first from the list because you know it will be the most, etc. The linq syntax is a little hard to read but is very useful.

How to move a rotated shape to a specific location in excel 2010 using vba

I've written some VBA code that automatically creates a chart. One of the axes on this chart doesn't use normal labels but a graphic. I've stored the graphic as an image and I use the .Copy and .Paste methods to get a copy of this image onto the chart.
Here is where it gets confusing. I need to rotate the image to get it aligned with the axis (using the .rotation property). But when I set the .top and .left properties the shape doesn't end up where I would expect. In fact setting the properties to 0 and 0 doesn't do what I would expect either. I've tried changing the order of the way I set the properties on the image object but it only appears in a different (wrong) location.
I'm sure I'm missing some vital aspect of how VBA/Excel is placing the object relative to what I'm setting the top and left properties to. Basically my goal is to make the image on the left side of the chart with the same width as the plot area's height (since the image is rotated I theorize this will make it the same size).
This code does not work:
Sheets(ImageSheet).Shapes("agreement").Copy
c.Chart.Paste
c.Chart.Shapes(1).Rotation=270
c.Chart.Shapes(1).width = c.Chart.PlotArea.height
c.Chart.shapes(1).left = 5
c.Chart.Shapes(1).top = c.Chart.PlotArea.top
I've also tried this code
c.chart.Shapes(1).top = c.chart.PlotArea.top + c.Chart.PlotArea.height
because I thought maybe it was calculating the "top" as the upper-left corner of the image object when it is not rotated (rotating 270 degrees makes this point in a place where it should align with the bottom of the plot area). But that doesn't do what I expected either.
The image is a skinny rectangle that acts as a label for the axis. The chart will end up being laid out like this: http://imgur.com/NrSXR and the axis label image would be something like this http://imgur.com/08EWU
What am I missing here?
Is it possible for you to align your chart into a position where the shape could rest align/on a cell?
IF YES then here is a suggestion:-
You could position shape into a cell. Then adjust the size to what you need. And rotate.
Then change its bring forward property be shown on the Chart.
Next Group Chart and the Shape
PS: I recorded a macro. However it's best if you could show us what your the exact picture (=how your sheeet/chart/image should look like) of your question.
I ended up rotating and resizing the image before copying and pasting to the chart and then positioning it. I had to use the IncrementLeft and IncrementTop methods rather than setting the left and top properties directly because that did not have the desired effect.
When doing the paste into the chart the object always ended up in the upper left hand-corner so I could increment to the left by the small amount I wanted as a margin I wanted there and increment the top by the value of PlotArea.top to align it with the plot area.
I was also surprised that when creating the copy of my image it retained the "name" i referred to it as when I copied it to the new sheet and chart. This was especially useful for positioning the image once it was on the chart.
I also needed execute this code at the very end of my procedure, after everything else had been positioned and aligned, or when I positioned the data labels for one of my series they wouldn't appear correctly.
Here is the code that I ended up using:
'make a copy of the label image and refer to it with a variable for convenience
Sheets(ImageSheet).Shapes("maturity").Copy
i = Sheets(ImageSheet).Shapes.Count
Sheets(ImageSheet).Paste
Dim axisImage As Shape
Set axisImage = Sheets(ImageSheet).Shapes(i + 1)
'rotate and resize the image
With axisImage
.Rotation = 270
.width = c.Chart.PlotArea.height
End With
'cut and paste the new image to the chart
axisImage.Cut
c.Chart.Paste
'position it in the chart using IncrementTop and IncrementLeft because setting the properties directly does not have the desired effect
c.Chart.Shapes("maturity").IncrementTop c.Chart.PlotArea.top
c.Chart.Shapes("maturity").IncrementLeft c.Chart.PlotArea.left - c.Chart.Shapes("maturity").height

VB .NET picture GetPixel & SetPixel: Include alpha?

I am trying to use GetPixel and SetPixel to copy the contents of one picture to another (I know there are other methods to do so, but there are reasons I want to try this ;D)
Anyway, the pictures are .png images, so they include transparency settings.
But for some reason, it seems like when I use GetPixel & SetPixel to put one image over another, it seems the second image completely replaces the other one. I mean, it seems the transparency settings are not respected when I use GetPixel & SetPixel.
Both images have the same size. Both have transparent areas.
Before calling SetPixel() you need to call MakeTransparnet(). Here's some code that copies the contents of the first pixel in an alpha-image onto another image and retain's the first image's alpha channel:
Using img1 = New Bitmap("c:\Users\Owner\Desktop\1.png")
PX = img1.GetPixel(0, 0)
End Using
Using img2 = New Bitmap("c:\Users\Owner\Desktop\2.png")
img2.MakeTransparent() '//Sets the transparent value and converts the image to Format32bppArgb
img2.SetPixel(0, 0, PX)
img2.Save("c:\Users\Owner\Desktop\3.png")
End Using