On my current project, there are several instances where a row of indicators (using 26x26 PNG icons) is required. In this case, it's a DataGridView (more specifically, a Telerik RadGridView). The images are loaded from the resource file and are present.
My current code defines these indicators as a row is created:
Bitmap indicators;
List<Bitmap> content = new List<Bitmap>();
if (l.Condition1 == true)
content.Add(myProj.Properties.Resources.One);
if (l.Condition2 == true)
content.Add(myProj.Properties.Resources.Two);
if (l.Condition3 == true)
content.Add(myProj.Properties.Resources.Three);
if (content.Count() != 0)
{
int width = content.Select(w => w.Width).Sum();
indicators = new Bitmap(width, 26);
using (Graphics g = Graphics.FromImage(indicators))
{
int origin = 0;
foreach (Bitmap p in content)
{
g.DrawImage(p, new Point(origin, 0));
origin += p.Width;
}
row.Cells[15].Value = indicators;
}
}
Unfortunately, this code doesn't work (the images don't display at all) and I can't quite sort out what I've missed. Assigning an image to the Value property works if I just load one image and don't use the loop. What have I overlooked that is preventing this from working and these indicators displaying?
Related
My code in C# displays picture boxes vertically where the second picture box is below the first one instead of displaying the second picture box horizontally next to the first such that when the width of the visible form overflows. the code creates a new row and continues to create picture boxes. The code reads image file paths from a folder and initializes an array of picture boxes based on the count of the images. The goal is to create a grid of picture boxes for displaying the images. How can I update the logic of the app to make it achieve the desired output.
public class ImageGrid:Form {
//declare the folder name that contains the complex images
private string _folder = "./Complex"; //declare the array of picture boxes to display in the form
private PictureBox[] _image_grid;
private List<string> _paths= new List<string>();
public ImageGrid() {
//set a title for the form
Text = "Confidence Level Checker";
//make the screen full
FormBorderStyle =
FormBorderStyle.None;
WindowState =
FormWindowState.Maximized;
//read all the image names in the folder
if (Directory.Exists(_folder)) {
//list all the files in the folder
string[] files =
Directory.GetFiles(_folder);
if (files != null && files.Length > 0) {
//add the paths to the list
foreach (var path in files) {
_paths.Add(path);
}
//create an array of picture boxes based on the file count
_image_grid = new PictureBox[files.Length];
//declare the size of each picture box
int width = 300; int height = 250;
int x = 20; int y = 20;
foreach (string path in _paths) {
PictureBox box = new PictureBox()
{
Size = new Size(width, height),
Location = new Point(x,y),
Image = Image.FromFile(path),
SizeMode = PictureBoxSizeMode.StretchImage
};
//add the picture box to the form
this.Controls.Add(box);
//update the location to draw the picture box
x += 320;
if (x + 300 > ClientSize.Width) { x = 20; y += 270; }
}
}
}
}
You can use a FlowLayoutPanel() instead to make this simpler.
Then ensure (in the form designer) that the property FlowDirection is set to LeftToRight.
You can also do this in code:
myFlowLayoutPanel.FlowDirection = FlowDirection.LeftToRight;
You add controls to a FlowLayoutPanel the same way you do to a standard Panel:
myFlowLayoutPanel.Add(someControl);
I am trying to make the points in a C# Chart show up as letters (e.g. 'A' and 'B') to separate sets of points, instead of coloring them with green/red.
The Label property of the point collection does not satisfy this request, since it only places labels beside the point, and I want the label to replace the point.
Here is what I have:
while (reader.Read())
{
if (reader[2].ToString() == "Kupi 002")
chart3.Series["Good_Group"].Points[pointsCounter].Label = "A";
else
chart3.Series["Good_Group"].Points[pointsCounter].Label = "B";
pointsCounter = pointsCounter + 1;
}
What property, instead of Label, should I use to achieve my goal?
Thanks in advance.
One option would be to use the MarkerImage property of either the series or point to apply custom bitmap labels of each letter:
chart.Series[0].MarkerImage = "a.png";
chart.Series[0].Points[2].MarkerImage = "b.png";
chart.Series[0].Points[4].MarkerImage = "b.png";
The bitmap images could be created in a paint program and distributed with your program. They could also be generated dynamically, as in the following (highly simplified) example:
private void CreateLetterBitmap(char letter, string path)
{
using (var bmp = new Bitmap(13, 13))
using (var gfx = Graphics.FromImage(bmp))
using (var font = new Font(FontFamily.GenericSansSerif, 12.0f, FontStyle.Bold, GraphicsUnit.Pixel))
{
gfx.TextRenderingHint = TextRenderingHint.AntiAlias;
gfx.DrawString(letter.ToString(), font, Brushes.Black, new Point(0, 0));
bmp.Save(path, ImageFormat.Png);
}
}
private void PrepareChart()
{
CreateLetterBitmap('A', "a.png");
CreateLetterBitmap('B', "b.png");
chart.Series[0].MarkerImage = "a.png";
chart.Series[0].Points[2].MarkerImage = "b.png";
chart.Series[0].Points[4].MarkerImage = "b.png";
}
Im adding multiple MapIcons to my UWP app MapControl. I want to change the MapIcon size based map zoom level.
This works almost ok, but when I update marker sizes (call UpdatMarkerSizes()) not all MapIcons get new image.
I have around 200 MapIcons in my map, which I try to update. Is this some performance issue or how I should try to update all MapIcons?
Here is how I initially add MapIcons:
public void AddMapIcons(IReadOnlyCollection<IItem> items)
{
var icon = (CurrentMarkerIconSize == MarkerIconSize.Small) ? _markerSmall : _markerNormal;
foreach (var item in items)
{
var stopIcon = new MapIcon
{
Location = new Geopoint(item.Location),
NormalizedAnchorPoint = new Point(0.5, 0.5),
ZIndex = 5,
CollisionBehaviorDesired = MapElementCollisionBehavior.RemainVisible,
Image = icon
};
MapControl.MapElements.Add(stopIcon);
}
}
And here is my MapIcon Image update functionality, this is called when map zoomlevel is changed.
private void UpdatMarkerSizes(MarkerIconSize newSize)
{
var newImage = (newSize == StopIconSize.Small) ? _markerSmall : _markerNormal;
foreach (var element in MapControl.MapElements)
{
(element as MapIcon).Image = newImage;
}
}
UPDATE 1:
I just noticed that if I also update MapIcon NormalizedAnchorPoint, ZIndex and CollisionBehaviorDesired (set same value again), this issue is not so bad. Previously when I updated my markers (UpdatMarkerSizes()) there was always couple of markers which did not get the new image. Now after this update, I get rarely one or two markers which did not get new image.
Updated code:
private void UpdatMarkerSizes(MarkerIconSize newSize)
{
var newImage = (newSize == StopIconSize.Small) ? _markerSmall : _markerNormal;
foreach (var element in MapControl.MapElements)
{
var mapIconElement = element as MapIcon;
if(mapIconElement != null)
{
mapIconElement.Image = newImage;
mapIconElement.NormalizedAnchorPoint = new Point(0.5, 0.5);
mapIconElement.ZIndex = 5;
mapIconElement.CollisionBehaviorDesired = MapElementCollisionBehavior.RemainVisible;
}
}
}
UPDATE 2:
I think that my solution in update 1 is good enough for now. I have posted new question which is related to MapIcons and their image updating too: Dynamically update collection of MapIcons, update process gets out of sync?
I want to show a lot of images in a form using User Control, but it's very slow and takes a lot of system memory.
How can I load image in Picture Box when User Control shows to user?
I wrote this sample code. It works fine for 700 images, but I am still looking for best solution.
Bitmap myBitmap;
Image myThumbnail;
foreach (var item in queryMatchingFiles)
{
Image.GetThumbnailImageAbort myCallback = new Image.GetThumbnailImageAbort(ThumbnailCallback);
myBitmap = new Bitmap(item);
myThumbnail = myBitmap.GetThumbnailImage(120, 183, myCallback, IntPtr.Zero);
flowLayoutPanel1.Controls.Add(new PictureBox {
Image = myThumbnail,
Width = 120,
Height = 183,
BackgroundImageLayout = ImageLayout.Stretch
});
count++;
myBitmap = null;
myThumbnail = null;
}
public bool ThumbnailCallback()
{
return false;
}
Here is my Code, I am trying to stitch two pictures together and as soon as I get to line 42 "Image img = Image.FromFile(file.FullName);" I get an out of memory error. What should I do?
namespace Practicing_Stiching
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void cmdCombine_Click(object sender, EventArgs e)
{
//Change the path to location where your images are stored.
DirectoryInfo directory = new DirectoryInfo(#"C:\Users\Elder Zollinger\Desktop\Images");
if (directory != null)
{
FileInfo[] files = directory.GetFiles();
CombineImages(files);
}
}
private void CombineImages(FileInfo[] files)
{
//change the location to store the final image.
string finalImage = #"C:\Users\Elder Zollinger\Desktop\Images";
List<int> imageHeights = new List<int>();
int nIndex = 0;
int width = 0;
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
imageHeights.Add(img.Height);
width += img.Width;
img.Dispose();
}
imageHeights.Sort();
int height = imageHeights[imageHeights.Count - 1];
Bitmap img3 = new Bitmap(width, height);
Graphics g = Graphics.FromImage(img3);
g.Clear(SystemColors.AppWorkspace);
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
if (nIndex == 0)
{
g.DrawImage(img, new Point(0, 0));
nIndex++;
width = img.Width;
}
else
{
g.DrawImage(img, new Point(width, 0));
width += img.Width;
}
img.Dispose();
}
g.Dispose();
img3.Save(finalImage, System.Drawing.Imaging.ImageFormat.Jpeg);
img3.Dispose();
imageLocation.Image = Image.FromFile(finalImage);
}
}
}
That's likely GDI playing tricks on you.
You see, when GDI encounters an unknown file, it will quite likely cause an OutOfMemoryException. Since you're not filtering the input images at all, I'd expect that you're simply grabbing a non-image file (or an image type that GDI doesn't understand).
Oh, and a bit sideways - make sure you set JPEG quality when saving JPEGs - the default is something like 75, which is rather bad for a lot of images. And please, do use using - it's very handy to ensure proper and timely clean-up :)
Get more memory!
But seriously, you don't appear to be filtering out files that are not image files. There are some hidden files in folders that you may be trying to open as an image accidentally, such as "Thumbs.db". Make sure that the file is an image with something like if (Path.GetExtension(file.FullPath) != ".png") continue;.
Also, on objects that you are calling .Dispose() on, consider wrapping them in a using() instead. For example:
using(var img = Image.FromFile(file.FullPath))
{
// ...
}