WriteableBitmap.Pixels in Windows Phone 8.1 - c#

I am writing a Windows Phone 8.1 (WINRT) App. I am using fileopenpicker to choose a picture from gallery and then i display it in my app. But i want that user can crop this image before getting displayed on app.
In windows phone 8, we used Photochooser task having width property and cropping options automatically used to come.
Now I am trying to use this :
Windows Phone 8.0: Image Crop With Rectangle
But there is no WriteableBitmap.Pixels in Windows Phone 8.1. What to use instead of WriteableBitmap.Pixels?
// Create a new WriteableBitmap. The size of the bitmap is the size of the cropping rectangle
// drawn by the user, multiplied by the image size ratio.
WB_CroppedImage = new WriteableBitmap((int)(widthRatio * Math.Abs(Point2.X - Point1.X)), (int)(heightRatio * Math.Abs(Point2.Y - Point1.Y)));
// Calculate the offset of the cropped image. This is the distance, in pixels, to the top left corner
// of the cropping rectangle, multiplied by the image size ratio.
int xoffset = (int)(((Point1.X < Point2.X) ? Point1.X : Point2.X) * widthRatio);
int yoffset = (int)(((Point1.Y < Point2.Y) ? Point1.Y : Point2.X) * heightRatio);
// Copy the pixels from the targeted region of the source image into the target image,
// using the calculated offset
if (WB_CroppedImage.Pixels.Length > 0)
{
for (int i = 0; i < WB_CroppedImage.Pixels.Length; i++)
{
int x = (int)((i % WB_CroppedImage.PixelWidth) + xoffset);
int y = (int)((i / WB_CroppedImage.PixelWidth) + yoffset);
WB_CroppedImage.Pixels[i] = WB_CapturedImage.Pixels[y * WB_CapturedImage.PixelWidth + x];
}
// Set the source of the image control to the new cropped bitmap
FinalCroppedImage.Source = WB_CroppedImage;
}
else
{
FinalCroppedImage.Source = null;
}

You should take a look at BitmapEncoder and BitmapDecoder classes.
Also you probably will be able to use BitmapBounds to crop your image - set 'X' and 'Y' along with 'Width' and 'Height'.
I think the code may look like this (but I've not tested it):
StorageFile destination; // your destination file
using (var sourceStream = await sourceFile.OpenAsync(FileAccessMode.Read))
{
BitmapDecoder bmpDecoder = await BitmapDecoder.CreateAsync(sourceStream);
// here you scale your image if needed and crop by setting X, Y, Width and Height
BitmapTransform bmpTransform = new BitmapTransform() { ScaledHeight = scaledHeight, ScaledWidth = scaledWidth, InterpolationMode = BitmapInterpolationMode.Cubic, Bounds = new BitmapBounds { X = topLeftX, Y = topLeftY Width = desiredSizeW, Height = desiredSizeH } };
PixelDataProvider pixelData = await bmpDecoder.GetPixelDataAsync(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, bmpTransform, ExifOrientationMode.RespectExifOrientation, ColorManagementMode.DoNotColorManage);
using (var destFileStream = await destination.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder bmpEncoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, destFileStream);
// here you need to set height and width - take from above
bmpEncoder.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, desiredSizeW, desiredSizeH, 300, 300, pixelData.DetachPixelData());
await bmpEncoder.FlushAsync();
}
}
Of course you don't need to save the edited picture to StorageFile - I've used it as an example, you can write to stream and then set your image source.

Related

bitmap merge different amount of images together every time c#

When i run the program, i get a different amount of images(from 20 all the way up to 2000) and i would like to merge all of these images into one image which would preferably be a square.
This is the code i have for getting the file images(the images are in URL format)
int ximg = 1;
int totalImgs = richTextBox1.Lines.Count();
while (ximg < totalImgs)
{
System.Net.WebRequest request = System.Net.WebRequest.Create(richTextBox1.Lines[ximg]);
System.Net.WebResponse response = request.GetResponse();
System.IO.Stream responseStream =
response.GetResponseStream();
Bitmap image = new Bitmap(responseStream);
List<Image> fileList = new List<Image>();
fileList.Add(image);
ximg++;
}
Also every single image has a title in a different richtextbox which i would like to know if it is possible to add a title under the image (richtextbox1.lines[1] (image) = richtextbox2.lines[1] (title)). Is it possible to add a picture as a background picture when merging(to the square image I want to generate)? Is it possible to add a border on every single image picture and merge them with the border? How can the code calculate when its time to change line and start adding images in the next row?
I've tried this code, but it works only if you know the amount of images you want to merge.
Bitmap bitmap = new Bitmap(image1.Width + image2.Width, Math.Max(image1.Height, image2.Height));
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawImage(image1, 0, 0);
g.DrawImage(image2, image1.Width, 0);
}
bitmap.Save("merged.bmp");
I would do it with photoshop but when there are 2000 images to merge together, I just do not have the time.
Is there any way to accomplish such task? Any references would be appreciated!
I have mentioned it above :) !
This solution will create a mosaic of the images from left to right, top to bottom. It does not do anything to maximize the available space. It also assumes that you have a max width and height for the finished image, since it's not realistic to support an arbitrary size.
// where we store the finished mosaic
var mosaic = new Bitmap(maxWidth, maxHeight);
// track the location where we are drawing each image
var imageCorner = new Point(0,0);
// track the height of the current row
var currentRowHeight = 0;
// track the width and height of the mosaic as it grows.
var mosaicWidth = 0;
var mosaicHeight = 0;
using (var g = Graphics.FromImage(bitmap))
{
var borderPen = new Pen(Brushes.Black) { Width = 2 };
var labelFont = new Font("Arial", 10);
var labelBrush = new SolidBrush(Color.Black);
foreach (var image in imageList)
{
if (imageCorner.X + image.Width > maxWidth)
{
// if adding the image to the current row would make it too wide,
// move to the next row by resetting X to zero and adding the
// height of the tallest image to Y
imageCorner.X = 0;
imageCorner.Y += currentRowHeight;
// since this is a new row, it's current height is zero
currentRowHeight = 0;
}
// if adding this image would put us past the
// height of the image, then we're out of room.
if (imageCorner.Y + image.Height > maxHeight)
{
// this skips images if there's no room for them in
// the mosaic, you may want to do something different
Trace.WriteLine($"Image is {image.Height} pixels tall, but only {maxHeight - mosaicHeight} pixels available.");
continue;
}
// draw the image
g.DrawImage(image, imageCorner);
// draw the border
g.DrawRectangle(borderPen,
imageCorner.X, imageCorner.Y,
image.Width, image.Height)
// draw the label
g.DrawText("Image Label", labelBrush, imageCorner.X, imageCorner.Y)
// now that we've drawn the image, we need to shift to the right
imageCorner.X += image.Width;
// row height is the height of the tallest image so far in this row
currentRowHeight = Math.Max(image.Height, currentRowHeight);
// track the total height of the mosaic
mosaicHeight = imageCorner.Y + currentRowHeight;
// mosaic width is just the widest row in the mosaic
mosaicWidth = Math.Max(imageCorner.X, widthOfWidestRow);
}
}
// trim off the parts of the mosaic we didn't fill
mosaic = mosaic.Clone(new Rectangle(0, 0, mosaicWidth, mosaicHeight);
mosaic.Save("merged.bmp");
If you wanted to minimize wasted space, you could sort your list of images in different ways, or calculate ahead of time what a good width and height for the mosaic would be.

svg to jpg (or png) with white background color

I'm running the following c# code to convert a SVG file to jpg, however, the files created return with a black background. Is there a good way to create a white background?
Or another solution to create perfect images?
var svgDocument = Svg.SvgDocument.Open(file);
var width = svgDocument.Width;
var height = svgDocument.Height;
float factor = outputWidth / width;
int newHeight = (int) Math.Floor(factor * height);
svgDocument.ShapeRendering = SvgShapeRendering.Auto;
Bitmap bmp = svgDocument.Draw(outputWidth, newHeight);
bmp.Save(#"output.jpg", ImageFormat.Jpeg);

Image resizing in C# with alignment of a logo and text in the image to the top

I have an image 3519 X 2495 with some logo and text next to it. When the image is opened, i see the logo and the text next to it in the center. I would like to resize the image to 768 X 1004 and want both the logo and the text next to it to appear on the top. When I resize the image I get the logo and text next to it in the center.
Is there a good way to achieve this in c#.
I tried the below code
Image image = Image.FromFile(#"D:\SSH\Automation\ImageResize\Diageo.jpg");
Bitmap bitmap = new Bitmap(768, 1004);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.DrawImage(image, 0, 0, 768, 1004);
bitmap.Save(#"D:\SSH\Automation\ImageResize\Diageo.png");
graphics.Dispose();
To resize an image and keep its initial aspect ratio use the following code:
Note that I use usings from the IDisposable interface instead of calling Dispose myself as this is considered best practice and is safer.
int maxWidth = 768;
int maxHeight = 1004;
using (Bitmap bitmap = new Bitmap(filePath))
{
int width = (int)(bitmap.Width * (maxHeight / (float)bitmap.Height));
int height = maxHeight;
if (bitmap.Height * (maxWidth / (float)bitmap.Width) <= maxHeight)
{
width = maxWidth;
height = (int)(bitmap.Height * (maxWidth / (float)bitmap.Width));
}
using (Bitmap resizedBitmap = new Bitmap(width, height))
{
resizedBitmap.SetResolution(bitmap.HorizontalResolution, bitmap.VerticalResolution);
using (Graphics g = Graphics.FromImage(resizedBitmap))
{
g.DrawImage(bitmap, 0, 0, resizedBitmap.Width, resizedBitmap.Height);
}
//Use resizedBitmap here
}
}

Getting BitmapImage PixelHeight Property causes Initialization Issues

I have a BitmapImage that I want to get the PixelHeight and PixelWidth properties so I can determine whether it has a landscape or portrait layout. After I determine its layout, I need to set either the height or width of the image to get it to fit into my image viewer window without distorting the height:width ratio. However, it appears I have to call BeginInit() in order to do anything with my image. I have to call EndInit() to get the PixelHeight or PixelWidth properties and I cannot call BeginInit() more than once on the same BitmapImage object. So how can I possibly set my image, get the height and width, determine its orientation and then resize the image?
Here the chunk of code that I have been working with:
image.BeginInit();
Uri imagePath = new Uri(path + "\\" + die.Die.ImageID + "_" + blueTape + "_BF.BMP");
image.UriSource = imagePath;
//image.EndInit();
imageHeight = image.PixelHeight;
imageWidth = image.PixelWidth;
//image.BeginInit();
// If the image is taller than it is wide, limit the height of the image
// i.e. DML87s and all non-rotated AOI devices
if (imageHeight > imageWidth)
{
image.DecodePixelHeight = 357;
}
else
{
image.DecodePixelWidth = 475;
}
image.EndInit();
When I run this, I get this run-time exception:
InvalidOperationException:
BitmapImage initialization is not complete. Call the EndInit method to
complete the initialization.
Does anybody know how to deal with this issue?
As far as I know, what you want to do is not possible without decoding the bitmap twice.
I guess it would be a lot simpler to just decode the bitmap to its native size and then set the size of the containing Image control as needed. The bitmap is scaled appropriately, as Stretch is set to Uniform (since both width and height of the Image control are set, Stretch could as well be set to Fill or UniformToFill).
var bitmap = new BitmapImage(new Uri(...));
if (bitmap.Width > bitmap.Height)
{
image.Width = 475;
image.Height = image.Width * bitmap.Height / bitmap.Width;
}
else
{
image.Height = 475;
image.Width = image.Height * bitmap.Width / bitmap.Height;
}
image.Stretch = Stretch.Uniform;
image.Source = bitmap;

Create thumbnail image

I want to display thumbnail image in a gridview from file location. How to generate that of .jpeg file?
I am using C# language with asp.net.
You have to use GetThumbnailImage method in the Image class:
https://msdn.microsoft.com/en-us/library/8t23aykb%28v=vs.110%29.aspx
Here's a rough example that takes an image file and makes a thumbnail image from it, then saves it back to disk.
Image image = Image.FromFile(fileName);
Image thumb = image.GetThumbnailImage(120, 120, ()=>false, IntPtr.Zero);
thumb.Save(Path.ChangeExtension(fileName, "thumb"));
It is in the System.Drawing namespace (in System.Drawing.dll).
Behavior:
If the Image contains an embedded thumbnail image, this method
retrieves the embedded thumbnail and scales it to the requested size.
If the Image does not contain an embedded thumbnail image, this method
creates a thumbnail image by scaling the main image.
Important: the remarks section of the Microsoft link above warns of certain potential problems:
The GetThumbnailImage method works well when the requested thumbnail
image has a size of about 120 x 120 pixels. If you request a large
thumbnail image (for example, 300 x 300) from an Image that has an
embedded thumbnail, there could be a noticeable loss of quality in the
thumbnail image.
It might be better to scale the main image (instead
of scaling the embedded thumbnail) by calling the DrawImage method.
The following code will write an image in proportional to the response, you can modify the code for your purpose:
public void WriteImage(string path, int width, int height)
{
Bitmap srcBmp = new Bitmap(path);
float ratio = srcBmp.Width / srcBmp.Height;
SizeF newSize = new SizeF(width, height * ratio);
Bitmap target = new Bitmap((int) newSize.Width,(int) newSize.Height);
HttpContext.Response.Clear();
HttpContext.Response.ContentType = "image/jpeg";
using (Graphics graphics = Graphics.FromImage(target))
{
graphics.CompositingQuality = CompositingQuality.HighSpeed;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.DrawImage(srcBmp, 0, 0, newSize.Width, newSize.Height);
using (MemoryStream memoryStream = new MemoryStream())
{
target.Save(memoryStream, ImageFormat.Jpeg);
memoryStream.WriteTo(HttpContext.Response.OutputStream);
}
}
Response.End();
}
Here is a complete example of how to create a smaller image (thumbnail). This snippet resizes the Image, rotates it when needed (if a phone was held vertically) and pads the image if you want to create square thumbs. This snippet creates a JPEG, but it can easily be modified for other file types. Even if the image would be smaller than the max allowed size the image will still be compressed and it's resolution altered to create images of the same dpi and compression level.
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
//set the resolution, 72 is usually good enough for displaying images on monitors
float imageResolution = 72;
//set the compression level. higher compression = better quality = bigger images
long compressionLevel = 80L;
public Image resizeImage(Image image, int maxWidth, int maxHeight, bool padImage)
{
int newWidth;
int newHeight;
//first we check if the image needs rotating (eg phone held vertical when taking a picture for example)
foreach (var prop in image.PropertyItems)
{
if (prop.Id == 0x0112)
{
int orientationValue = image.GetPropertyItem(prop.Id).Value[0];
RotateFlipType rotateFlipType = getRotateFlipType(orientationValue);
image.RotateFlip(rotateFlipType);
break;
}
}
//apply the padding to make a square image
if (padImage == true)
{
image = applyPaddingToImage(image, Color.Red);
}
//check if the with or height of the image exceeds the maximum specified, if so calculate the new dimensions
if (image.Width > maxWidth || image.Height > maxHeight)
{
double ratioX = (double)maxWidth / image.Width;
double ratioY = (double)maxHeight / image.Height;
double ratio = Math.Min(ratioX, ratioY);
newWidth = (int)(image.Width * ratio);
newHeight = (int)(image.Height * ratio);
}
else
{
newWidth = image.Width;
newHeight = image.Height;
}
//start the resize with a new image
Bitmap newImage = new Bitmap(newWidth, newHeight);
//set the new resolution
newImage.SetResolution(imageResolution, imageResolution);
//start the resizing
using (var graphics = Graphics.FromImage(newImage))
{
//set some encoding specs
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.DrawImage(image, 0, 0, newWidth, newHeight);
}
//save the image to a memorystream to apply the compression level
using (MemoryStream ms = new MemoryStream())
{
EncoderParameters encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, compressionLevel);
newImage.Save(ms, getEncoderInfo("image/jpeg"), encoderParameters);
//save the image as byte array here if you want the return type to be a Byte Array instead of Image
//byte[] imageAsByteArray = ms.ToArray();
}
//return the image
return newImage;
}
//=== image padding
public Image applyPaddingToImage(Image image, Color backColor)
{
//get the maximum size of the image dimensions
int maxSize = Math.Max(image.Height, image.Width);
Size squareSize = new Size(maxSize, maxSize);
//create a new square image
Bitmap squareImage = new Bitmap(squareSize.Width, squareSize.Height);
using (Graphics graphics = Graphics.FromImage(squareImage))
{
//fill the new square with a color
graphics.FillRectangle(new SolidBrush(backColor), 0, 0, squareSize.Width, squareSize.Height);
//put the original image on top of the new square
graphics.DrawImage(image, (squareSize.Width / 2) - (image.Width / 2), (squareSize.Height / 2) - (image.Height / 2), image.Width, image.Height);
}
//return the image
return squareImage;
}
//=== get encoder info
private ImageCodecInfo getEncoderInfo(string mimeType)
{
ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
for (int j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType.ToLower() == mimeType.ToLower())
{
return encoders[j];
}
}
return null;
}
//=== determine image rotation
private RotateFlipType getRotateFlipType(int rotateValue)
{
RotateFlipType flipType = RotateFlipType.RotateNoneFlipNone;
switch (rotateValue)
{
case 1:
flipType = RotateFlipType.RotateNoneFlipNone;
break;
case 2:
flipType = RotateFlipType.RotateNoneFlipX;
break;
case 3:
flipType = RotateFlipType.Rotate180FlipNone;
break;
case 4:
flipType = RotateFlipType.Rotate180FlipX;
break;
case 5:
flipType = RotateFlipType.Rotate90FlipX;
break;
case 6:
flipType = RotateFlipType.Rotate90FlipNone;
break;
case 7:
flipType = RotateFlipType.Rotate270FlipX;
break;
case 8:
flipType = RotateFlipType.Rotate270FlipNone;
break;
default:
flipType = RotateFlipType.RotateNoneFlipNone;
break;
}
return flipType;
}
//== convert image to base64
public string convertImageToBase64(Image image)
{
using (MemoryStream ms = new MemoryStream())
{
//convert the image to byte array
image.Save(ms, ImageFormat.Jpeg);
byte[] bin = ms.ToArray();
//convert byte array to base64 string
return Convert.ToBase64String(bin);
}
}
For the asp.net users a little example of how to upload a file, resize it and display the result on the page.
//== the button click method
protected void Button1_Click(object sender, EventArgs e)
{
//check if there is an actual file being uploaded
if (FileUpload1.HasFile == false)
{
return;
}
using (Bitmap bitmap = new Bitmap(FileUpload1.PostedFile.InputStream))
{
try
{
//start the resize
Image image = resizeImage(bitmap, 256, 256, true);
//to visualize the result, display as base64 image
Label1.Text = "<img src=\"data:image/jpg;base64," + convertImageToBase64(image) + "\">";
//save your image to file sytem, database etc here
}
catch (Exception ex)
{
Label1.Text = "Oops! There was an error when resizing the Image.<br>Error: " + ex.Message;
}
}
}
Here is a version based on the accepted answer. It fixes two problems...
Improper disposing of the images.
Maintaining the aspect ratio of the image.
I found this tool to be fast and effective for both JPG and PNG files.
private static FileInfo CreateThumbnailImage(string imageFileName, string thumbnailFileName)
{
const int thumbnailSize = 150;
using (var image = Image.FromFile(imageFileName))
{
var imageHeight = image.Height;
var imageWidth = image.Width;
if (imageHeight > imageWidth)
{
imageWidth = (int) (((float) imageWidth / (float) imageHeight) * thumbnailSize);
imageHeight = thumbnailSize;
}
else
{
imageHeight = (int) (((float) imageHeight / (float) imageWidth) * thumbnailSize);
imageWidth = thumbnailSize;
}
using (var thumb = image.GetThumbnailImage(imageWidth, imageHeight, () => false, IntPtr.Zero))
//Save off the new thumbnail
thumb.Save(thumbnailFileName);
}
return new FileInfo(thumbnailFileName);
}
Here is an example to convert high res image into thumbnail size-
protected void Button1_Click(object sender, EventArgs e)
{
//---------- Getting the Image File
System.Drawing.Image img = System.Drawing.Image.FromFile(Server.MapPath("~/profile/Avatar.jpg"));
//---------- Getting Size of Original Image
double imgHeight = img.Size.Height;
double imgWidth = img.Size.Width;
//---------- Getting Decreased Size
double x = imgWidth / 200;
int newWidth = Convert.ToInt32(imgWidth / x);
int newHeight = Convert.ToInt32(imgHeight / x);
//---------- Creating Small Image
System.Drawing.Image.GetThumbnailImageAbort myCallback = new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback);
System.Drawing.Image myThumbnail = img.GetThumbnailImage(newWidth, newHeight, myCallback, IntPtr.Zero);
//---------- Saving Image
myThumbnail.Save(Server.MapPath("~/profile/NewImage.jpg"));
}
public bool ThumbnailCallback()
{
return false;
}
Source-
http://iknowledgeboy.blogspot.in/2014/03/c-creating-thumbnail-of-large-image-by.html
This is the code I'm using. Also works for .NET Core > 2.0 using System.Drawing.Common NuGet.
https://www.nuget.org/packages/System.Drawing.Common/
using System;
using System.Drawing;
class Program
{
static void Main()
{
const string input = "C:\\background1.png";
const string output = "C:\\thumbnail.png";
// Load image.
Image image = Image.FromFile(input);
// Compute thumbnail size.
Size thumbnailSize = GetThumbnailSize(image);
// Get thumbnail.
Image thumbnail = image.GetThumbnailImage(thumbnailSize.Width,
thumbnailSize.Height, null, IntPtr.Zero);
// Save thumbnail.
thumbnail.Save(output);
}
static Size GetThumbnailSize(Image original)
{
// Maximum size of any dimension.
const int maxPixels = 40;
// Width and height.
int originalWidth = original.Width;
int originalHeight = original.Height;
// Return original size if image is smaller than maxPixels
if (originalWidth <= maxPixels || originalHeight <= maxPixels)
{
return new Size(originalWidth, originalHeight);
}
// Compute best factor to scale entire image based on larger dimension.
double factor;
if (originalWidth > originalHeight)
{
factor = (double)maxPixels / originalWidth;
}
else
{
factor = (double)maxPixels / originalHeight;
}
// Return thumbnail size.
return new Size((int)(originalWidth * factor), (int)(originalHeight * factor));
}
}
Source:
https://www.dotnetperls.com/getthumbnailimage

Categories

Resources