How to draw a rainbow line using Graphic class c# - c#

So i'm trying to create infinite rainbow line. Here ColorUtils class How do I get a rainbow color gradient in C#? (I'm using Framework 4.7.3
int rainbowStage = 0;
int rainbowNext = 0;
private void Form1_Paint(object sender, PaintEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
PointF point1 = new PointF(100.0F, 100.0F);
PointF point2 = new PointF(235.0F, 100.0F);
worker.DoWork += async delegate (object s, DoWorkEventArgs args)
{
do
{
Console.WriteLine(await getRainbow());
rainbowNext++;
Pen pen = new Pen(await getRainbow(), 3);
e.Graphics.DrawLine(pen, point1, point2);
e.Graphics.Clear(Color.FromArgb(26, 26, 26));
} while (rainbowStage == rainbowNext);
};
worker.RunWorkerCompleted += delegate (object s, RunWorkerCompletedEventArgs args)
{
rainbowStage++;
};
}
async Task<ColorUtils.ColorRGB> getRainbow()
{
for (double i = 0; i < 1; i += 0.01)
{
ColorUtils.ColorRGB c = ColorUtils.HSL2RGB(i, 0.5, 0.5);
return c;
}
ColorUtils.ColorRGB c1 = ColorUtils.HSL2RGB(0, 0.5, 0.5);
return c1;
}

So, you have found how to generate a sequence of rainbow colors. But your code is not actually correct, it should be something like:
IEnumerable<Color> GetRainbow()
{
for (double i = 0; i < 1; i += 0.1)
{
Color c = ColorUtils.HSL2RGB(i, 0.5, 0.5);
yield return c;
}
}
That will give you a sequence of ten colors, using the actual color type used by winforms.
To draw the rainbow we need to draw each color as a separate line, slightly offset from each other. To get the offset we need to do some vector math:
var dir = point1 - point2;
var offset= new PointF(dir.Y, -dir.X).Normalize();
...
public static PointF Normalize(this PointF A)
{
float distance = Math.Sqrt(A.X * A.X + A.Y * A.Y);
return new PointF(A.X / distance, A.Y / distance);
}
public static PointF Mul(this PointF a, float b)
{
return new PointF(a.X * b, a.Y * b);
}
We can then begin drawing our line:
var colors = GetRainbow().ToList();
var width = 10f / colors.Count;
for(int i = 0; i < colors.Count; i++){
using var pen = new Pen(colors[i], width);
var o = offset.Mul( width * i)
e.Graphics.DrawLine(pen, point1 + o, point2 + o);
}
That should give you a rainbow line of with 10 with one pixel per color, adjust the width literal to get a wider line.
An alternative approach would be to create something like a texture brush displaying the rainbow and use that for drawing.
Note that all drawing code need to be run on the UI thread, and any other calculations are really fast, they just involve a handful of simple math operations. So there is nothing at all to be gained from trying to run anything on any background thread.

Here's a copy, paste, run, version of what you're trying to do:
public class Form1 : Form
{
public Form1()
{
this.Paint += Form1_Paint;
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
foreach (var rgb in GetRainbow().Select((colour, indexer) => (colour, indexer)))
{
Console.WriteLine(rgb.colour);
using (Pen pen = new Pen(rgb.colour, 3))
{
e.Graphics.DrawLine(pen, new PointF(100.0F, 100.0F + rgb.indexer), new PointF(235.0F, 100.0F + rgb.indexer));
}
}
}
IEnumerable<ColorRGB> GetRainbow()
{
for (double i = 0; i < 1; i += 0.01)
{
yield return HSL2RGB(i, 0.5, 0.5);
}
}
public struct ColorRGB
{
public byte R;
public byte G;
public byte B;
public ColorRGB(Color value)
{
this.R = value.R;
this.G = value.G;
this.B = value.B;
}
public static implicit operator Color(ColorRGB rgb)
{
Color c = Color.FromArgb(rgb.R, rgb.G, rgb.B);
return c;
}
public static explicit operator ColorRGB(Color c)
{
return new ColorRGB(c);
}
}
public static ColorRGB HSL2RGB(double h, double sl, double l)
{
double v;
double r, g, b;
r = l; // default to gray
g = l;
b = l;
v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl);
if (v > 0)
{
double m;
double sv;
int sextant;
double fract, vsf, mid1, mid2;
m = l + l - v;
sv = (v - m) / v;
h *= 6.0;
sextant = (int)h;
fract = h - sextant;
vsf = v * sv * fract;
mid1 = m + vsf;
mid2 = v - vsf;
switch (sextant)
{
case 0:
r = v;
g = mid1;
b = m;
break;
case 1:
r = mid2;
g = v;
b = m;
break;
case 2:
r = m;
g = v;
b = mid1;
break;
case 3:
r = m;
g = mid2;
b = v;
break;
case 4:
r = mid1;
g = m;
b = v;
break;
case 5:
r = v;
g = m;
b = mid2;
break;
}
}
ColorRGB rgb;
rgb.R = Convert.ToByte(r * 255.0f);
rgb.G = Convert.ToByte(g * 255.0f);
rgb.B = Convert.ToByte(b * 255.0f);
return rgb;
}
}
When run, I get this:
There were too many things going wrong with your original code, but don't use async/await, don't forget to dispose disposables, don't forget to compute the actual line you're trying to draw, use yield return to get your rainbow colours, etc.

Related

Implementing Floyd-Steinberg Dithering in C# with specific Palette

I am making a program where I want to take an image and reduce its color palette to a preset palette of 60 colors, and then add a dithering effect. This seems to involve two things:
A color distance algorithm that goes through each pixel, gets its color, and then changes it to the color closest to it in the palette so that that image doesn't have colors that are not contained in the palette.
A dithering algorithm that goes through the color of each pixel and diffuses the difference between the original color and the new palette color chosen across the surrounding pixels.
After reading about color difference, I figured I would use either the CIE94 or CIEDE2000 algorithm for finding the closest color from my list. I also decided to use the fairly common Floyd–Steinberg dithering algorithm for the dithering effect.
Over the past 2 days I have written my own versions of these algorithms, pulled other versions of them from examples on the internet, tried them both first in Java and now C#, and pretty much every single time the output image has the same issue. Some parts of it look perfectly fine, have the correct colors, and are dithered properly, but then other parts (and sometimes the entire image) end up way too bright, are completely white, or all blur together. Usually darker images or darker parts of images turn out fine, but any part that is bright or has lighter colors at all gets turned up way brighter. Here is an example of an input and output image with these issues:
Input:
]3
Output:
I do have one idea for what may be causing this. When a pixel is sent through the "nearest color" function, I have it output its RGB values and it seems like some of them have their R value (and potentially other values??) pushed way higher than they should be, and even sometimes over 255 as shown in the screenshot. This does NOT happen for the earliest pixels in the image, only for ones that are multiple pixels in already and are already somewhat bright. This leads me to believe it is the dithering/error algorithm doing this, and not the color conversion or color difference algorithms. If that is the issue, then how would I go about fixing that?
Here's the relevant code and functions I'm using. At this point it's a mix of stuff I wrote and stuff I've found in libraries or other StackOverflow posts. I believe the main dithering algorithm and C3 class are copied basically directly from this Github page (and changed to work with C#, obviously)
class Program
{
public static C3[] palette = new C3[]{
new C3(196, 76, 86),
new C3(186, 11, 39),
new C3(113, 0, 32),
new C3(120, 41, 56),
new C3(203, 125, 84),
new C3(205, 90, 40),
new C3(175, 50, 33),
new C3(121, 61, 54),
// etc... palette is 60 colors total
// each object contains an r, g, and b value
};
static void Main(string[] args)
{
// paths for original image and output path for dithered image
string path = #"C:\Users\BillehBawb\Desktop\";
string imgPath = path + "amy.jpg";
string createPath = path + "amydithered.jpg";
// pulls the original image, runs the dithering function, then saves the new image
Bitmap img = new Bitmap(imgPath);
Bitmap dithered = floydSteinbergDithering(img);
dithered.Save(createPath, ImageFormat.Jpeg);
}
// loops through every pixel in the image, populates a 2d array with the pixel colors, then loops through again to change the color to one in the palette and do the dithering algorithm
private static Bitmap floydSteinbergDithering(Bitmap img)
{
int w = img.Width;
int h = img.Height;
C3[,] d = new C3[h, w];
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
d[y, x] = new C3(img.GetPixel(x, y).ToArgb());
}
}
for (int y = 0; y < img.Height; y++)
{
for (int x = 0; x < img.Width; x++)
{
C3 oldColor = d[y, x];
C3 newColor = findClosestPaletteColor(oldColor, palette);
img.SetPixel(x, y, newColor.toColor());
C3 err = oldColor.sub(newColor);
if (x + 1 < w)
{
d[y, x + 1] = d[y, x + 1].add(err.mul(7.0 / 16));
}
if (x - 1 >= 0 && y + 1 < h)
{
d[y + 1, x - 1] = d[y + 1, x - 1].add(err.mul(3.0 / 16));
}
if (y + 1 < h)
{
d[y + 1, x] = d[y + 1, x].add(err.mul(5.0 / 16));
}
if (x + 1 < w && y + 1 < h)
{
d[y + 1, x + 1] = d[y + 1, x + 1].add(err.mul(1.0 / 16));
}
}
}
return img;
}
// loops through the palette, converts the input pixel and palette colors to the LAB format, finds the difference between all of them, and selects the palette color with the lowest difference
private static C3 findClosestPaletteColor(C3 c, C3[] palette)
{
double[] pixelLab = rgbToLab(c.toColor().R, c.toColor().G, c.toColor().B);
double minDist = Double.MaxValue;
int colorIndex = 0;
for (int i = 0; i < palette.Length; i++)
{
double[] colors = rgbToLab(palette[i].toColor().R, palette[i].toColor().G, palette[i].toColor().B);
double dist = labDist(pixelLab[0], pixelLab[1], pixelLab[2], colors[0], colors[1], colors[2]);
if (dist < minDist)
{
colorIndex = i;
minDist = dist;
}
}
return palette[colorIndex];
}
// finds the deltaE/difference between two sets of LAB colors with the CIE94 algorithm
public static double labDist(double l1, double a1, double b1, double l2, double a2, double b2)
{
var deltaL = l1 - l2;
var deltaA = a1 - a2;
var deltaB = b1 - b2;
var c1 = Math.Sqrt(Math.Pow(a1, 2) + Math.Pow(b1, 2));
var c2 = Math.Sqrt(Math.Pow(a2, 2) + Math.Pow(b2, 2));
var deltaC = c1 - c2;
var deltaH = Math.Pow(deltaA, 2) + Math.Pow(deltaB, 2) - Math.Pow(deltaC, 2);
deltaH = deltaH < 0 ? 0 : Math.Sqrt(deltaH);
double sl = 1.0;
double kc = 1.0;
double kh = 1.0;
double Kl = 1.0;
double K1 = .045;
double K2 = .015;
var sc = 1.0 + K1 * c1;
var sh = 1.0 + K2 * c1;
var i = Math.Pow(deltaL / (Kl * sl), 2) +
Math.Pow(deltaC / (kc * sc), 2) +
Math.Pow(deltaH / (kh * sh), 2);
var finalResult = i < 0 ? 0 : Math.Sqrt(i);
return finalResult;
}
// converts RGB colors to the XYZ and then LAB format so the color difference algorithm can be done
public static double[] rgbToLab(int R, int G, int B)
{
float[] xyz = new float[3];
float[] lab = new float[3];
float[] rgb = new float[3];
rgb[0] = R / 255.0f;
rgb[1] = G / 255.0f;
rgb[2] = B / 255.0f;
if (rgb[0] > .04045f)
{
rgb[0] = (float)Math.Pow((rgb[0] + .055) / 1.055, 2.4);
}
else
{
rgb[0] = rgb[0] / 12.92f;
}
if (rgb[1] > .04045f)
{
rgb[1] = (float)Math.Pow((rgb[1] + .055) / 1.055, 2.4);
}
else
{
rgb[1] = rgb[1] / 12.92f;
}
if (rgb[2] > .04045f)
{
rgb[2] = (float)Math.Pow((rgb[2] + .055) / 1.055, 2.4);
}
else
{
rgb[2] = rgb[2] / 12.92f;
}
rgb[0] = rgb[0] * 100.0f;
rgb[1] = rgb[1] * 100.0f;
rgb[2] = rgb[2] * 100.0f;
xyz[0] = ((rgb[0] * .412453f) + (rgb[1] * .357580f) + (rgb[2] * .180423f));
xyz[1] = ((rgb[0] * .212671f) + (rgb[1] * .715160f) + (rgb[2] * .072169f));
xyz[2] = ((rgb[0] * .019334f) + (rgb[1] * .119193f) + (rgb[2] * .950227f));
xyz[0] = xyz[0] / 95.047f;
xyz[1] = xyz[1] / 100.0f;
xyz[2] = xyz[2] / 108.883f;
if (xyz[0] > .008856f)
{
xyz[0] = (float)Math.Pow(xyz[0], (1.0 / 3.0));
}
else
{
xyz[0] = (xyz[0] * 7.787f) + (16.0f / 116.0f);
}
if (xyz[1] > .008856f)
{
xyz[1] = (float)Math.Pow(xyz[1], 1.0 / 3.0);
}
else
{
xyz[1] = (xyz[1] * 7.787f) + (16.0f / 116.0f);
}
if (xyz[2] > .008856f)
{
xyz[2] = (float)Math.Pow(xyz[2], 1.0 / 3.0);
}
else
{
xyz[2] = (xyz[2] * 7.787f) + (16.0f / 116.0f);
}
lab[0] = (116.0f * xyz[1]) - 16.0f;
lab[1] = 500.0f * (xyz[0] - xyz[1]);
lab[2] = 200.0f * (xyz[1] - xyz[2]);
return new double[] { lab[0], lab[1], lab[2] };
}
}
And here is the C3 class, its basically just the Color class with some math functions to make it cleaner to do the dithering on
class C3
{
int r, g, b;
public C3(int c)
{
Color color = Color.FromArgb(c);
r = color.R;
g = color.G;
b = color.B;
}
public C3(int r, int g, int b)
{
this.r = r;
this.g = g;
this.b = b;
}
public C3 add(C3 o)
{
return new C3(r + o.r, g + o.g, b + o.b);
}
public int clamp(int c)
{
return Math.Max(0, Math.Min(255, c));
}
public int diff(C3 o)
{
int Rdiff = o.r - r;
int Gdiff = o.g - g;
int Bdiff = o.b - b;
int distanceSquared = Rdiff * Rdiff + Gdiff * Gdiff + Bdiff * Bdiff;
return distanceSquared;
}
public C3 mul(double d)
{
return new C3((int)(d * r), (int)(d * g), (int)(d * b));
}
public C3 sub(C3 o)
{
return new C3(r - o.r, g - o.g, b - o.b);
}
public Color toColor()
{
return Color.FromArgb(clamp(r), clamp(g), clamp(b));
}
public int toRGB()
{
return toColor().ToArgb();
}
}
Sorry for the massive code dump, the functions are just pretty large and I want to provide everything I can. If anyone has any suggestions on a simpler or different way to do this, or if you know how to fix the issue I'm running into, please let me know. I have tried quite a few different algorithms for my desired result but I haven't been able to get any of them to do what I want them to. Any help or ideas are greatly appreciated, thank you!
It appears that when you shift the error to the neighbors in floydSteinbergDithering() the r,g,b values never get clamped until you cast them back to Color.
Since you're using int and not byte there is no prevention of overflows to negative or large values greater than 255 for r, g, and b.
You should consider implementing r,g, and b as properties that clamp to 0-255 when they're set.
This will ensure their values will never be outside your expected range (0 - 255).
class C3
{
private int r;
public int R
{
get => r;
set
{
r = clamp(value);
}
}
private int g;
public int G
{
get => g;
set
{
g = clamp(value);
}
}
private int b;
public int B
{
get => b;
set
{
b = clamp(value);
}
}
// rest of class
}

Plasma effect in WinForms, how to create continous loop

I'm trying to create some simple graphics ("plasma" effect) with C# and Winforms.
I have two classes in my code, (main)Form1 and Plasmadraw.
In Plasmadraw I have following setup:
class Plasmadraw
{
int y;
int x;
double i;
double pii = 3.1415;
public void Draw(Graphics gfx, int addition)
{
for (int i = 0; i < 23040; i++)
{
x = x + 10;
if (x == 1920)
{
x = 0;
y = y + 10;
}
if (y == 1200)
{
y = 0;
}
double v = Math.Sin((x * 0.5) + i * 0.001 * addition);
double c = v * pii;
double d = c + (2 * pii / 3);
double f = c + (6 * pii / 3);
double r = 255 * Math.Abs(Math.Sin(c));
double g = 255 * Math.Abs(Math.Sin(d));
double b = 255 * Math.Abs(Math.Sin(f));
int r1 = (int)r;
int g1 = (int)g;
int b1 = (int)b;
Color e = Color.FromArgb(r1, g1, b1);
SolidBrush brush = new SolidBrush(e);
Rectangle rect = new Rectangle(x, y, 10, 10);
gfx.FillRectangle(brush, rect);
}
}
}
and then in Form1 I have Paint event:
private void Form1_Paint(object sender, PaintEventArgs e)
{
Plasmadraw plasmaeffect = new Plasmadraw();
for (int a = 0; a < 30; a++)
{
plasmaeffect.Draw(e.Graphics, a);
Invalidate();
}
Is this somehow completely wrong way to build the logic ? I've managed to create some graphics effects (moving sprites etc.) by creating a list and then running through the list with Foreach in Paint event (& Invalidate()). However, I'd like to learn some new way to do things, rather than copying the old way.

Fractal renderer not displaying image at all?

I'm converting a fractal renderer from Java to C# for an assignment and I think I have everything set up but the fractal itself won't render.
This is a photo of when I run the program:
And here is how my files are laid out in the folder that contains the project itself:
This is the code that I am using for the actually rendering itself which I think has no errors but if I've missed something extremely obvious then I'm sorry for wasting all of your time:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
init();
start();
this.DoubleBuffered = true;
}
//code to convert HSB to RGB from HSB.cs. All your code so i made it take up less space.
public struct HSBColor
{
float h;
float s;
float b;
int a;
public HSBColor(float h, float s, float b) { this.a = 0xff; this.h = Math.Min(Math.Max(h, 0), 255); this.s = Math.Min(Math.Max(s, 0), 255); this.b = Math.Min(Math.Max(b, 0), 255); }
public HSBColor(int a, float h, float s, float b) { this.a = a; this.h = Math.Min(Math.Max(h, 0), 255); this.s = Math.Min(Math.Max(s, 0), 255); this.b = Math.Min(Math.Max(b, 0), 255); }
public float H { get { return h; } }
public float S { get { return s; } }
public float B { get { return b; } }
public int A { get { return a; } }
public Color Color { get { return FromHSB(this); } }
public static Color FromHSB(HSBColor hsbColor)
{
float r = hsbColor.b;
float g = hsbColor.b;
float b = hsbColor.b;
if (hsbColor.s != 0)
{
float max = hsbColor.b; float dif = hsbColor.b * hsbColor.s / 255f; float min = hsbColor.b - dif; float h = hsbColor.h * 360f / 255f;
if (h < 60f) { r = max; g = h * dif / 60f + min; b = min; }
else if (h < 120f) { r = -(h - 120f) * dif / 60f + min; g = max; b = min; }
else if (h < 180f) { r = min; g = max; b = (h - 120f) * dif / 60f + min; }
else if (h < 240f) { r = min; g = -(h - 240f) * dif / 60f + min; b = max; }
else if (h < 300f) { r = (h - 240f) * dif / 60f + min; g = min; b = max; }
else if (h <= 360f) { r = max; g = min; b = -(h - 360f) * dif / 60 + min; }
else { r = 0; g = 0; b = 0; }
}
return Color.FromArgb(hsbColor.a, (int)Math.Round(Math.Min(Math.Max(r, 0), 255)), (int)Math.Round(Math.Min(Math.Max(g, 0), 255)), (int)Math.Round(Math.Min(Math.Max(b, 0), 255)));
}
}
private const int MAX = 256; // max iterations
private const double SX = -2.025; // start value real
private const double SY = -1.125; // start value imaginary
private const double EX = 0.6; // end value real
private const double EY = 1.125; // end value imaginary
private static int x1, y1, xs, ys, xe, ye;
private static double xstart, ystart, xende, yende, xzoom, yzoom;
private static float xy;
private int c = 0;
//private Image picture; Taken out, not needed
// create rectangle variable JGB
Rectangle rec;
private Graphics g1;
//private Cursor c1, c2; Taken out, not needed
private System.Drawing.Bitmap bitmap;
public void init()
{
//setSize(640, 480); changed this code to JGB:
this.Size = new Size(640, 480);
// Taken all lines out below. Not needed.
/*finished = false;
addMouseListener(this);
addMouseMotionListener(this);
c1 = new Cursor(Cursor.WAIT_CURSOR);
c2 = new Cursor(Cursor.CROSSHAIR_CURSOR); */
x1 = 640;
y1 = 480;
xy = (float)x1 / (float)y1;
//picture = createImage(x1, y1); Taken out and replaced with JGB:
bitmap = new Bitmap(x1, y1);
//g1 = picture.getGraphics(); changed to get my bitmap
g1 = Graphics.FromImage(bitmap);
//finished = true; Finished variable deleted so not needed
}
//Code below didnt appear to do anything so i deleted it
/*public void destroy() // delete all instances
{
if (finished)
{
removeMouseListener(this);
removeMouseMotionListener(this);
picture = null;
g1 = null;
c1 = null;
c2 = null;
System.gc(); // garbage collection
}
} */
public void start()
{
//action = false;
//rectangle = false;
initvalues();
// added dialog box for instance loading and save varaibles needed for position and zoom to text file
DialogResult dialog = MessageBox.Show("Would You Like to Load Your Last Instance?", "Load Instance?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if (dialog == DialogResult.Yes)
{
string[] lines = System.IO.File.ReadAllLines(#"C:\Users\Public\Writelines.txt");
xzoom = System.Convert.ToDouble(lines[0]);
yzoom = System.Convert.ToDouble(lines[1]);
xstart = System.Convert.ToDouble(lines[2]);
ystart = System.Convert.ToDouble(lines[3]);
}
else
{
xzoom = (xende - xstart) / (double)x1;
yzoom = (yende - ystart) / (double)y1;
}
mandelbrot();
}
public void stop()
{
}
/*public void paint(Graphics g, PaintEventArgs e)
{
update(g);
}
public void update(Graphics g)
{
//g.DrawImage(picture, 0, 0);
}*/
private void mandelbrot()
{
int x, y;
float h, b, alt = 0.0f;
Color color;
Pen pen = new Pen(Color.Black);
for (x = 0; x < x1; x += 2)
for (y = 0; y < y1; y++)
{
h = pointcolour(xstart + xzoom * (double)x, ystart + yzoom * (double)y, c);
if (h != alt)
{
b = 1.0f - h * h;
color = HSBColor.FromHSB(new HSBColor(h * 255, 0.8f * 255, b * 255));
pen = new Pen(color);
alt = h;
}
g1.DrawLine(pen, x, y, x + 1, y);
}
}
private float pointcolour(double xwert, double ywert, int j)
{
double r = 0.0, i = 0.0, m = 0.0;
// int j = 0;
while ((j < MAX) && (m < 4.0))
{
j++;
m = r * r - i * i;
i = 2.0 * r * i + ywert;
r = m + xwert;
}
return (float)j / (float)MAX;
}
private void initvalues()
{
xstart = SX;
ystart = SY;
xende = EX;
yende = EY;
if ((float)((xende - xstart) / (yende - ystart)) != xy)
xstart = xende - (yende - ystart) * (double)xy;
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g1 = e.Graphics;
g1.DrawImage(bitmap, 0, 0, x1, y1);
using (Pen pen = new Pen(Color.White, 2))
{
e.Graphics.DrawRectangle(pen, rec);
}
Invalidate();
}
//added load method
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
xe = e.X;
ye = e.Y;
if (xs < xe)
{
if (ys < ye) rec = new Rectangle(xs, ys, (xe - xs), (ye - ys));
else rec = new Rectangle(xs, ye, (xe - xs), (ys - ye));
}
else
{
if (ys < ye) rec = new Rectangle(xe, ys, (xs - xe), (ye - ys));
else rec = new Rectangle(xe, ye, (xs - xe), (ys - ye));
}
this.Invalidate();
}
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// e.consume();
xs = e.X;
ys = e.Y; // starting point y
this.Invalidate();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
rec = new Rectangle(0, 0, 0, 0);
if (e.Button == MouseButtons.Left)
{
int z, w;
//e.consume();
//xe = e.X;
//ye = e.Y;
if (xs > xe)
{
z = xs;
xs = xe;
xe = z;
}
if (ys > ye)
{
z = ys;
ys = ye;
ye = z;
}
w = (xe - xs);
z = (ye - ys);
if ((w < 2) && (z < 2)) initvalues();
else
{
if (((float)w > (float)z * xy)) ye = (int)((float)ys + (float)w / xy);
else xe = (int)((float)xs + (float)z * xy);
xende = xstart + xzoom * (double)xe;
yende = ystart + yzoom * (double)ye;
xstart += xzoom * (double)xs;
ystart += yzoom * (double)ys;
}
xzoom = (xende - xstart) / (double)x1;
yzoom = (yende - ystart) / (double)y1;
mandelbrot();
string stringxzoom = xzoom.ToString();
string stringyzoom = yzoom.ToString();
string stringystart = ystart.ToString();
string stringxstart = xstart.ToString();
string[] lines = { stringxzoom, stringyzoom, stringxstart, stringystart };
System.IO.File.WriteAllLines(#"C:\Users\Public\Writelines.txt", lines);
this.Invalidate();
//Repaint();
}
}
private void restartToolStripMenuItem_Click(object sender, EventArgs e)
{
Application.Restart();
}
private void exitToolStripMenuItem1_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void menuToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
}
}
}
Change your Form1() code into these
InitializeComponent();
init();
start();
this.DoubleBuffered = true;
this.pictureBox1.Image = bitmap;
You took out the InitializeComponent call (which should be automatically generated) and you never set the resulting bitmap as the image of the pictureBox. Also, you might wanna set the picturebox Size mode to Zoom and enlarge it.

WindowsFormsApplication1.Form1.Dispose(bool)':no suitable method found to override

For an assignment I've had to convert a fractal rendering program from Java to C# and I think I've done it but when i try to run it I get the error that is present in the title and I have no idea why it is happening. This is the code for the renderer itself which presents me with no errors:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Form1
{
public partial class Form1 : Form
{
public Form1()
{
init();
start();
this.DoubleBuffered = true;
}
//code to convert HSB to RGB from HSB.cs. All your code so i made it take up less space.
public struct HSBColor
{
float h;
float s;
float b;
int a;
public HSBColor(float h, float s, float b) { this.a = 0xff; this.h = Math.Min(Math.Max(h, 0), 255); this.s = Math.Min(Math.Max(s, 0), 255); this.b = Math.Min(Math.Max(b, 0), 255); }
public HSBColor(int a, float h, float s, float b) { this.a = a; this.h = Math.Min(Math.Max(h, 0), 255); this.s = Math.Min(Math.Max(s, 0), 255); this.b = Math.Min(Math.Max(b, 0), 255); }
public float H { get { return h; } }
public float S { get { return s; } }
public float B { get { return b; } }
public int A { get { return a; } }
public Color Color { get { return FromHSB(this); } }
public static Color FromHSB(HSBColor hsbColor)
{
float r = hsbColor.b;
float g = hsbColor.b;
float b = hsbColor.b;
if (hsbColor.s != 0)
{
float max = hsbColor.b; float dif = hsbColor.b * hsbColor.s / 255f; float min = hsbColor.b - dif; float h = hsbColor.h * 360f / 255f;
if (h < 60f) { r = max; g = h * dif / 60f + min; b = min; }
else if (h < 120f) { r = -(h - 120f) * dif / 60f + min; g = max; b = min; }
else if (h < 180f) { r = min; g = max; b = (h - 120f) * dif / 60f + min; }
else if (h < 240f) { r = min; g = -(h - 240f) * dif / 60f + min; b = max; }
else if (h < 300f) { r = (h - 240f) * dif / 60f + min; g = min; b = max; }
else if (h <= 360f) { r = max; g = min; b = -(h - 360f) * dif / 60 + min; }
else { r = 0; g = 0; b = 0; }
}
return Color.FromArgb(hsbColor.a, (int)Math.Round(Math.Min(Math.Max(r, 0), 255)), (int)Math.Round(Math.Min(Math.Max(g, 0), 255)), (int)Math.Round(Math.Min(Math.Max(b, 0), 255)));
}
}
private const int MAX = 256; // max iterations
private const double SX = -2.025; // start value real
private const double SY = -1.125; // start value imaginary
private const double EX = 0.6; // end value real
private const double EY = 1.125; // end value imaginary
private static int x1, y1, xs, ys, xe, ye;
private static double xstart, ystart, xende, yende, xzoom, yzoom;
private static float xy;
private int c = 0;
//private Image picture; Taken out, not needed
// create rectangle variable JGB
Rectangle rec;
private Graphics g1;
//private Cursor c1, c2; Taken out, not needed
private System.Drawing.Bitmap bitmap;
public void init()
{
//setSize(640, 480); changed this code to JGB:
this.Size = new Size(640, 480);
// Taken all lines out below. Not needed.
/*finished = false;
addMouseListener(this);
addMouseMotionListener(this);
c1 = new Cursor(Cursor.WAIT_CURSOR);
c2 = new Cursor(Cursor.CROSSHAIR_CURSOR); */
x1 = 640;
y1 = 480;
xy = (float)x1 / (float)y1;
//picture = createImage(x1, y1); Taken out and replaced with JGB:
bitmap = new Bitmap(x1, y1);
//g1 = picture.getGraphics(); changed to get my bitmap
g1 = Graphics.FromImage(bitmap);
//finished = true; Finished variable deleted so not needed
}
//Code below didnt appear to do anything so i deleted it
/*public void destroy() // delete all instances
{
if (finished)
{
removeMouseListener(this);
removeMouseMotionListener(this);
picture = null;
g1 = null;
c1 = null;
c2 = null;
System.gc(); // garbage collection
}
} */
public void start()
{
//action = false;
//rectangle = false;
initvalues();
// added dialog box for instance loading and save varaibles needed for position and zoom to text file
DialogResult dialog = MessageBox.Show("Would You Like to Load Your Last Instance?", "Load Instance?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if (dialog == DialogResult.Yes)
{
string[] lines = System.IO.File.ReadAllLines(#"C:\Users\Public\Writelines.txt");
xzoom = System.Convert.ToDouble(lines[0]);
yzoom = System.Convert.ToDouble(lines[1]);
xstart = System.Convert.ToDouble(lines[2]);
ystart = System.Convert.ToDouble(lines[3]);
}
else
{
xzoom = (xende - xstart) / (double)x1;
yzoom = (yende - ystart) / (double)y1;
}
mandelbrot();
}
public void stop()
{
}
/*public void paint(Graphics g, PaintEventArgs e)
{
update(g);
}
public void update(Graphics g)
{
//g.DrawImage(picture, 0, 0);
}*/
private void mandelbrot()
{
int x, y;
float h, b, alt = 0.0f;
Color color;
Pen pen = new Pen(Color.Black);
for (x = 0; x < x1; x += 2)
for (y = 0; y < y1; y++)
{
h = pointcolour(xstart + xzoom * (double)x, ystart + yzoom * (double)y, c);
if (h != alt)
{
b = 1.0f - h * h;
color = HSBColor.FromHSB(new HSBColor(h * 255, 0.8f * 255, b * 255));
pen = new Pen(color);
alt = h;
}
g1.DrawLine(pen, x, y, x + 1, y);
}
}
private float pointcolour(double xwert, double ywert, int j)
{
double r = 0.0, i = 0.0, m = 0.0;
// int j = 0;
while ((j < MAX) && (m < 4.0))
{
j++;
m = r * r - i * i;
i = 2.0 * r * i + ywert;
r = m + xwert;
}
return (float)j / (float)MAX;
}
private void initvalues()
{
xstart = SX;
ystart = SY;
xende = EX;
yende = EY;
if ((float)((xende - xstart) / (yende - ystart)) != xy)
xstart = xende - (yende - ystart) * (double)xy;
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g1 = e.Graphics;
g1.DrawImage(bitmap, 0, 0, x1, y1);
using (Pen pen = new Pen(Color.White, 2))
{
e.Graphics.DrawRectangle(pen, rec);
}
Invalidate();
}
//added load method
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
xe = e.X;
ye = e.Y;
if (xs < xe)
{
if (ys < ye) rec = new Rectangle(xs, ys, (xe - xs), (ye - ys));
else rec = new Rectangle(xs, ye, (xe - xs), (ys - ye));
}
else
{
if (ys < ye) rec = new Rectangle(xe, ys, (xs - xe), (ye - ys));
else rec = new Rectangle(xe, ye, (xs - xe), (ys - ye));
}
this.Invalidate();
}
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// e.consume();
xs = e.X;
ys = e.Y; // starting point y
this.Invalidate();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
rec = new Rectangle(0, 0, 0, 0);
if (e.Button == MouseButtons.Left)
{
int z, w;
//e.consume();
//xe = e.X;
//ye = e.Y;
if (xs > xe)
{
z = xs;
xs = xe;
xe = z;
}
if (ys > ye)
{
z = ys;
ys = ye;
ye = z;
}
w = (xe - xs);
z = (ye - ys);
if ((w < 2) && (z < 2)) initvalues();
else
{
if (((float)w > (float)z * xy)) ye = (int)((float)ys + (float)w / xy);
else xe = (int)((float)xs + (float)z * xy);
xende = xstart + xzoom * (double)xe;
yende = ystart + yzoom * (double)ye;
xstart += xzoom * (double)xs;
ystart += yzoom * (double)ys;
}
xzoom = (xende - xstart) / (double)x1;
yzoom = (yende - ystart) / (double)y1;
mandelbrot();
string stringxzoom = xzoom.ToString();
string stringyzoom = yzoom.ToString();
string stringystart = ystart.ToString();
string stringxstart = xstart.ToString();
string[] lines = { stringxzoom, stringyzoom, stringxstart, stringystart };
System.IO.File.WriteAllLines(#"C:\Users\Public\Writelines.txt", lines);
this.Invalidate();
//Repaint();
}
}
private void restartToolStripMenuItem_Click(object sender, EventArgs e)
{
Application.Restart();
}
private void exitToolStripMenuItem1_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void menuToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
}
}
}
and this is the code that is used for the form designer which was auto generated and I'm not sure why an error is being presented because I've never had one before:
namespace WindowsFormsApplication1
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Text = "Form1";
}
#endregion
}
}
I believe it is caused because your namespaces are not the same. Since the partial code generated by the designer doesn't inherit from Form, you don't have a method to override. Once you make the two classes tie together properly by matching the namespaces, it should work.
To fix it, you can either change the namespace of the designer code to match your namespace of Form1:
namespace Form1
{
partial class Form1
{
//...
}
}
Or change your form to match the designer:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
//....
}
}
Edit the project properties and update the Default namespace to match the desired namespace for all forms

Is there a built-in C#/.NET System API for HSV to RGB?

Is there an API built into the .NET framework for converting HSV to RGB? I didn't see a method in System.Drawing.Color for this, but it seems surprising that there wouldn't be one in the platform.
There isn't a built-in method for doing this, but the calculations aren't terribly complex.
Also note that Color's GetHue(), GetSaturation() and GetBrightness() return HSL values, not HSV.
The following C# code converts between RGB and HSV using the algorithms described on Wikipedia.
I already posted this answer here, but I'll copy the code here for quick reference.
The ranges are 0 - 360 for hue, and 0 - 1 for saturation or value.
public static void ColorToHSV(Color color, out double hue, out double saturation, out double value)
{
int max = Math.Max(color.R, Math.Max(color.G, color.B));
int min = Math.Min(color.R, Math.Min(color.G, color.B));
hue = color.GetHue();
saturation = (max == 0) ? 0 : 1d - (1d * min / max);
value = max / 255d;
}
public static Color ColorFromHSV(double hue, double saturation, double value)
{
int hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6;
double f = hue / 60 - Math.Floor(hue / 60);
value = value * 255;
int v = Convert.ToInt32(value);
int p = Convert.ToInt32(value * (1 - saturation));
int q = Convert.ToInt32(value * (1 - f * saturation));
int t = Convert.ToInt32(value * (1 - (1 - f) * saturation));
if (hi == 0)
return Color.FromArgb(255, v, t, p);
else if (hi == 1)
return Color.FromArgb(255, q, v, p);
else if (hi == 2)
return Color.FromArgb(255, p, v, t);
else if (hi == 3)
return Color.FromArgb(255, p, q, v);
else if (hi == 4)
return Color.FromArgb(255, t, p, v);
else
return Color.FromArgb(255, v, p, q);
}
I don't think there's a method doing this in the .NET framework.
Check out Converting HSV to RGB colour using C#
This is the implementation code,
void HsvToRgb(double h, double S, double V, out int r, out int g, out int b)
{
double H = h;
while (H < 0) { H += 360; };
while (H >= 360) { H -= 360; };
double R, G, B;
if (V <= 0)
{ R = G = B = 0; }
else if (S <= 0)
{
R = G = B = V;
}
else
{
double hf = H / 60.0;
int i = (int)Math.Floor(hf);
double f = hf - i;
double pv = V * (1 - S);
double qv = V * (1 - S * f);
double tv = V * (1 - S * (1 - f));
switch (i)
{
// Red is the dominant color
case 0:
R = V;
G = tv;
B = pv;
break;
// Green is the dominant color
case 1:
R = qv;
G = V;
B = pv;
break;
case 2:
R = pv;
G = V;
B = tv;
break;
// Blue is the dominant color
case 3:
R = pv;
G = qv;
B = V;
break;
case 4:
R = tv;
G = pv;
B = V;
break;
// Red is the dominant color
case 5:
R = V;
G = pv;
B = qv;
break;
// Just in case we overshoot on our math by a little, we put these here. Since its a switch it won't slow us down at all to put these here.
case 6:
R = V;
G = tv;
B = pv;
break;
case -1:
R = V;
G = pv;
B = qv;
break;
// The color is not defined, we should throw an error.
default:
//LFATAL("i Value error in Pixel conversion, Value is %d", i);
R = G = B = V; // Just pretend its black/white
break;
}
}
r = Clamp((int)(R * 255.0));
g = Clamp((int)(G * 255.0));
b = Clamp((int)(B * 255.0));
}
/// <summary>
/// Clamp a value to 0-255
/// </summary>
int Clamp(int i)
{
if (i < 0) return 0;
if (i > 255) return 255;
return i;
}
It's not built in, but there's there's an open-source C# library called ColorMine which makes converting between color spaces pretty easy.
Rgb to Hsv:
var rgb = new Rgb {R = 123, G = 11, B = 7};
var hsv = rgb.To<Hsv>();
Hsv to Rgb:
var hsv = new Hsv { H = 360, S = .5, L = .17 }
var rgb = hsv.to<Rgb>();
For this you can use ColorHelper library:
RGB rgb = ColorConverter.HsvToRgb(new HSV(100, 100, 100));
There is no built-in method (I couldn't find it), but here is code that might help you out. (above solutions didn't work for me)
/// <summary>
/// Converts HSV color values to RGB
/// </summary>
/// <param name="h">0 - 360</param>
/// <param name="s">0 - 100</param>
/// <param name="v">0 - 100</param>
/// <param name="r">0 - 255</param>
/// <param name="g">0 - 255</param>
/// <param name="b">0 - 255</param>
private void HSVToRGB(int h, int s, int v, out int r, out int g, out int b)
{
var rgb = new int[3];
var baseColor = (h + 60) % 360 / 120;
var shift = (h + 60) % 360 - (120 * baseColor + 60 );
var secondaryColor = (baseColor + (shift >= 0 ? 1 : -1) + 3) % 3;
//Setting Hue
rgb[baseColor] = 255;
rgb[secondaryColor] = (int) ((Mathf.Abs(shift) / 60.0f) * 255.0f);
//Setting Saturation
for (var i = 0; i < 3; i++)
rgb[i] += (int) ((255 - rgb[i]) * ((100 - s) / 100.0f));
//Setting Value
for (var i = 0; i < 3; i++)
rgb[i] -= (int) (rgb[i] * (100-v) / 100.0f);
r = rgb[0];
g = rgb[1];
b = rgb[2];
}
I've searched the internet for better way to do this, but I can't find it.
This is a C# method to convert HSV to RGB, the method arguments are in range of 0-1, the output is in range of 0-255
private Color hsv2rgb (float h, float s, float v)
{
Func<float, int> f = delegate (float n)
{
float k = (n + h * 6) % 6;
return (int)((v - (v * s * (Math.Max(0, Math.Min(Math.Min(k, 4 - k), 1))))) * 255);
};
return Color.FromArgb(f(5), f(3), f(1));
}

Categories

Resources