I have some code to convert an image, which is working now, but the width of the image that is generated is really small. I would like to force it to use a width of 600px.
My code looks like this:
public async Task<string> ConvertImage(byte[] data)
{
// Create our settings
var settings = new MagickReadSettings
{
Width = 600
};
// Create our image
using (var image = new MagickImage(data, settings))
{
// Create a new memory stream
using (var memoryStream = new MemoryStream())
{
// Set to a png
image.Format = MagickFormat.Png;
image.Write(memoryStream);
memoryStream.Position = 0;
// Create a new blob block to hold our image
var blockBlob = container.GetBlockBlobReference(Guid.NewGuid().ToString() + ".png");
// Upload to azure
await blockBlob.UploadFromStreamAsync(memoryStream);
// Return the blobs url
return blockBlob.StorageUri.PrimaryUri.ToString();
}
}
}
The image I have uploaded is an AI file, but when it gets converted it is only 64px wide.
Does anyone know why and how I can fix it?
With the current version of Magick.NET this is the expected behavior. But after seeing your post we made some changes to ImageMagick/Magick.NET. With Magick.NET 7.0.0.0103 and higher you will get an image that fits inside the bounds that you specify with Width and Height. So when you specify a Width of 600 you will get an image that is 600 pixels wide.
Related
As the title says. It seems that Avalonia Bitmap requires file path, so the only solution that comes to my mind is saving image, and then displaying it. But it's not exactly what I want to do, I would want to directly display the image from memory.
public void ReadAndDisplayImage()
{
ReadWrite rw = new ReadWrite();
var image = rw.ReadImage(ImagePath); //ImageSharp Image
SelectedImage = new Avalonia.Media.Imaging.Bitmap(ImagePath); //constructor accepts only string, unable to display ImageSharp Image directly
}
In this case here displaying from path is fully acceptable, but later I will need to display it without saving.
You can save the Image's data into a memory stream and pass it in to Avalonia's Bitmap.
public void ReadAndDisplayImage()
{
ReadWrite rw = new ReadWrite();
var image = rw.ReadImage(ImagePath);
using (MemoryStream ms = new MemoryStream())
{
image.Save(ms,PngFormat.Instance);
SelectedImage = new Avalonia.Media.Imaging.Bitmap(ms);
}
}
We want to take a scanned image and determine if it is landscape or portrait, then based on the user's preference of having it rotated to landscape or portrait, rotate it if needed.
i.e. the user wants it in portrait, but its original format was landscape.
How do we determine if it is portrait or landscape and then if required, rotate it 90 degrees.
Trying something like this, but getting stuck on streams not being opened or reset, etc...But more importantly, is this the right/most efficient approach? I don't see any instructions to do this automatically like :desiredAspectRation=Portrait; that would do this already in ImageResizer.net, correct?
int? imageWidth;
int? imageHeight;
using (var updatedImageFileStream = new MemoryStream())
{
ImageJob imageJob = new ImageJob(origFileStream, updatedImageFileStream,
new Instructions(strInstructions)
);
imageJob.Build();
//change to portrait if required
imageWidth = imageJob.SourceWidth;
imageHeight = imageJob.SourceHeight;
if(imageWidth > imageHeight)
{
//updatedImageFileStream.Seek(0, SeekOrigin.Begin);
strInstructions = "rotate=90;";
imageJob = new ImageJob(updatedImageFileStream, updatedImageFileStream,
new Instructions(strInstructions)
);
imageJob.Build();
}
updatedImageFileStream.Seek(0, SeekOrigin.Begin);
//upload image to azure
await azureRepository.UploadAsync(serverRelativePath, updatedImageFileStream, contentType);
origFileStream.Dispose();
}
UPDATE
Got it to work using the below. But not sure it's the most efficient.
Do you need to create a new stream or can ImageJob take the same source and destination to overwrite it...I got an error about cannot access a closed stream when trying, so maybe you do need to create a new stream as I did.
I don't like the duplicate call to upload the image(await azureRepository.UploadAsync(serverRelativePath, updatedImageFileStream, contentType);) but I couldn't figure out how to copy the 2nd image stream over the first so I could retain just one call to the UploadAsync. I kept getting cannot access closed stream type errors.
am I missing anything else?
Working code, but efficient?
int? imageWidth;
int? imageHeight;
using (var updatedImageFileStream = new MemoryStream())
{
ImageJob imageJob = new ImageJob(origFileStream, updatedImageFileStream,
new Instructions(strInstructions)
);
imageJob.Build();
//change to portrait if required - WORKS, uncomment if want to do 100% of time, or this is how to implement based on a parameter of "change to Portrait"
imageWidth = imageJob.SourceWidth;
imageHeight = imageJob.SourceHeight;
if (imageWidth > imageHeight)
{
updatedImageFileStream.Seek(0, SeekOrigin.Begin);
strInstructions = "rotate=90;";
var updatedImageFileStream2 = new MemoryStream();
imageJob = new ImageJob(updatedImageFileStream, updatedImageFileStream2,
new Instructions(strInstructions)
);
imageJob.Build();
updatedImageFileStream2.Seek(0, SeekOrigin.Begin);
//upload image to azure
await azureRepository.UploadAsync(serverRelativePath, updatedImageFileStream2, contentType);
updatedImageFileStream2.Dispose();
}
else
{
updatedImageFileStream.Seek(0, SeekOrigin.Begin);
//upload image to azure
await azureRepository.UploadAsync(serverRelativePath, updatedImageFileStream, contentType);
}
origFileStream.Dispose();
}
Instead of processing the image just to get the dimensions, you could use Config.Current.CurrentImageBuilder.LoadImage instead and query the .Width and .Height on the resulting Bitmap instance. Remember to dispose it.
For an MUCH faster solution, you could use Imageflow.NET, with the ImageJob.GetImageInfo() method to get the width/height, and ImageJob.BuildCommandString(source, dest, "rotate=90") to perform the rotation. This will also have the benefit of producing much smaller file sizes at improved quality levels.
I'm trying to resize images into thumbnails in a .NET Core C# application using SixLabors.ImageSharp (version 1.0.0-beta0007). I've noticed that for only certain images, the resized image has a white, red, or blue distorted border, like so:
My code for generating the thumbnail is as follows:
using (var imageToResize = Image.Load(inStream, out IImageFormat imageFormat))
{
var size = GetThumbnailSize(imageToResize.Size()); //max size 150,preserves aspect-ratio
imageToResize.Mutate(x => x.Resize(new ResizeOptions()
{
Size = size,
Mode = ResizeMode.Crop
}));
using (var memorystream = new MemoryStream())
{
imageToResize.Save(memorystream , imageFormat);
ms.Position = 0;
outputStream.UploadFromStreamAsync(memorystream);
}
}
These two images were captured from the same device, and both have the same dimension (3024x4032) and these are the only similarities I could notice as I am a novice to image processing. I've also played around with the resize modes and different Resamplers, but could not resolve this.
What is causing this issue? Is there any way to fix this by using the SixLabors.ImageSharp library?
The issue was resolved after I modified the code to load the ImageSharp Image from a byte array instead of a stream. As per #JamesSouth's comment on the question above, it might have been my input stream not providing the all the bytes.
Below is the updated code:
// convert inStream to a byte array "bytes"
using (var imageToResize = Image.Load(bytes, out IImageFormat imageFormat))
{
Size newSize = GetThumbnailSize(imageToResize.Size()); //max size 150, preserves aspect-ratio
imageToResize.Mutate(x => x.Resize(newSize));
...
}
I need to convert a JPG image to PNG and change its white background to transparent instead. I am using ImageMagick.NET and I have found the following ImageMagick command that is supposed to do what I am trying to achieve:
convert image.jpg -fuzz XX% -transparent white result.png
I have tried converting this to c# but all I am getting is a png image with a white background. My code snippet:
using (var img = new MagickImage("image.jpg"))
{
img.Format = MagickFormat.Png;
img.BackgroundColor = MagickColors.White;
img.ColorFuzz = new Percentage(10);
img.BackgroundColor = MagickColors.None;
img.Write("image.png");
}
Any kind of help will be greatly appreciated. Thank you!!
This is a late response as it took me a while to find an answer myself, but this seems to work for me quite well. Look at where the Background property is assigned the Transparent value.
using (var magicImage = new MagickImage())
{
var magicReadSettings = new MagickReadSettings
{
Format = MagickFormat.Svg,
ColorSpace = ColorSpace.Transparent,
BackgroundColor = MagickColors.Transparent,
// increasing the Density here makes a larger and sharper output to PNG
Density = new Density(950, DensityUnit.PixelsPerInch)
};
magicImage.Read("someimage.svg", magicReadSettings);
magicImage.Format = MagickFormat.Png;
magicImage.Write("someimage.png");
}
In my case, I wanted to send this to UWP Image element, so instead of Write(), I did the following after the steps above:
// Create byte array that contains a png file
byte[] imageData = magicImage.ToByteArray();
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
using (DataWriter writer = new DataWriter(stream.GetOutputStreamAt(0)))
{
writer.WriteBytes(imageData);
await writer.StoreAsync();
}
await bitmapImage.SetSourceAsync(stream);
}
return bitMapImage; // new BitMapImage() was scoped before all of this
Then on the UWP Image element, simply use:
imageElement.Source = bitMapImage;
Most of the arguments on the command line are either properties or method on the MagickImage class. Your command would translate to this:
using (var img = new MagickImage("image.jpg"))
{
// -fuzz XX%
img.ColorFuzz = new Percentage(10);
// -transparent white
img.Transparent(MagickColors.White);
img.Write("image.png");
}
I'm using ImageMagick.NET for generating image from pdf. Its working, but the conversion process is too slow. Code -->
public void ProcessRequest(HttpContext context)
{
if (context.Request["id"] != null)
{
string id = context.Request["id"].ToString();
MagickReadSettings settings = new MagickReadSettings();
settings.Density = new MagickGeometry(300, 300);
using (MagickImageCollection images = new MagickImageCollection())
{
images.Read(System.Web.HttpContext.Current.Server.MapPath(string.Format("~/Reciepts/order{0}.pdf", id)), settings);
MagickImage vertical= images.AppendVertically();
using (var memoryStream = new MemoryStream())
{
vertical.ToBitmap().Save(memoryStream, ImageFormat.Jpeg);
var d = memoryStream.GetBuffer();
context.Response.Clear();
context.Response.ContentType = "image/jpeg";
context.Response.BinaryWrite(d);
context.Response.End();
}
}
}
}
Where i can improve ?
You are using Magick.NET not ImageMagick.NET.
It is not necessary to create a bitmap before you send it to the output stream. You can just do this:
using (MagickImage vertical=images.AppendVertically())
{
vertical.Format = MagickFormat.Jpeg;
vertical.Write(context.Response.OutputStream);
}
And maybe you should cache the result to a file?
If you decided to use Magick.NET, method is not wrong.
First answer gives you "Using" statement for MagickImage.
But this differs only a few milliseconds to finish the job.
I see that the slow line is this line:
images.Read(System.Web.HttpContext.Current.
Server.MapPath(string.Format("~/Reciepts/order{0}.pdf", id)), settings);
because of settings objects properties.
Your property says that image must be in 300dpi and 300 might be very high for your cpu:
settings.Density = new MagickGeometry(300, 300);
You can try to use lower density, not 300dpi. Lower density is more fast:
settings.Density = new Density(72, 72);
I think there must be another fast way to create image from pdf file. Magick.NET uses Ghostscript to generate image from pdf and Ghostscript is slow and sometimes not successful to generate image from complicated (layered) pdf's.