Iam trying to convert a vector image(SVG) to PNG. I almost got it working except the final touch which has something todo with Shape Rendering.
I use the following code:
public string GeneratePng()
{
SvgDocument SvgDoc = SvgDocument.Open(#"C:\Temp\test.svg");
SvgDoc.Width = 1000;
SvgDoc.Height = 1000;
SvgDoc.ShapeRendering = SvgShapeRendering.GeometricPrecision;
Bitmap bmp = SvgDoc.Draw();
bmp.Save(#"C:\Temp\test.png", ImageFormat.Png);
return "done";
}
I use the nuget package: nuget.org/packages/Svg/
and the following svg file: https://www.w3.org/Icons/SVG/svg-logo-h.svg
The result https://i.stack.imgur.com/4bw9G.png with the edges pixelated. What I except it to do is to smoothen out the edges as stated GeometricPrecision would do.
Can anyone tell me what I am missing or doing wrong?
Related
I've been searching for some good examples of how to take a screenshot using ITakesScreenshot in Selenium Webdriver in C#, then to crop the image using the elements dimensions and then saving this new image. With no such luck have I found any in C#.
I have this method at the moment but every so often I get a Out of Memory exception when used in a test. It fails on the line where it tries to crop.
public void TakeScreenShotOfElement(IWebDriver _driver, string rootpath, string imgName, string element2)
{
string element3 = element2;
var element = driver.FindElement(By.XPath(element3));
Byte[] ba = ((ITakesScreenshot)driver).GetScreenshot().AsByteArray;
var ss = new Bitmap(new MemoryStream(ba));
var crop = new Rectangle(element.Location.X, element.Location.Y, element.Size.Width, element.Size.Height);
//create a new image by cropping the original screenshot
Bitmap image2 = ss.Clone(crop, ss.PixelFormat);
if (!Directory.Exists(rootpath))
{
Directory.CreateDirectory(rootpath);
}
image2.Save(String.Format("{0}\\{1}.png", rootpath, imgName), System.Drawing.Imaging.ImageFormat.Png);
}
Any help is much appreciated, thanks in advance!!!
Some of the objects you're creating are IDisposable. You need to make sure Dispose() gets called on them. As it stands they're not releasing the memory they've claimed, which is why you get the exceptions.
The easiest way to make sure these items get disposed is to wrap each of them in a using block.
I'm staring with the Nokia Imaging SDK to play a little with it. Now, I'm facing the problem where I have an Image which already exists (in a folder in my visual studio solution) and I want to convert this image in order to use it in the BlendFilter class of the Nokia Imaging SDK. However I don't know how to use it.
I was trying to convert the existing image in a stream and then pass it as a parameter to the BlendFilter constructor. But not luck. The compiler says that the best overload method match ... has some invalid arguments.
This is the way I'm trying to load the existing image to a stream:
Image image = new Image();
image.Source = new BitmapImage(new Uri("/Images/Template3.2.png", UriKind.Relative));
BitmapImage bitImage = new BitmapImage(new Uri("/Images/Template3.2.png", UriKind.Relative));
WriteableBitmap Bitmap = new WriteableBitmap(bitImage);
And then:
var BlendFilter = new BlendFilter(bitImage, BlendFunction.Add); --> the compiler error is here
Does anyone know how to use the BlendFilter class? any example would be very helpful.
Regards!
Blend filter takes an IImageProvider as input. That means you can use any of the X-ImageSource classes as input and it will do all the work internally.
If you have a stream of the image I suggest you create an StreamImageSource and pass that to BlendFilter.
The list of different image sources is quite long, I suggest you look into the documentation and chose the one that is most appropriate to you.
Here is an example that takes a stream of an image as input, and blends a new image on top of it. For simplicity the other image is just an image filled with one color (ColorImageSource), but you can set any IImageProvider as source: chose the most convenient one.
using (var backgroundSource = new StreamImageSource(stream))
using (var filterEffect = new FilterEffect(backgroundSource))
{
using (BlendFilter blendFilter = new BlendFilter())
{
var size = new Windows.Foundation.Size(400, 400);
var color = Windows.UI.Color.FromArgb(250, 128, 255, 200);
blendFilter.ForegroundSource = new ColorImageSource(size, color);
blendFilter.BlendFunction = BlendFunction.Add;
filterEffect.Filters = new[] { blendFilter };
var result = await new JpegRenderer(filterEffect).RenderAsync();
}
}
I am using an Epson Perfection V700 scanner and selecting the following options when scanning using their tool:
ICM Color correction (source: EPSON-Standard and target: sRGB)
Unsharp Mask (medium)
That produces this image:
Now my problem is this - I actually need to interact with this scanner using TWAIN .Net and when I do so, the image I get back is this:
Aside: I unselected the aforementioned two options and scanned again with the Epson and got a very similar image to what I get through TWAIN.
So I figure that perhaps these are post processing steps that I can do myself on the image (maybe they are done in the hardware somehow though, I don't know).
I am using EmguCV so first of all I created an extension method that applies the ICM (I struggled to find any documentation for this, so it is a bit of a guess and maybe I am wrong straight away but I got the information from here: The bitmap transform class and it seems to make a difference to the image):
public static Image<Bgr, TDepth> ApplyIcm<TDepth>(
this Image<Bgr, TDepth> source,
string sourceIcm,
string targetIcm)
where TDepth : new()
{
var target = source.CopyBlank();
using (source)
{
using (var b = source.Bitmap)
{
using (var memory = new MemoryStream())
{
b.Save(memory, ImageFormat.Bmp);
memory.Position = 0;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
var ccb = new ColorConvertedBitmap();
ccb.BeginInit();
ccb.Source = bitmapImage;
ccb.SourceColorContext =
new ColorContext(new Uri(sourceIcm));
ccb.DestinationColorContext =
new ColorContext(new Uri(targetIcm));
ccb.EndInit();
var encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(ccb));
using (var ms = new MemoryStream())
{
encoder.Save(ms);
target.Bitmap = new Bitmap(ms);
}
}
}
}
return target;
}
Then I looked at that unsharpen thing and came across this question: How to sharpen an image in OpenCV? which says:
You use a gaussian smoothing filter and subtract the smoothed version from the original image
(I also checked this question to find out what the equivalent emgucv call is Why might EmguCV Gaussian blur not return identical results as OpenCV Gaussian blur?) and came up with this additional extension method:
public static Image<Bgr, TDepth> UnsharpMask<TDepth>(
this Image<Bgr, TDepth> source,
Size kernelSize,
int kernelHoritonalStandardDeviation,
int kernelVerticalStandardDeviation,
double alpha,
double beta,
double gamma)
where TDepth : new()
{
Image<Bgr, TDepth> ret = source.CopyBlank();
CvInvoke.cvSmooth(source,
ret,
SMOOTH_TYPE.CV_GAUSSIAN,
kernelSize.Width,
kernelSize.Height,
kernelHoritonalStandardDeviation,
kernelVerticalStandardDeviation);
CvInvoke.cvAddWeighted(source, alpha, ret, beta, gamma, ret);
return ret;
}
Now I call it like so:
string sourceIcm = #"C:\Windows\System32\spool\drivers\color\ewrgb18.icm";
string targetIcm = #"C:\Windows\System32\spool\drivers\color\ewsrgb.icm";
using(var im = new Image<Bgr, byte>("out.bmp"))
{
using (var icmmed = im.ApplyIcm(sourceIcm, targetIcm))
{
using (var ret = icmmed.UnsharpMask(new Size(0, 0), 5, 5, 2.4, -1.5, 0))
{
ret.Save("ret.bmp");
}
}
}
and this is the result:
Not very good! :-(
I have fiddled with the parameters endlessly but I just cannot work out how (or even if) I can achieve the same result as the Epson tool.
So, my question is:
Does anyone know if it is possible to achieve a result using opencv/emgucv (or even TWAIN - I had a look through the documentation for that and tried adjusting some of the capability parameters but I just made the image worse) that is similar in sharpness to the original image above or is there another technique I should try (could it be that I would need to know some details about the hardware itself in order to achieve correct sharpening)?
I think you should know how using WIA (Windows Image Acquisition) in your project, you may don't need to get access to hardware using opencv. WIA is used for integrating with webcams and scanners. Or, you can use TWAIN as you mentioned
have a look at these examples they could by helpful for your project:
using WIA
and
using TWAIN
Concerning the sharpening, you can use opencv functionality at software level, as another choice to solve your problem
What is the C# equivalent of the following Java snippet below:
Drawable image;
URL imageUrl;
imageUrl = new URL(getMyImageUrl(imageNumber));
Bitmap bitmap = BitmapFactory.decodeStream(imageUrl.openStream());
image = new BitmapDrawable(bitmap);
Thanks in advance.
A more literal conversion to C# would be:
var imageUrl = new Java.Net.URL(GetMyImageUrl(imageNumber));
var bitmap = Android.Graphics.BitmapFactory.DecodeStream (imageUrl.OpenStream ());
var image = new Android.Graphics.Drawables.BitmapDrawable (bitmap);
This is one of the strengths of Mono for Android: the classes and methods mirror the underlying Java platform (with some exceptions) while providing much of the .NET framework, so migrating code from Java to C# should be reasonably straightforward.
using System.Drawing;
using System.Drawing.Imaging;
public Bitmap DownloadImage(string imageUrl)
{
try
{
WebClient client = new WebClient();
using(Stream stream = client.OpenRead(imageUrl))
{
Bitmap bitmap = new Bitmap(stream);
}
}
catch(Exception)
{
//todo: handle me
throw;
}
return bitmap
}
Have a look at http://www.dreamincode.net/code/snippet2555.htm . I assumed you would want to use Bitmap. I have never used Drawable in Java, so correct me if I'm wrong.
How to read a tiff file's dimension (width and height) and resolution (horizontal and vertical) without first loading it into memory by using code like the following. It is too slow for big files and I don't need to manipulate them.
Image tif = Image.FromFile(#"C:\large_size.tif");
float width = tif.PhysicalDimension.Width;
float height = tif.PhysicalDimension.Height;
float hresolution = tif.HorizontalResolution;
float vresolution = tif.VerticalResolution;
tif.Dispose();
Edit:
Those tiff files are Bilevel and have a dimension of 30x42 inch. The file sizes are about 1~2 MB. So the method above works Ok but slow.
Ran into this myself and found the solution (possibly here). Image.FromStream with validateImageData = false allows you access to the information you're looking for, without loading the whole file.
using(FileStream stream = new FileStream(#"C:\large_size.tif", FileMode.Open, FileAccess.Read))
{
using(Image tif = Image.FromStream(stream, false, false))
{
float width = tif.PhysicalDimension.Width;
float height = tif.PhysicalDimension.Height;
float hresolution = tif.HorizontalResolution;
float vresolution = tif.VerticalResolution;
}
}
As far as I know, all classes from System.Drawing namespace load image data immediately when image is open.
I think LibTiff.Net can help you to read image properties without loading image data. It's free and open-source (BSD license, suitable for commercial applications).
Here is a sample for your task (error checks are omitted for brevity):
using BitMiracle.LibTiff.Classic;
namespace ReadTiffDimensions
{
class Program
{
static void Main(string[] args)
{
using (Tiff image = Tiff.Open(args[0], "r"))
{
FieldValue[] value = image.GetField(TiffTag.IMAGEWIDTH);
int width = value[0].ToInt();
value = image.GetField(TiffTag.IMAGELENGTH);
int height = value[0].ToInt();
value = image.GetField(TiffTag.XRESOLUTION);
float dpiX = value[0].ToFloat();
value = image.GetField(TiffTag.YRESOLUTION);
float dpiY = value[0].ToFloat();
}
}
}
}
Disclaimer: I am one of the maintainers of the library.
Try this, it seems to be what you are looking for. Just skip everything after:
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, ref w); //your width
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, ref h); //your height
TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, ref bits);
TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, ref samples);
Don't forget to close after you:
TIFFClose(tif);
The only way I can think of is reading the tiff binary header.
Here you can download the specification: http://partners.adobe.com/public/developer/tiff/index.html
Here is some code used to read Tiffs that you can use to learn:
http://www.koders.com/csharp/fidF6632006F25B8E5B3BCC62D13076B38D71847929.aspx?s=zoom
I created a library to read the tiff headers some time ago (with this two resources as base) but it was part of my employer code so I can't post my code here and I can say it is no really hard.
I Hope this helps.