A simple question - If I want to print a picture so it best fits the page in C#, do I have to scale it to the dimensions of the page myself ?
I've noticed the many good answers about how-to scale, I just want to know If I need to scale myself, as the scaling isn't a part of an image processing, it's only for the sake of the printing.
(a simple yes (if it's the answer) would do)
Edit:
Currently I'm scaling using:
e.Graphics.DrawImage(my_image, destRect, srcRect, GraphicsUnit.Pixel);
Whereas destRect is a rectangle of the dimensions of the wanted output, I've done a simple algorithm to set this destRect to optimal sizes while preserving the original aspect ratio. (btw I'm not happy with this simple scaling, as it lacks in Image quality, will probably update to something fancier if I must).
But I've wanted to know if there's some auto-scaling provided by the framework for printing purposes, I really don't want to re-invent this wheel..
I'm not sure if this is as simple as yes/no. I suspect that you must still use GDI+ and the Graphics object, so scaling is as simple as calling Graphics.DrawImage(...) on the graphics object for the printing device. Some printer drivers might support scaling the source automatically, though.
Related
I am trying to write a drawing application that allows users to select two points on canvas and draws a line between those points pixel-by-pixel. In WinForms that would be an easy solution - create a canvas, get its bitmap, draw on the bitmap using the SetPixel method, and replace the canvas bitmap. I am wondering if there is a way to do this in a similar way in AvaloniaUI? From what I understood, it uses SkiaSharp under the hood. However, solutions to render SKCanvas on Avalonia.Controls.Canvas seem... hard. Although SKBitmap also has the SetPixel method. The question is not about how to draw a line - it is about how to set single pixels on Bitmap in AvaloniaUI and set this bitmap to the Avalonia.Controls.Canvas.
Here are some links I found:
https://github.com/AvaloniaUI/Avalonia/pull/2371
https://github.com/AvaloniaUI/Avalonia/issues/2492
AvaloniaUI - How to draw directly on the canvas - Unfortunately, I am not allowed to draw on the canvas itself.
Artifacts on Avalonia WriteableBitmap BitmapContext - unsafe code, three extension methods... while an option seems a little bit too complex.
P.S. As tempting as this may sound, drawing a rectangle-by-rectangle of size 1x1 as in the official documentation example (https://docs.avaloniaui.net/docs/controls/canvas) is also not allowed by the university.
P.P.S. I am not asking anyone to do the homework for me - in case you are worried about that please, consider this a framework comparison question, not a "please do that for me" one. I have found and linked solutions that I can use - it just seems to me that there should be a more easy way to achieve the result I seek. That's why I have asked the question - in case I missed something.
Doing a Jedi thing: this is not some student trying to lay off his work on other people. You can go by your business
UPDATED: you can swap bitmap on the image control: https://docs.avaloniaui.net/docs/controls/image
The original question (although poorly stated, my bad) was intented to clarify if there is a way to perform the SetPixel operation on the Avalonia bitmap. Unfortunately, currently, it doesn't seem like an available option: so the only way is to either create a custom drawing context OR control OR conversion between different Bitmap types (like System.Drawing.Bitmap or SkBitmap from SkiaSharp) to Avalonia.WriteableBitmap. All those solutions are referenced in the original question.
Now I used next code to download picture from desctop to PictureBox
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "BMP|*.bmp";
if (openFileDialog.ShowDialog() != DialogResult.OK)
return;
pictureBox.Load(openFileDialog.FileName);
pictureBox.SizeMode=PictureBoxSizeMode.StretchImage;
pictureBox.BorderStyle = BorderStyle.Fixed3D;
If I used a normal picture(100x100) it looks nice(unfuzzy).
If I used a smal picture(15x15) it looks fuzzy.
I want to know how to make them unfuzzy( they can look like bricks, but they need to be unfuzzy);
Waiting result for small picture need to look like this
Waiting result for normal picture need to look like this
The fuzziness comes from image interpolation. To have your desired blocky look, you need to use nearest neighbour interpolation.
Thankfully, .NET has this build into. You can set to the interpolation mode to the GDI Graphics object which renders your PictureBox.
To do so I'd recommend exteding the PictureBox user control and adding an InterpolationMode parameter. Then, you can override the OnPaint method, and use your interpolation mode.
public class InterpolatingPictureBox : PictureBox
{
public InterpolationMode InterpolationMode { get; set; }
protected override void OnPaint(PaintEventArgs eventArgs)
{
eventArgs.Graphics.InterpolationMode = InterpolationMode;
base.OnPaint(eventArgs);
}
}
Here is a 16x16 image: , upscaled to 256x256 using
NearestNeighbour (left)
Bilinear (which is default, middle)
HighQualityBilinear (right)
All are rendered on the InterpolatingPictureBox control.
You have a SERIOUS problem. There is no easy solution.
I want to know how to make them unfuzzy
Impossible. Sharpening (which is what you want) of images to larger resolution is possible within reason, but this takes seriously advanced programs that run for quite some time. Not talking as programmer here - but this is a standard step in printing fine art photography. Photos have a relatively low resolution (mine come at up to 43 megapixel) and printers a much higher one.
There are some AA approaches that are easy, but 10x10 sized up t0 100x100 is going to challenge even the most advanced programs - 10x10 is nothing to work with. You talk of 10x starting with no data on the beginning.
You CAN turn off anti aliasing, resize the image in code (easy to do) with no anti aliasing - but this will turn real pictures looking UGLY. .NET has no real high level sharpening functionality and again, 10x10 is not enough to start working with.
The best you can do is not load them into a picture box. Load them into a bitmap, then draw that onto a new bitmap of optimal size (100x100). This at least gives you full control over the resizing.
The code for this you can find at
Scaling a System.Drawing.Bitmap to a given size while maintaining aspect ratio
while
Image resizing in .Net with Antialiasing
tells you how to select anti aliasing.
But again: expect quite little. Those anti aliasing modes are purely technical and not anything that you use for photos. Plus selecting the right one depends on the input image - so you can use a default or give the user a choice. I am probably overcomplicating things, but outside programming I actually DO deal with images that need to be scaled up with as little image loss as possible for large printing.
We need to:
Measure text accurately.
Render text line by line to a screen graphics context in the presence of translation and scaling transforms applied to the graphics context.
Hit testing: allow text to be selected precisely with the mouse or via a displayed caret.
Print the result if needed, and as accurately as possible, with a printer. Note: this is secondary. Screen rendering and hit testing are primary.
Run on Windows XP and higher operating systems.
within a WinForms application that is also rendering graphics and images to the same graphics context.
There are four technologies that we've encountered. We've tried using the first two, and ran into the issues described, over the course of several months.
GDI+
Purportedly resolution-independent text. However according to this question - and other sources - this technology is to be avoided because of quality issues.
MSDN states that calling Graphics.MeasureString along with StringFormat.GenericTypographic and TextRenderingHint.AntiAlias produces accurate string measurement. However, in our experience, and that of others, this is not the case - we do not get accurate string measurements.
Pros: Fast
Cons: inaccurate string measurement.
Result: unusable because of inaccurate string measurement.
GDI via TextRenderer
This was introduced to overcome the limitations of GDI+. However this introduced limitations of its own:
Very slow
Does not work with graphics transforms
Result: unusuable for these reasons
GDI via p/invoke
Calling GetTextExtentExPoint for text measurement and DrawText / DrawTextEx / ExtTextOut for rendering.
We haven't tried this yet.
DirectWrite
This seems promising, since it interoperates with other technologies including GDI/GDI+, so presumably the rest of our graphics rendering wouldn't change. However it is only available for Windows Vista and more recent Windows versions. This is presently a problem since Windows XP still has a significant installed base.
Question
Which of these technologies can be made to work given the requirements?
Note: There's much misinformation about this topic floating around, so please answer this question only if you have expertise in this area.
Also, please don't suggest WPF - that isn't something we're considering using.
Supposedly the MeasureCharacterRanges function is more accurate than MeasureString.
If you have to target both the screen and a printer, then you need to make some decisions about your approach before deciding which rendering engine to use. Here are some possibilities:
Lay out in screen units and do a best-possible approximation for the printer.
Lay out in printer units and do a best-possible approximation for the screen.
Lay out in a theoretical high-resolution space and do a best-possible approximation for both printer and screen.
In all cases, the best-possible approximation might be done by very careful approximations at each step, which can give the highest fidelity for each device at the cost of accuracy in matching, or you could render to bitmap and scale to the device, which gives lower fidelity but a the best-possible approximation to the other space.
I've done hard-core print preview with GDI. It's hard, but do-able for regular layouts. But if you're handling arbitrary transforms, especially rotations other than +/-90 degrees, it's nigh impossible.
It's very easy to make subtle mistakes and believe that the measurements you get back are wrong.
Font hinting makes font scaling non-linear when the stroke widths are on the same order of magnitude as the dpi, so if you get a width w for some text, then the width if you double the size of the font may not be exactly 2*w.
Font substitution is common in many printer drivers. Even if you choose a TrueType or OpenType font you might not get the same font on the printer as you got on the screen.
Non-square pixels are common in some printers. These can mess up even decent rasterizers when you're doing something that's not axis-aligned.
Kerning can be surprising. Don't assume that width('a') + width('b') == width("ab").
Rounding errors are easy to make. Sometimes you have to know the rounding rules used by the underlying rasterizer.
Measuring in the wrong context is too common. Don't try to measure in a screen context and apply a transform to get to printer units. If you need printer units, measure in the printer context.
I'm of the opinion today that if you need just print preview, then you should lay out in printer units to a bitmap that's sized to the page, and scale the bitmap to the screen based on the ratios of the DPIs. That's the easiest thing to do and it gives good results. But it's not clear if a good hardcopy and print-preview is really what you're after.
I had similar requirements and ran into the same problems with text rendering and scaling. Even my attempts with WPF (.NET 3.5) were a nightmare, for many reasons.
I ended up using GDI+ graphics.DrawString, despite being 'deprecated', with a funny trick to get accurate text measurements.
static public RectangleF MeasureInkBox(Graphics graphics, string text, Font font)
{
var bounds = new RectangleF();
using (var textPath = new GraphicsPath())
{
textPath.AddString(
text,
font.FontFamily,
(int)font.Style,
font.Size,
new PointF(0, 0),
StringFormat.GenericTypographic );
bounds = textPath.GetBounds();
}
return bounds;
}
The speed and quality turned out to be satisfying. Also, graphics.DrawString is the recommended way to print text with winforms.
Measuring individual character positions can be tricky due to kerning, but I guess a slightly more complex version of this method could do the job. For example, for "Hello" it would measure "H", then "He", then Hel" and so on. It should not degrade performances significantly, especially if you do it on he fly when receiving a click on the word.
I found an article on image processing from here: http://www.switchonthecode.com/tutorials/csharp-tutorial-image-editing-saving-cropping-and-resizing Everything works fine.
I want to keep the high quality when resizing the image. I think if I can increase the DPI value I can achieve this. Does anyone know if this is possible? And if so, how can I implement it in C#?
For starters, it's worth pointing out that there are two general categories of images; vector [e.g. SVG, WMF, Adobe Illustrator and Corel Draw Graphics] and bitmap (also called raster) images [e.g. Bitmap, JPEG and PNG Images].
Vector images are formed from a series of mathematical equations and/or calculations. Bitmap images, on the other hand, are made up of individual dots (pixels) each corresponding to a particular feature on the object the image is taken of.
If it should happen that you want to resize an image, the first thing to consider is if it is a bitmap or vector image. By virtue of the fact that vector images are obtained from calculations, they can be perfectly resized without losing any detail. The case is different for bitmap images. Since each pixel is independent of the other, when you desire to resize it, you are simply increasing or decreasing the source to target pixel ratio.
So in order to double the size of a vector image, simply multiply the target dimensions by two and everything comes out all right. If you should apply the same effect on a bitmap, you are actually increasing each source pixel to cover four pixels (two rows of two horizontal pixels).
Of course, by applying interpolation and filtering, the computer can "smooth" out the edges of the target pixels so they seem to blend into each other and give the appearance of a reasonably resized image but this output is never the same as resizing a vector image; vector images resize perfectly.
You also mentioned DPI in your question. DPI is essentially the number of pixels that correspond to an inch when the image is printed not when it is viewed on a screen. Therefore by increasing the DPI of the image, you do not increase the size of the image on the screen. You only increase the quality of print [which needless to say depends on the maximum resolution of the printer].
If you really desire to resize the image and the image is a bitmap, as a rule of thumb, do not increase the size beyond 200% of the original image's size else you'll lose the quality.
You can see this answer for code to resize bitmap images.
To see a sample vector image, go to this link.
Note Try zooming in and out of the image to see how well it resizes.
A typical bitmap are the StackOverflow sprites. They do not keep their quality resized.
Further Reading
Vector Graphics: http://en.wikipedia.org/wiki/Vector_image
Bitmap Graphics: http://en.wikipedia.org/wiki/Bitmap_image
Simply If the original image is smaller then the re-sized image then there is hardly anything you can do. Rest is a research problem.
This would only be possible if it's a vector graphic. Look into SVG. Otherwise, I think you might need Silverlight or Flex for that part.
What you're asking isn't really possible. You can't enlarge an image while maintaining the same quality.
If you think about an image as a mapped array of pixels (literally, a "bit-map"), this makes sense. The image is saved with a fixed amount of data, and that's all you have to work with when you resize it. Any examples to the contrary (like TV shows, as suggested by one of the comments) are purely fictional.
The best that you can do is set the InterpolationMode property of the Graphics object you're using to do the resizing to "HighQualityBicubic", which is the highest quality smoothing algorithm supported by GDI+ and in fact by every major graphics package on the market. It's the best that even Adobe Photoshop has to offer. Essentially, interpolation means that the computer is calculating the approximate value of the new pixels you're adding to make the image larger from the relative values of neighboring pixels. It's a "best guess" method, but it's the best compromise we've come up with yet.
At the very least, the resulting images won't have "jaggies" or rough, pixelated lines.
Sample code:
Graphics g;
g.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
// ... insert the rest of your code here
Beyond that, it's worth noting that GDI+ (which the .NET Framework uses internally for graphics routines) works best with image sizes that are multiples of 16. So if it all possible, you should try and make the width and height of your resized images a multiple of 16. This will preserve as much of the original image quality as possible.
The ideal solution is to switch to vector graphics that can be resized at will. Instead of pixel information, they contain mathematical information used to draw or "render" the image. Read more on Wikipedia.
let's try metadata in GDI+, may be it can suit your request
I have bitmaps of lines and text that have anti-alias applied to them. I want to develop a filter that removes tha anti-alias affect. I'm looking for ideas on how to go about doing that, so to start I need to understand how anti-alias algorithms work. Are there any good links, or even code out there?
I need to understand how anti-alias algorithms work
Anti-aliasing works by rendering the image at a higher resolution before it is down-sampled to the output resolution. In the down-sampling process the higher resolution pixels are averaged to create lower resolution pixels. This will create smoother color changes in the rendered image.
Consider this very simple example where a block outline is rendered on a white background.
It is then down-sampled to half the resolution in the process creating pixels having shades of gray:
Here is a more realistic demonstration of anti-aliasing used to render the letter S:
I am not familiar at all with C# programming, but I do have experience with graphics. The closest thing to an anti-anti-alias filter would be a sharpening filter (at least in practice, using Photoshop), usually applied multiple times, depending on the desired effect. The sharpening filter work best when there is great contrast already between the anti-aliased elements and the background, and even better if the background is one flat color, rather than a complex graphic.
If you have access to any advanced graphics editor, you could try a few tests, and if you're happy with the results you could start looking into sharpening filters.
Also, if you are working with grayscale bitmaps, an even better solution is to convert it to a B/W image - that will remove any anti-aliasing on it.
Hope this helps at least a bit :)