I am trying to make a neat little bar graph with unique markers on the columns.
I used a 20x20px png image for this purpose and set it with
chart1.Series[0].Points[chart1.Series[0].Points.Count - 1].MarkerImage = imageIWanToUse;
but the marker is huge, tried to use
chart1.Series[0].Points[chart1.Series[0].Points.Count - 1].MarkerSize = 1;
but with no luck, i get this on all of the columns, where can i fix this?
image of a column
You need to make sure that the image you use has the proper dpi setting, so that it fits with your screen's dp, which probably is around 75-96 dpi.
If it looks too large than the dpi of the image is too small..
You can change it in code like this:
Bitmap bmp = (Bitmap) Bitmap.FromFile("D:\\stop32.png");
bmp.SetResolution(50, 50);
bmp.Save("D:\\stop32_50dpi.png");
bmp.SetResolution(250, 250);
bmp.Save("D:\\stop32_250dpi.png");
Series S0 = chart1.Series[0];
S0.Points[chart1.Series[0].Points.Count - 3].MarkerImage = "D:\\stop32.png";
S0.Points[chart1.Series[0].Points.Count - 2].MarkerImage = "D:\\stop32_50.png";
S0.Points[chart1.Series[0].Points.Count - 1].MarkerImage = "D:\\stop32_250.png";
Here are the resulting markers:
The original resolution was 96dpi. (Left marker.)
You will have to watch out for varying screen dpi and use either different images or create the right one dynamically. You can get the current screen dpi e.g. by testing the current Graphics object in a Paint event: Console.WriteLine(e.Graphics.DpiX + " dpi x"); For my screen this resulted in 120 dpi..
Related
I have a C# 4.7 WinForms application with line chart. I want to save chart image with very large resolution e.g 10000x2000. Here is what I have archived:
Form1.Width = 3860; //my screen width resolution - maximum allowed
Form1.Height = 1080; //my screen height resolution - maximum allowed
chart1.Dock = DockStyle.Fill;
chart1.SaveImage(saveFile.FileName, ChartImageFormat.Jpeg);
That code saves jpeg image with 3860x1080 resolution and i can zoom in points I need. But it is not enough and I want to enlarge my form or chart to
get an image like 10000x2000, VS says it cannot be larger than my screen.
I have a lot of data on this chart, so bigger form provides me with more data on a chart. Picture is required for other people to see the maximum info.
How can I do it?
This is quite simple.
All you need to do is create the Chart in code without displaying it on screen.
Now you can size it as needed..:
Chart bigChart = new Chart();
bigChart.ChartAreas.Add("ca");
Series s1 = bigChart.Series.Add("s1");
s1.BorderWidth = 5;
s1.ChartType = SeriesChartType.Line;
// testdata
Random rnd = new Random(8);
for (int i = 0; i < 111; i++)
{
s1.Points.AddXY(rnd.Next(123) + i, rnd.Next(12 * i)) ;
}
bigChart.Size = new Size(10000, 8000);
bigChart.SaveImage(filename, ChartImageFormat.Png);
A few notes:
You may want to add a Legend as well, as the dynamically created Chart has none of the default elements..
If you want to you can use a chart you have, serialize its content to a file (or stream) and then load (deserialize) it into the big chart..
The automatic smartness of MSChart tends to hit some limit when the sizes grow a lot; so brace yourself for tweaking some settings for line width, Fonts etc..
You also may want to load the saved image and set the dpi to a bigger values than the default, which is the screen resolution..
Final remark: Sometimes it is better to save the chart as a vector format; these are also provided in the SaveImage method.
Update: Maybe you want to combine vector and pixel formats as in Jimi's last comments.
You may want to study this post which discusses a few general options.
I am adding Image instances to a Canvas in Windows Runtime environment and my image keeps getting scaled up when in 140 and 180 scale resolution displays, it looks perfect in scale resolution 100. I tried creating 3 PNG images, one for each scale size: 100, 140, 180 but it still scales them up and they look blurry. I created a test image with 4 black pixels on a cyan background and I took a screenshot from the simulator, see how the image is blurry, my original image has just 4 perfect black pixels:
I tried changing the stretch mode of my Image objects, but it does nothing. I'm using this code to add the images at runtime:
var bitmapImage = new BitmapImage();
StorageFile bitmapFile = await StorageFile.GetFileFromApplicationUriAsync(imageUri);
await bitmapImage.SetSourceAsync(await bitmapFile.OpenReadAsync());
Image image = new Image{ Source = bitmapImage};
image.SetValue(Canvas.LeftProperty, x);
image.SetValue(Canvas.TopProperty, y);
canvas.Children.Add(image);
How do I get the images to draw pixel perfectly in the canvas without scaling and at the exact x/y coordinates I want?
I think I have a workaround, but it requires two steps:
First I have to load the image using a more a standard way that doesn't involve getting the file path like so.
var bitmapImage = new BitmapImage(imageUri);
Somehow this must retain more information internally that this image came from a file with the corresponding ResolutionScale for the current display. Thus when it is drawn by the canvas it is not scaled at all. However this only solves half the problem.
The next problem is that the x, y coordinates used to specify where the image is drawn are being scaled so the image is drawn in the wrong place, further than where I wanted. The only thing I can figure to do is unscale them first like so:
var resScale = DisplayInformation.GetForCurrentView().ResolutionScale;
Image image = new Image{ Source = bitmapImage};
image.SetValue(Canvas.LeftProperty, (x * 100.0) / (int)resScale);
image.SetValue(Canvas.TopProperty, (y * 100.0) / (int)resScale);
canvas.Children.Add(image);
The whole thing seems a bit crazy but it seems to work so far... Anyone have a better solution or an explanation why all this is necessary? Seems like the Canvas class needs an unscaled mode that doesn't mess with the images or coordinates across different resolution displays.
UPDATE: This doesn't work perfectly, using a double to store the value results in precision loss and sometimes there are anti-aliasing artifacts. This is not acceptable if you want pixel perfect graphics. I am still looking for a perfect solution.
There are a few more things that might help with your solution.
Use UseLayoutRounding="False" on your image.
Put your Canvas in a full-screen Viewbox, then set the Canvas Width and Height to the screen resolution. You'd use unscaled Canvas.Left/Top values in this case.
Use Direct2D/Direct3D for rendering.
Good luck.
You can change the Stretch property to "None", If you image is still meshed-up:
You should look at what DPI it is saved on. WPF tries to be DPI-independend, so it tries to draw an image of 5"x5" on every monitor the same size. Even when the resolution is higher, it still should be 5"x5" only a high resolution would render(rasterize) the image in higher quality.
Here's some info: http://www.wpflearningexperience.com/?p=41
How do I convert a WPF size to physical pixels?
Here's a piece of xaml code
you can always use scale transform from code behind to scale the images to appropriate amount be it less or more.
<Image Canvas.Left="150" Height="170" Width="170" Visibility="Visible" Stretch="None">
<Image.Source >
<BitmapImage UriSource="ms-appx:///Assets/rollingDieSprite.png"></BitmapImage>
</Image.Source>
<Image.RenderTransform>
<ScaleTransform ScaleX="4" ScaleY="4" x:Name="scaleTfDie"></ScaleTransform>
</Image.RenderTransform>
</Image>
in c# code behind you can go for the following
ScaleTransform sc = new ScaleTransform();
sc.ScaleX = 0.9;
sc.ScaleY = 0.9;
imgDieRolling.RenderTransform = sc;
this will control the scaling . try using fill=none . Let me know if it works.
I found this issue quite problematic as well. I'm creating custom bitmaps and drawing them at different positions on the canvas. I couldn't find a way in the XAML, but I found a way using Direct2D. When you set up your D2DContext, there's a function called SetUnitMode(). The default unit mode is "DIPS" which causes all drawing to be scaled. By switching to PIXELS mode, the system stops scaling the drawing and does everything 1:1.
m_d2dContext->SetUnitMode(D2D1_UNIT_MODE_PIXELS);
As part of an application, I have a canvas object <Canvas Name="canvas"/> into which I am trying to insert the components of a clock as follows
// Add Background
Image bg = new Image();
bg.SetValue(Canvas.ZIndexProperty, 0);
bg.Source = new BitmapImage(new Uri("images/background.png", UriKind.Relative));
canvas.Width = bg.Source.Width;
canvas.Height = bg.Source.Height;
canvas.Children.Add(bg);
// Add second hand
Image hand = new Image();
hand.SetValue(Canvas.ZIndexProperty, 10);
hand.Source = new BitmapImage(new Uri("images/hand.png", UriKind.Relative));
canvas.Children.Add(hand);
The first image (bg) appears correctly but the second one (hand) appears to be scaled (original size is 5 x 61 pixels, interrogating image size after creation shows it has become 6.66 x 84.02 display units)
(bg original is 130 x 130 pixels and shows as 130.4 in display units)
All the answers to my query that I can find (StackOverflow and Google) suggest DPI setting of image but both my images are 96 DPI (according to Paint)
I have tried moving the image declarations into the XAML (not a long term solution) but this makes no difference. I have tried changing the order in which I insert the images with no effect. I have set the canvas width/height explicitly in the XAML - no effect.
I have set the size of the image explicitly - again no effect.
Can anybody tell me what is going on?
added: Compiled using .net 4 on windows7 64bit
Resolved:
Paint was reporting an incorrect DPI setting for the image.
Paint.Net gave me the correct value and by changing this to 96 DPI the problem was resolved
Issue resolved: Paint was reporting an incorrect DPI. Using an alternate paint package (Paint.net) showed the DPI was different. Correcting this setting fixed the issue.
You haven't set Width and Height for the second image and this had probably caused the issue.
You can also try to disable image stretching by adding a line (this should at least not scale the image, even if the control is scaled):
hand.Stretch = Stretch.None;
Update: I've just noticed You've already tried setting the dimensions of the image. Try to set if in the code. I'm currently looking for another possible causes of this problem.
Update II: I see You've found a solution. I'm glad you've made it work :).
I have a Bitmap object created by drawing several controls with the DrawToBitmap method. I would now like to print the bitmap. However, the bitmap is too large to fit on a single page and so it must be scaled down. I'm trying to do that using the following overload of DrawImage:
public void PrintPageHandler(object sender, PrintPageEventArgs e)
{
Bitmap bitmap = GetBitmap();
Rectangle destRect = new Rectangle(
e.MarginBounds.X,
e.MarginBounds.Y,
e.MarginBounds.Width,
e.MarginBounds.Width * bitmap.Height / bitmap.Width);
e.Graphics.DrawImage(
bitmap,
destRect,
0,
0,
bitmap.Width,
bitmap.Height,
System.Drawing.GraphicsUnit.Pixel);
}
Note that the destRect width and height are constructed like this because the bitmap is much wider than it is tall (i.e. width is always the limiting dimension).
My problem is that the image ends up being very blurry when it's printed. Am I scaling this incorrectly? I have a feeling there may be some issue with a GraphicsUnit mismatch between e.MarginBounds and the image dimensions. Any help would be appreciated.
[UPDATE]
I tried resizing the bitmap using the method given in the comment below, but the image still prints blurry. For testing, I saved both the original and resized bitmap to files, opened them in Windows Photo Viewer, and tried to print them from there. The resized image prints blurry like it does from within my c# application, but the original image prints beautifully; whatever algorithm Windows Photo Viewer uses to resize to a single page did not cause the image to get blurred.
I wonder, could Windows Photo Viewer be increasing the pixel density when it resizes for printing? Maybe that's why resizing it in code is causing it to get blurred; the origin pixel density is insufficient to display the scaled down image clearly.
It doesn't look like you are preserving the aspect ratio. You need to calculate the ratio of the width to height of the original image and make sure to scale the output image so that it's dimensions have the same ratio.
Basically:
1 - Calculate the aspect ratio.
2 - Find the largest dimension of the target size.
3 - Resize the output so that the largest dimensions matches, and set the smaller dimension to the larger one multiplied by the ratio.
EDIT
Check the graphics.dpiX and .DpiY proeprties to see if your printer has a different DPI going horizontally from vertically. If they are different you will have to apply some additional adjustments to the dimensions.
I am trying to draw two images side-by-side using the C# Drawing namespace.
Here is a very simple example that assumes we have two images of the same height:
Image[] oldImages = GetOldImages();
var newImage = new Bitmap(oldImages[0].Width + oldImages[1].Width, 800);
using (var newImageGraphics = Graphics.FromImage(newImage))
{
newImageGraphics.DrawImage(oldImages[0], 0, 0);
newImageGraphics.DrawImage(oldImages[1], oldImage[0].Width, 0);
newImageGraphics.Save();
}
This works OK if the resolution of the two old images are the same.
However, if the resolutions are different then the image is resized, causing problems. For example, if the first image has a different resolution, then the second image will be positioned incorrectly.
Does anyone know how I can fix this problem easily? Ideally I want the original image's height and width to remain the same when they are drawn on to the new image.
Try this trick:
Bitmap picture_1 = new Bitmap(picture_1_path);
Graphics graphics = Graphics.FromImage(picture_1);
Bitmap picture_2 = new Bitmap(picture_2_path);
picture_2.SetResolution(graphics.DpiX, graphics.DpiY);
//Then do with pictures anything
Basically you'll need to resize the second image before adding to the new image.
Though as you say you want to retain the original height and width you'll need to change the canvas size of the second image. This increases the size of the image by adding empty space around the actual image. If the second image is larger than the first you'll need to do this to the first image instead.