I'm looking to remove all color from WMF image file by only 1 color.
Metafile img = new Metafile(path + strFilename + ".wmf");
float planScale = 0.06615f;
float scale = 1200f / (float)img.Width;
planScale = planScale / scale; ;
float widht = img.Width * scale;
float height = img.Height * scale;
using (var target = new Bitmap((int)widht, (int)height))
{
using (var g = Graphics.FromImage(target))
{
g.DrawImage(img, 0, 0, (int)widht, (int)height);
target.Save("image.png", ImageFormat.Png);
}
}
For the moment, I load a WMF file, set the scale and save it as PNG file.
Example of PNG result:
But now I need to remove all the colors (green, purple....) and set only 1 color like Gray for example.
If the background is always white you can do something like that. You can change the 200 to something you want, to adjust the Color that shouldn't be changed. In this example the white color is not changed. If you don't want to draw black, you can adjust the Color at target.SetPixel(x,y,Color.Black);
Metafile img = new Metafile("D:\\Chrysanthemum.wmf");
float planScale = 0.06615f;
float scale = 1200f / (float)img.Width;
planScale = planScale / scale; ;
float widht = img.Width * scale;
float height = img.Height * scale;
using (var target = new Bitmap((int)widht, (int)height))
{
using (var g = Graphics.FromImage(target))
{
g.DrawImage(img, 0, 0, (int)widht, (int)height);
}
for (int x = 0; x < target.Width; x++)
{
for (int y = 0; y < target.Height; y++)
{
Color white = target.GetPixel(x, y);
if ((int)white.R > 200 || (int)white.G > 200 || (int)white.B > 200)
{
target.SetPixel(x, y, Color.Black);
}
}
}
target.Save("D:\\image.png", ImageFormat.Png);
}
WMF Image:
PNG Image:
I hope that is what you are searching for.
Related
I have an image that looks like this. I have the pointy image which looks good and then I have to draw the green image on top of the pointy image. The idea is to draw the green image in the center of the pointy image. I am having some problems with that.
var shipImageOffset = new PointF(0, 0);
using (var bmp = new Bitmap(_shipImage))
using (var image = ImageUtilities.RotateImage(
bmp,
(float)ShipHeading,
new PointF(this.Width / 2, this.Height / 2),
shipImageOffset,
this.Width,
this.Height))
{
e.Graphics.DrawImage(image, new PointF(0,0));
}
//paint the green pointer image
if (_windImageRepo.TryGetValue(needleSpeed, out var windImage))
{
//need to figure out the origin point - the origin point is the center of the long rectangle
//at the bottom
var center = new PointF(windImage.HorizontalResolution, windImage.VerticalResolution);
using (var bmp = new Bitmap(windImage))
{
for (int x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
var color = bmp.GetPixel(x, y);
if (color != Color.FromArgb(0))
{
bmp.SetPixel(x, y, System.Drawing.Color.LimeGreen);
}
}
}
var windImageOffset = new PointF(0,0);
using (var image = ImageUtilities.RotateImage(
bmp,
(float)WindHeading,
new PointF(this.Width / 2, this.Height / 2),
windImageOffset,
this.Width,
this.Height))
{
//This is your image from the pictureBox1
Bitmap img = new Bitmap(_shipImage);
// I am targeting the middle of the image, Your case would be the binarized image
Point index = new Point(img.Size.Width / 2, img.Size.Height / 2);
e.Graphics.DrawImage(image,Center(_shipImage));
}
}
}
base.OnPaint(e);
}
The objective is to get the green pointer in the middle of other image. Not having luck on that.
I'm trying to resize my picture so it fits the 640x640 size and keep the aspect ratio.
For example, if this is the original picture: http://i.imgur.com/WEMCSyd.jpg
I want to resize in this way: http://i.imgur.com/K2BalOm.jpg to keep the aspect ratio (Basically, the image is always in the middle, and keeps the aspect ratio, the rest of space remains white)
I have tried making a program in C# which has this code:
Bitmap originalImage, resizedImage;
try
{
using (FileStream fs = new FileStream(textBox1.Text, System.IO.FileMode.Open))
{
originalImage = new Bitmap(fs);
}
int imgHeight = 640;
int imgWidth = 640;
if (originalImage.Height == originalImage.Width)
{
resizedImage = new Bitmap(originalImage, imgHeight, imgWidth);
}
else
{
float aspect = originalImage.Width / (float)originalImage.Height;
int newHeight;
int newWidth;
newWidth = (int)(imgWidth / aspect);
newHeight = (int)(newWidth / aspect);
if (newWidth > imgWidth || newHeight > imgHeight)
{
if (newWidth > newHeight)
{
newWidth = newHeight;
newHeight = (int)(newWidth / aspect);
}
else
{
newHeight = newWidth;
newWidth = (int)(newHeight / aspect);
}
}
resizedImage = new Bitmap(originalImage, newWidth, newHeight);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
But it doesn't work the way I need it to.
Let (W, H) be the size of your image. Let s = max(W, H). Then you want to resize the image to (w, h) = (640 * W / s, 640 * H / s) where / denotes integer division. Note that we have w <= 640 and h <= 640 and max(w, h) = 640.
The horizontal and vertical offsets for your image inside of the new (640, 640) image are x = (640 - W) / 2 and y = (640 - H) / 2, respectively.
You can accomplish all of this by creating a new (640, 640) blank white image and then drawing your current image to the rectangle (x, y, w, h).
var sourcePath = textBox1.Text;
var destinationSize = 640;
using (var destinationImage = new Bitmap(destinationSize, destinationSize))
{
using (var graphics = Graphics.FromImage(destinationImage))
{
graphics.Clear(Color.White);
using (var sourceImage = new Bitmap(sourcePath))
{
var s = Math.Max(sourceImage.Width, sourceImage.Height);
var w = destinationSize * sourceImage.Width / s;
var h = destinationSize * sourceImage.Height / s;
var x = (destinationSize - w) / 2;
var y = (destinationSize - h) / 2;
// Use alpha blending in case the source image has transparencies.
graphics.CompositingMode = CompositingMode.SourceOver;
// Use high quality compositing and interpolation.
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.DrawImage(sourceImage, x, y, w, h);
}
}
destinationImage.Save(...);
}
Can u add max-width:100% to image tag. And define your fixed width to parent tag using css. Hope this should work no need to write c# code for the same.
Eg. <figure > <img src="" > </figure>
Css
Figure{ width:600px }
Img { max-width: 100%}
I am asking this question as the other one is two years old and not answered accurately.
I'm looking to replicate the PhotoShop effect mentioned in this article in C#. Adobe call it a Color halftone, I think it looks like some sort of rotated CMYK halftone thingy. Either way I don't know how I would do it.
Current code sample is below.
Any ideas?
P.S.
This isn't homework. I'm looking to upgrade the comic book effect I have in my OSS project ImageProcessor.
Progress Update.
So here's some code to show what I have done so far...
I can convert to and from CMYK to RGB fairly easily and accurately enough for my needs and also print out a patterned series of ellipses based on the the intensity of each colour component at a series of points.
What I am stuck at just now is rotating the graphics object for each colour so that the points are laid at the angles specified in the code. Can anyone give me some pointers as how to go about that?
public Image ProcessImage(ImageFactory factory)
{
Bitmap newImage = null;
Image image = factory.Image;
try
{
int width = image.Width;
int height = image.Height;
// These need to be used.
float cyanAngle = 105f;
float magentaAngle = 75f;
float yellowAngle = 90f;
float keylineAngle = 15f;
newImage = new Bitmap(width, height);
newImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (Graphics graphics = Graphics.FromImage(newImage))
{
// Reduce the jagged edges.
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.Clear(Color.White);
using (FastBitmap sourceBitmap = new FastBitmap(image))
{
for (int y = 0; y < height; y += 4)
{
for (int x = 0; x < width; x += 4)
{
Color color = sourceBitmap.GetPixel(x, y);
if (color != Color.White)
{
CmykColor cmykColor = color;
float cyanBrushRadius = (cmykColor.C / 100) * 3;
graphics.FillEllipse(Brushes.Cyan, x, y, cyanBrushRadius, cyanBrushRadius);
float magentaBrushRadius = (cmykColor.M / 100) * 3;
graphics.FillEllipse(Brushes.Magenta, x, y, magentaBrushRadius, magentaBrushRadius);
float yellowBrushRadius = (cmykColor.Y / 100) * 3;
graphics.FillEllipse(Brushes.Yellow, x, y, yellowBrushRadius, yellowBrushRadius);
float blackBrushRadius = (cmykColor.K / 100) * 3;
graphics.FillEllipse(Brushes.Black, x, y, blackBrushRadius, blackBrushRadius);
}
}
}
}
}
image.Dispose();
image = newImage;
}
catch (Exception ex)
{
if (newImage != null)
{
newImage.Dispose();
}
throw new ImageProcessingException("Error processing image with " + this.GetType().Name, ex);
}
return image;
}
Input Image
Current Output
As you can see since the drawn ellipses are not angled colour output is incorrect.
So here's a working solution. It ain't pretty, it ain't fast (2 seconds on my laptop) but the output is good. It doesn't exactly match Photoshop's output though I think they are performing some additional work.
Slight moiré patterns sometimes appear on different test images but descreening is out of scope for the current question.
The code performs the following steps.
Loop through the pixels of the image at a given interval
For each colour component, CMYK draw an ellipse at a given point which is calculated by rotating the current point by the set angle. The dimensions of this ellipse are determined by the level of each colour component at each point.
Create a new image by looping though the pixel points and adding the CMYK colour component values at each point to determine the correct colour to draw to the image.
Output image
The code
public Image ProcessImage(ImageFactory factory)
{
Bitmap cyan = null;
Bitmap magenta = null;
Bitmap yellow = null;
Bitmap keyline = null;
Bitmap newImage = null;
Image image = factory.Image;
try
{
int width = image.Width;
int height = image.Height;
// Angles taken from Wikipedia page.
float cyanAngle = 15f;
float magentaAngle = 75f;
float yellowAngle = 0f;
float keylineAngle = 45f;
int diameter = 4;
float multiplier = 4 * (float)Math.Sqrt(2);
// Cyan color sampled from Wikipedia page.
Brush cyanBrush = new SolidBrush(Color.FromArgb(0, 153, 239));
Brush magentaBrush = Brushes.Magenta;
Brush yellowBrush = Brushes.Yellow;
Brush keylineBrush;
// Create our images.
cyan = new Bitmap(width, height);
magenta = new Bitmap(width, height);
yellow = new Bitmap(width, height);
keyline = new Bitmap(width, height);
newImage = new Bitmap(width, height);
// Ensure the correct resolution is set.
cyan.SetResolution(image.HorizontalResolution, image.VerticalResolution);
magenta.SetResolution(image.HorizontalResolution, image.VerticalResolution);
yellow.SetResolution(image.HorizontalResolution, image.VerticalResolution);
keyline.SetResolution(image.HorizontalResolution, image.VerticalResolution);
newImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
// Check bounds against this.
Rectangle rectangle = new Rectangle(0, 0, width, height);
using (Graphics graphicsCyan = Graphics.FromImage(cyan))
using (Graphics graphicsMagenta = Graphics.FromImage(magenta))
using (Graphics graphicsYellow = Graphics.FromImage(yellow))
using (Graphics graphicsKeyline = Graphics.FromImage(keyline))
{
// Ensure cleared out.
graphicsCyan.Clear(Color.Transparent);
graphicsMagenta.Clear(Color.Transparent);
graphicsYellow.Clear(Color.Transparent);
graphicsKeyline.Clear(Color.Transparent);
// This is too slow. The graphics object can't be called within a parallel
// loop so we have to do it old school. :(
using (FastBitmap sourceBitmap = new FastBitmap(image))
{
for (int y = -height * 2; y < height * 2; y += diameter)
{
for (int x = -width * 2; x < width * 2; x += diameter)
{
Color color;
CmykColor cmykColor;
float brushWidth;
// Cyan
Point rotatedPoint = RotatePoint(new Point(x, y), new Point(0, 0), cyanAngle);
int angledX = rotatedPoint.X;
int angledY = rotatedPoint.Y;
if (rectangle.Contains(new Point(angledX, angledY)))
{
color = sourceBitmap.GetPixel(angledX, angledY);
cmykColor = color;
brushWidth = diameter * (cmykColor.C / 255f) * multiplier;
graphicsCyan.FillEllipse(cyanBrush, angledX, angledY, brushWidth, brushWidth);
}
// Magenta
rotatedPoint = RotatePoint(new Point(x, y), new Point(0, 0), magentaAngle);
angledX = rotatedPoint.X;
angledY = rotatedPoint.Y;
if (rectangle.Contains(new Point(angledX, angledY)))
{
color = sourceBitmap.GetPixel(angledX, angledY);
cmykColor = color;
brushWidth = diameter * (cmykColor.M / 255f) * multiplier;
graphicsMagenta.FillEllipse(magentaBrush, angledX, angledY, brushWidth, brushWidth);
}
// Yellow
rotatedPoint = RotatePoint(new Point(x, y), new Point(0, 0), yellowAngle);
angledX = rotatedPoint.X;
angledY = rotatedPoint.Y;
if (rectangle.Contains(new Point(angledX, angledY)))
{
color = sourceBitmap.GetPixel(angledX, angledY);
cmykColor = color;
brushWidth = diameter * (cmykColor.Y / 255f) * multiplier;
graphicsYellow.FillEllipse(yellowBrush, angledX, angledY, brushWidth, brushWidth);
}
// Keyline
rotatedPoint = RotatePoint(new Point(x, y), new Point(0, 0), keylineAngle);
angledX = rotatedPoint.X;
angledY = rotatedPoint.Y;
if (rectangle.Contains(new Point(angledX, angledY)))
{
color = sourceBitmap.GetPixel(angledX, angledY);
cmykColor = color;
brushWidth = diameter * (cmykColor.K / 255f) * multiplier;
// Just using blck is too dark.
keylineBrush = new SolidBrush(CmykColor.FromCmykColor(0, 0, 0, cmykColor.K));
graphicsKeyline.FillEllipse(keylineBrush, angledX, angledY, brushWidth, brushWidth);
}
}
}
}
// Set our white background.
using (Graphics graphics = Graphics.FromImage(newImage))
{
graphics.Clear(Color.White);
}
// Blend the colors now to mimic adaptive blending.
using (FastBitmap cyanBitmap = new FastBitmap(cyan))
using (FastBitmap magentaBitmap = new FastBitmap(magenta))
using (FastBitmap yellowBitmap = new FastBitmap(yellow))
using (FastBitmap keylineBitmap = new FastBitmap(keyline))
using (FastBitmap destinationBitmap = new FastBitmap(newImage))
{
Parallel.For(
0,
height,
y =>
{
for (int x = 0; x < width; x++)
{
// ReSharper disable AccessToDisposedClosure
Color cyanPixel = cyanBitmap.GetPixel(x, y);
Color magentaPixel = magentaBitmap.GetPixel(x, y);
Color yellowPixel = yellowBitmap.GetPixel(x, y);
Color keylinePixel = keylineBitmap.GetPixel(x, y);
CmykColor blended = cyanPixel.AddAsCmykColor(magentaPixel, yellowPixel, keylinePixel);
destinationBitmap.SetPixel(x, y, blended);
// ReSharper restore AccessToDisposedClosure
}
});
}
}
cyan.Dispose();
magenta.Dispose();
yellow.Dispose();
keyline.Dispose();
image.Dispose();
image = newImage;
}
catch (Exception ex)
{
if (cyan != null)
{
cyan.Dispose();
}
if (magenta != null)
{
magenta.Dispose();
}
if (yellow != null)
{
yellow.Dispose();
}
if (keyline != null)
{
keyline.Dispose();
}
if (newImage != null)
{
newImage.Dispose();
}
throw new ImageProcessingException("Error processing image with " + this.GetType().Name, ex);
}
return image;
}
Additional code for rotating the pixels is as follows. This can be found at Rotating a point around another point
I've left out the colour addition code for brevity.
/// <summary>
/// Rotates one point around another
/// <see href="https://stackoverflow.com/questions/13695317/rotate-a-point-around-another-point"/>
/// </summary>
/// <param name="pointToRotate">The point to rotate.</param>
/// <param name="centerPoint">The centre point of rotation.</param>
/// <param name="angleInDegrees">The rotation angle in degrees.</param>
/// <returns>Rotated point</returns>
private static Point RotatePoint(Point pointToRotate, Point centerPoint, double angleInDegrees)
{
double angleInRadians = angleInDegrees * (Math.PI / 180);
double cosTheta = Math.Cos(angleInRadians);
double sinTheta = Math.Sin(angleInRadians);
return new Point
{
X =
(int)
((cosTheta * (pointToRotate.X - centerPoint.X)) -
((sinTheta * (pointToRotate.Y - centerPoint.Y)) + centerPoint.X)),
Y =
(int)
((sinTheta * (pointToRotate.X - centerPoint.X)) +
((cosTheta * (pointToRotate.Y - centerPoint.Y)) + centerPoint.Y))
};
}
I have a method that takes in a bitmap object and overlays dates and times strings over it and returns that new bitmap. The code is below.
public static Bitmap overlayBitmap(Bitmap sourceBMP, int width, int height, List<String> times, List<String> dates, IEnumerable<Color> colors) {
// Determine the new width
float newWidth = width + (width / 3.0f);
float newHeight = height + (height / 3.0f);
// Intelligent vertical + horizontal text distance calculator
float verticalDistance = height / (times.Count - 1.0f);
float horizontalDistance = width / (dates.Count - 1.0f);
Bitmap result = new Bitmap((int)newWidth, (int)newHeight);
using (Graphics g = Graphics.FromImage(result)) {
// Background color
Brush brush = new SolidBrush(colors.First());
g.FillRectangle(brush, 0, 0, newWidth, newHeight);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
// Times text configs
StringFormat stringFormatTimes = new StringFormat();
stringFormatTimes.LineAlignment = StringAlignment.Center;
stringFormatTimes.Alignment = StringAlignment.Center;
Font drawFontY = new Font("Whitney", newHeight / 70);
// Dates text configs
StringFormat stringFormatDates = new StringFormat();
stringFormatDates.LineAlignment = StringAlignment.Center;
stringFormatTimes.Alignment = StringAlignment.Center;
stringFormatDates.FormatFlags = StringFormatFlags.DirectionVertical;
Font drawFontX = new Font("Whitney", newHeight / 70);
// Location of times text
for (int i = 0; i < times.Count; i++) {
if (i % determineIncrementTimes(times.Count) == 0) {
g.DrawString(times[i], drawFontX, Brushes.White, (((newWidth - width) / 2) / 2), ((newHeight - height) / 2) + (verticalDistance * i), stringFormatTimes);
}
}
// Location of dates text
for (int i = 0; i < dates.Count; i++) {
if (i % determineIncrementDates(dates.Count) == 0) {
g.DrawString(dates[i], drawFontY, Brushes.White, ((newWidth - width) / 2) + (horizontalDistance * i), ((newHeight - height) / 2) + height, stringFormatDates);
}
}
// New X and Y Position of the sourceBMP within the new BMP.
int XPos = width / 6;
int YPos = height / 6;
// Int -> Float casting for the outline
float fXPos = width / 6.0f;
float fYPos = height / 6.0f;
float fWidth = width / 1.0f;
float fHeight = height / 1.0f;
// Draw new image at the position width/6 and height/6 with the size at width and height
g.DrawImage(sourceBMP, fXPos, fYPos, fWidth, fHeight);
g.DrawRectangle(Pens.White, fXPos, fYPos, fWidth, fHeight); // white outline
g.Dispose();
}
return result;
}
My concern is, I would like to be able, for the next developer, to easily access and set particular values that currently I've only "hardcoded" in. An example being the x-position of the time text calculated via this snippet of code:
(((newWidth - width) / 2) / 2)
Realistically I'd like to have the developer be able to access and/or set this value through simply typing in:
something.XPos = [someFloat];
How my method above is used (is pseudo-code) is as the following:
private readonly Bitmap _image;
private readonly Bitmap _overlayedImage;
public myConstructor(int someInputValues){
// some code that generates the first bitmap called _image
_newImage = overlayImage(_image, ....);
}
For reference this is the image drawn:
My question is - since some values need to be casted and initialized first, can I set my instance variables at the end of the method, before the closing brace?
public Bitmap overlayBitmap
{
get
{
// Build bitmap overlay
return overlayBitmapOutput;
}
...
}
[Edit: Answer Insufficient >> Wait]
How to resample an image to square, padding with white background in c# preferable without using any 3rd party libraries (.Net framework only)?
Thanks!
This can actually be done pretty easily.
public static Image PadImage(Image originalImage)
{
int largestDimension = Math.Max(originalImage.Height, originalImage.Width);
Size squareSize = new Size(largestDimension, largestDimension);
Bitmap squareImage = new Bitmap(squareSize.Width, squareSize.Height);
using (Graphics graphics = Graphics.FromImage(squareImage))
{
graphics.FillRectangle(Brushes.White, 0, 0, squareSize.Width, squareSize.Height);
graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
graphics.DrawImage(originalImage, (squareSize.Width / 2) - (originalImage.Width / 2), (squareSize.Height / 2) - (originalImage.Height / 2), originalImage.Width, originalImage.Height);
}
return squareImage;
}
Try using this method. The last argument is a switch for whether you want to stretch the image to fit. If false, the image is centered inside the new white canvas. You can pass a square or non-square size to it as needed.
public static Bitmap ResizeBitmapOnWhiteCanvas(Bitmap bmpOriginal, Size szTarget, bool Stretch)
{
Bitmap result = new Bitmap(szTarget.Width, szTarget.Height);
using (Graphics g = Graphics.FromImage((Image)result))
{
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.FillRectangle(Brushes.White, new Rectangle(0, 0, szTarget.Width, szTarget.Height));
if (Stretch)
{
g.DrawImage(bmpOriginal, 0, 0, szTarget.Width, szTarget.Height); // fills the square (stretch)
}
else
{
float OriginalAR = bmpOriginal.Width / bmpOriginal.Height;
float TargetAR = szTarget.Width / szTarget.Height;
if (OriginalAR >= TargetAR)
{
// Original is wider than target
float X = 0F;
float Y = ((float)szTarget.Height / 2F) - ((float)szTarget.Width / (float)bmpOriginal.Width * (float)bmpOriginal.Height) / 2F;
float Width = szTarget.Width;
float Height = (float)szTarget.Width / (float)bmpOriginal.Width * (float)bmpOriginal.Height;
g.DrawImage(bmpOriginal, X, Y, Width, Height);
}
else
{
// Original is narrower than target
float X = ((float)szTarget.Width / 2F) - ((float)szTarget.Height / (float)bmpOriginal.Height * (float)bmpOriginal.Width) / 2F;
float Y = 0F;
float Width = (float)szTarget.Height / (float)bmpOriginal.Height * (float)bmpOriginal.Width;
float Height = szTarget.Height;
g.DrawImage(bmpOriginal, X, Y, Width, Height);
}
}
}
return result;
}
You don't say how you want it padded. Assuming you want the image centered, with the image file name in imageFileName and the desired output file name in newFileName:
Bitmap orig = new Bitmap(imageFileName);
int dim = Math.Max(orig.Width, orig.Height);
Bitmap dest;
using (Graphics origG = Graphics.FromImage(orig))
{
dest = new Bitmap(dim, dim, origG);
}
using (Graphics g = Graphics.FromImage(dest))
{
Pen white = new Pen(Color.White, 22);
g.FillRectangle(new SolidBrush(Color.White), 0, 0, dim, dim);
g.DrawImage(orig, new Point((dim - orig.Width) / 2, (dim - orig.Height) / 2));
}
dest.Save(newFileName);