Need help with altering the Bitmaps in an ImageList to switch the black pixels to yellow, they are being used as images for a UICommandBar (screenshot and attempt below)
The code gets executed, with GetPixel condition and then SetPixel, but the images are not changed. Maybe related to ImageListStreamer or not the right time to swap those pixels.
rtfeditor.cs
this.imageList1.ImageStream = ( (System.Windows.Forms.ImageListStreamer)(resources.GetObject( "imageList1.ImageStream" ) ) );
this.imageList1 = ColorSpace.ProcessHighContrast(this.imageList1);
Utils\ColorSpace.cs
public static System.Windows.Forms.ImageList ProcessHighContrast(System.Windows.Forms.ImageList imageList)
{
if (System.Windows.Forms.SystemInformation.HighContrast)
{
foreach (System.Drawing.Bitmap imageListImage in imageList.Images)
{
for (int i = 0; i < imageListImage.Width; i++)
{
for (int j = 0; j < imageListImage.Height; j++)
{
Color color = imageListImage.GetPixel(i, j);
if (System.Drawing.Color.FromArgb(255, 0, 0, 0).Equals(color))
imageListImage.SetPixel(i, j, System.Drawing.SystemColors.WindowText);
}
}
}
}
return imageList;
}
Solved
Hans Passant's comment was critical for resolving this (see quoted comment below) + changing the order of the call of ProcessHighContrast (now first) with the assignment of the ImageList to the Janus.Windows.UI.CommandBars.UICommandBar (now second). New method and calling code below.
ImageList.Images returns a copy of each image. Altering the copy therefore does not modify the ImageList content at all. Create a new ImageList instead. Do consider that Darth Vader color schemes tend to be appreciated only by programmers, regular users expect the high contrast version to have a white background. That's going to be a lot less painful. – Hans Passant
rtfeditor.cs
this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream")));
this.imageList1 = ColorSpace.ProcessHighContrast(this.imageList1);
this.uiCommandManager1.ImageList = this.imageList1;
Utils\ColorSpace.cs
public static System.Windows.Forms.ImageList ProcessHighContrast(System.Windows.Forms.ImageList imageList)
{
if (System.Windows.Forms.SystemInformation.HighContrast)
{
System.Windows.Forms.ImageList imageListNew = new ImageList();
foreach (System.Drawing.Bitmap imageListImage in imageList.Images)
{
for (int i = 0; i < imageListImage.Width; i++)
{
for (int j = 0; j < imageListImage.Height; j++)
{
Color color = imageListImage.GetPixel(i, j);
if (System.Drawing.Color.FromArgb(255, 0, 0, 0).Equals(color))
imageListImage.SetPixel(i, j, System.Drawing.SystemColors.WindowText);
}
}
imageListNew.Images.Add(imageListImage);
}
return imageListNew;
}
return imageList;
}
Related
The function GetBitMapColorMatrix is supposed to decode the tiff image and return a bitmap that describes the tiff image but for some reason, I get this exception -> System.PlatformNotSupportedException: 'System.Drawing is not supported on this platform'. Any help would be appreciated.
public Color[][] GetBitMapColorMatrix(string bitmapFilePath)
{
Bitmap b1 = new Bitmap(bitmapFilePath);
int hight = b1.Height;
int width = b1.Width;
Color[][] colorMatrix = new Color[width][];
for (int i = 0; i < width; i++)
{
colorMatrix[i] = new Color[hight];
for (int j = 0; j < hight; j++)
{
colorMatrix[i][j] = b1.GetPixel(i, j);
}
}
return colorMatrix;
}
UWP does not use the full .net framework so the classes in System.Drawing are not available. Their are some classes like BitmapPallette and BitmapImage in the System.Media.Imaging namespace that could be useful. I would also look at Win2D or SharpDX.
I'm working on a program in windows forms that generate random coordinate points to draw fish. I need the fish to stop intersecting with each other but the code I wrote doesn't work. The coordinates generated should be put into rectangles and then checked against all the other points rectangles. The fish keep intersecting. Any idea why?
Code I wrote to stop the intersection.
for (int i = 0; i < fishNumber; i++)
{
// Checks for overlapping
fishX = x.Next(200, 3100);
fishY = y.Next(100, 1620);
fishPoints.Add(new Point(fishX, fishY));
for (int j = 0; j < i; j++)
{
while (i != 0 && new Rectangle(fishPoints[i], new Size(200, 134)).IntersectsWith(new Rectangle(fishPoints[j], new Size(200, 134))))
{
fishPoints.RemoveAt(i);
fishX = x.Next(200, 3100);
fishY = y.Next(100, 1620);
fishPoints.Add(new Point(fishX, fishY));
}
}
}
Try something more like the below out. It only adds the point AFTER it has been determined that it doesn't intersect with any of the other fish:
Size fishSize = new Size(200, 134);
for (int i = 0; i < fishNumber;i++)
{
Point pt;
bool collided;
do
{
collided = false;
pt = new Point(x.Next(200, 3100), y.Next(100, 1620));
Rectangle rcNewFish = new Rectangle(pt, fishSize);
foreach(Point otherPt in fishPoints)
{
if (rcNewFish.IntersectsWith(new Rectangle(otherPt, fishSize)))
{
collided = true;
break;
}
}
} while (collided);
fishPoints.Add(pt);
}
I've loaded an indexed colour image (8bppI) with a unique palette into a C# program and I need to access the index of colours in that image. However, the only access function seems to be Bitmap.GetPixel(x,y) which returns a colour, not an index. When that same colour is inserted back into a Bitmap of the same format and palette, the colour information is apparently misinterpreted as an index and everything goes to heck. Here's a simplified version of the code for clarity of the issue:
public void CreateTerrainMap() {
visualization = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
visualizationLock = new LockBitmap(visualization);
Lock();
// "TerrainIndex.bmp" is a 256x256 indexed colour image (8bpp) with a unique palette.
// Debugging confirms that this image loads with its palette and format intact
Bitmap terrainColours = new Bitmap("Resources\\TerrainIndex.bmp");
visualization.Palette = terrainColours.Palette;
Color c;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
if (Terrain[x, y] < SeaLevel) {
c = Color.FromArgb(15); // Counterintuitively, this actually gives index 15 (represented as (0,0,0,15))
} else {
heatIndex = <some number between 0 and 255>;
rainIndex = <some number between 0 and 255>;
if (IsCoastal(x, y)) {
c = Color.FromArgb(35); // Counterintuitively, this actually gives index 35 (represented as (0,0,0,35))
} else {
// This returns an argb colour rather than an index...
c = terrainColours.GetPixel(rainIndex, heatIndex);
}
}
// ...and this seemingly decides that the blue value is actually an index and sets the wrong colour entirely
visualizationLock.SetPixel(x, y, c);
}
}
}
TerrainIndex looks like this:
TerrainIndex.bmp
The palette looks like this: Palette
The output should look like this: Good
But it looks like this instead: Bad
Note that the oceans (index 15) and coasts (index 35) look correct, but everything else is coming from the wrong part of the palette.
I can't find any useful information on working with indexed colour bitmaps in C#. I really hope someone can explain to me what I might be doing wrong, or point me in the right direction.
I created an answer from my comment. So the "native" solution is something like this (requires allowing unsafe code):
Bitmap visualization = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
visualization.Palette = GetVisualizationPalette();
BitmapData visualizationData = visualization.LockBits(new Rectangle(Point.Empty, visualization.Size),
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
try
{
unsafe
{
byte* row = (byte*)visualizationData.Scan0;
for (int y = 0; y < visualizationData.Height; y++)
{
for (int x = 0; x < visualizationData.Width; x++)
{
// here you set the 8bpp palette index directly
row[x] = GetHeatIndex(x, y);
}
row += visualizationData.Stride;
}
}
}
finally
{
visualization.UnlockBits(visualizationData);
}
Or, you can use these libraries, and then:
using KGySoft.Drawing;
using KGySoft.Drawing.Imaging;
// ...
Bitmap visualization = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
visualization.Palette = GetVisualizationPalette();
using (IWritableBitmapData visualizationData = visualization.GetWritableBitmapData())
{
for (int y = 0; y < visualizationData.Height; y++)
{
IWritableBitmapDataRow row = visualizationData[y];
for (int x = 0; x < visualizationData.Width; x++)
{
// setting pixel by palette index
row.SetColorIndex(x, GetHeatIndex(x, y));
// or: directly by raw data (8bpp means 1 byte per pixel)
row.WriteRaw<byte>(x, GetHeatIndex(x, y));
// or: by color (automatically applies the closest palette index)
row.SetColor(x, GetHeatColor(x, y));
}
}
}
Edit:
And for reading pixels/indices you can use terrainColors.GetReadableBitmapData() so you will able to use rowTerrain.GetColorIndex(x) or rowTerrain.ReadRaw<byte>(x) in a very similar way.
I have written some c# code that needs to process upwards of about 3000 images, but by the 500th image the task manager is showing the program using 1.5gb of memory. The function below seems to be one of the major culprits. What could I be doing better here? Any help or suggestions are appreciated. Thanks.
private void FixImage(ref Bitmap field)
{
//rotate 45 degrees
RotateBilinear rot = new RotateBilinear(45);
field = rot.Apply(field); //Memory spikes 2mb here
//crop out unwanted image space
Crop crop = new Crop(new Rectangle(cropStartX, cropStartY, finalWidth, finalHeight));
field = crop.Apply(field); //Memory spikes 2mb here
//correct background
for (int i = 0; i < field.Width; i++)
{
for (int j = 0; j < field.Height; j++)
{
if (field.GetPixel(i, j).ToArgb() == Color.Black.ToArgb())
field.SetPixel(i, j, Color.White);
}
} //Memory usuage increases 0.5mb by the end
}
i could reduce memory when changing your code like this
private void FixImage(ref Bitmap field)
{
//rotate 45 degrees
RotateBilinear rot = new RotateBilinear(45);
var rotField = rot.Apply(field); //Memory spikes 2mb here
field.Dispose();
//crop out unwanted image space
Crop crop = new Crop(new Rectangle(cropStartX, cropStartY, finalWidth, finalHeight));
var cropField = crop.Apply(rotField); //Memory spikes 2mb here
rotField.Dispose();
//correct background
for (int i = 0; i < cropField.Width; i++)
{
for (int j = 0; j < cropField.Height; j++)
{
if (cropField.GetPixel(i, j).ToArgb() == Color.Black.ToArgb())
cropField.SetPixel(i, j, Color.White);
}
} //Memory usuage increases 0.5mb by the end
field = cropField;
}
so it seems to be a good idea, to free up that image memory right away, and not to wait until the GC takes care of it eventually.
I'm looking at doing a project in C# that looks at an image file not sure of extension yet, and notes the RGB value and if its too dark moves it to another folder for me to look at later
So here it is in block form
Load multiple images from directory > Check RGB value of every file > if too dark > move to different folder. if not ignore (leave in original folder)
I know the basics like get files from dir but checking RGB value of whole picture and then moving it or ignoring it I'm stumped.
I have this code:
private void button1_Click(object sender, EventArgs e)
{
CompareImages(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures),
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "checked"), 127.0, new string[] {"*.jpg", "*.png"});
}
private void CompareImages(string sourceFolder, string disposedImgFolder, double threshold, string[] extensions)
{
if (Directory.Exists(sourceFolder))
{
DirectoryInfo dir = new DirectoryInfo(sourceFolder);
List<FileInfo> pictures = new List<FileInfo>();
foreach (string ext in extensions)
{
FileInfo[] fi = dir.GetFiles(ext);
pictures.AddRange(fi);
}
Directory.CreateDirectory(disposedImgFolder);
int j = 0;
if (pictures.Count > 0)
{
for (int i = 0; i < pictures.Count; i++)
{
Image img = null;
Bitmap bmp = null;
try
{
img = Image.FromFile(pictures[i].FullName);
bmp = new Bitmap(img);
img.Dispose();
double avg = GetAveragePixelValue(bmp);
bmp.Dispose();
if (avg < threshold)
{
string dest = Path.Combine(disposedImgFolder, pictures[i].Name);
if (File.Exists(dest) == false)
{
pictures[i].MoveTo(dest);
j++;
}
else
{
}
}
else
{
}
}
catch
{
if (img != null)
img.Dispose();
if (bmp != null)
bmp.Dispose();
}
}
MessageBox.Show("Done, " + j.ToString() + " files moved.");
}
}
}
private unsafe double GetAveragePixelValue(Bitmap bmp)
{
BitmapData bmData = null;
try
{
bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
int stride = bmData.Stride;
IntPtr scan0 = bmData.Scan0;
int w = bmData.Width;
int h = bmData.Height;
double sum = 0;
long pixels = bmp.Width * bmp.Height;
byte* p = (byte*)scan0.ToPointer();
for (int y = 0; y < h; y++)
{
p = (byte*)scan0.ToPointer();
p += y * stride;
for (int x = 0; x < w; x++)
{
double i = ((double)p[0] + p[1] + p[2]) / 3.0;
sum += i;
p += 4;
}
}
bmp.UnlockBits(bmData);
double result = sum / (double)pixels;
return result;
}
catch
{
try
{
bmp.UnlockBits(bmData);
}
catch
{
}
}
return -1;
}
How do I define the threashold?
If you want to read every pixel of an image, it must be converted to a bitmap. Then you can use the GetPixel method. But, this process is very slow and it takes a lot of CPU. If you do so, you really should run some test before.
using (var m = new MemoryStream())
{
using (var img = Image.FromFile(args[0]))
{
img.Save(m, ImageFormat.Bmp);
}
m.Position = 0;
using (var bitmap = (Bitmap)Bitmap.FromStream(m))
{
for (var x = 0; x < bitmap.Width; x++)
{
for (var y = 0; y < bitmap.Height; y++)
{
var color = bitmap.GetPixel(x, y);
// TODO: Do what ever you want
}
}
}
}
I think you need to read up a bit on RGB. Every pixel will have an Red, Green and Blue value associated with it and i guess you are looking for a way to get some meassure of how bright the "average" pixel is? If so you need to loop over all pixels. While doing so calculate brightness of each pixel. "Brightness" of each pixels can be calculated in several ways, you could simply do (R + G + B)/3, or you could try to mimic that the human eye isn't equaly sensitive to R, G and B.
Then you will have to decide how to use your "brightness" of pixel. Mean, Median, something else? It depends on what you want to do..
Update: After reading more of your comments I'm still not really sure what you mean by "bright" or "dark". It also seems that you have your terminology a bit confused, you keep talking about a RGB value for an entire image, but RGB values in an image refer to individual pixel values.
I believe that this page could help you doing what you want:
http://www.nbdtech.com/Blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx
Also, some complimentary reading to understand RGB:
http://en.wikipedia.org/wiki/Luma_(video)
http://en.wikipedia.org/wiki/RGB_color_space