Compress image in tiff viewer - c#

I have created Tiff file viewer for my web application and it's working great. But the problem is there are some big images (4000 X 2000 - 5+ MB) which I need to display in it's original size.
Is it possible to compress the size of the image and then send the stream to Response Stream on the ashx page?
Note that all my images are scanned black and white images. However for precaution I would like to check whether compression algorithm specific to black & white image be applied to the image or not.
Look the below code of TiffHelper class
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Drawing.Drawing2D;
public class TiffHelper
{
public static int GetPageCount(String filePath)
{
int pageCount = 0;
try
{
using (Image img = Image.FromStream(
new FileStream(filePath,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite)
))
{
pageCount = img.GetFrameCount(FrameDimension.Page);
}
}
catch (Exception ex)
{
CException.SuppressException(ex);
pageCount = -1;
}
return pageCount;
}
public static Image GetTiffImage(String sourceFile, int pageNumber, int thumbnailSize, int degree)
{
MemoryStream ms = null;
Image sourceImage = null;
Image returnImage = null;
try
{
sourceImage = Image.FromStream(
new FileStream(sourceFile,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite)
);
ms = new MemoryStream();
FrameDimension FrDim = new FrameDimension(sourceImage.FrameDimensionsList[0]);
sourceImage.SelectActiveFrame(FrDim, pageNumber - 1);
sourceImage.Save(ms, ImageFormat.Tiff);
/*
EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, 90);
ImageCodecInfo tiffCodec = GetEncoderInfo("image/tiff");
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
sourceImage.Save(ms, tiffCodec, encoderParams);
*/
/*
EncoderParameters iparams = new EncoderParameters(2);
iparams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.SaveFlag, (long)EncoderValue.MultiFrame);
iparams.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)EncoderValue.CompressionCCITT4);
*
sourceImage.Save(ms, GetEncoderInfo("image/tiff"), iparams);
*/
int height = sourceImage.Height;
int width = sourceImage.Width;
if (thumbnailSize > 0)
{
if (sourceImage.Width < sourceImage.Height)
{
width = thumbnailSize;
height = sourceImage.Height * thumbnailSize / sourceImage.Width;
}
else
{
width = sourceImage.Width * thumbnailSize / sourceImage.Height;
height = thumbnailSize;
}
}
//returnImage = ResizeImage(Image.FromStream(ms), new Size(width, height));
returnImage = Image.FromStream(ms).GetThumbnailImage(width, height, null, IntPtr.Zero);
returnImage.RotateFlip(GetFlipType(degree));
}
catch (Exception ex)
{
CException.SuppressException(ex);
}
finally
{
ms.Dispose();
sourceImage.Dispose();
}
return returnImage;
}
private static Image ResizeImage(Image imgToResize, Size size)
{
int sourceWidth = imgToResize.Width;
int sourceHeight = imgToResize.Height;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)size.Width / (float)sourceWidth);
nPercentH = ((float)size.Height / (float)sourceHeight);
if (nPercentH < nPercentW)
nPercent = nPercentH;
else
nPercent = nPercentW;
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap b = new Bitmap(destWidth, destHeight);
Graphics g = Graphics.FromImage((Image)b);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighSpeed;
g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
g.CompositingQuality = CompositingQuality.HighQuality;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return (Image)b;
}
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
for (int i = 0; i < codecs.Length; i++)
{
if (codecs[i].MimeType == mimeType)
{
return codecs[i];
}
}
return null;
}
private static RotateFlipType GetFlipType(int degree)
{
switch (degree)
{
case 90:
return RotateFlipType.Rotate90FlipNone;
case 180:
return RotateFlipType.Rotate180FlipNone;
case 270:
return RotateFlipType.Rotate270FlipNone;
case -90:
return RotateFlipType.Rotate90FlipXY;
case -180:
return RotateFlipType.Rotate180FlipNone;
case -270:
return RotateFlipType.Rotate270FlipXY;
default:
return RotateFlipType.RotateNoneFlipNone;
}
}
}

Related

How to reduce image file size while uploading multiple images using ASP.NET C#

I want to upload multiple images to the server, while uploading need to compress the file size
foreach (HttpPostedFile thefile in FileUpload1.PostedFiles)
{
string sfile = thefile.FileName;
string spath = Server.MapPath("~/Uploads");
string sfullpath = Path.Combine(spath, sfile);
thefile.SaveAs(sfullpath);
}
wanted to include the file compressing code
You can use C# bitmap & ImageCodecInfo inbuilt class to compress the image.
public static void Compressimage(Stream sourcePath, string targetPath, String filename)
{
try
{
using (var image = Image.FromStream(sourcePath))
{
float maxHeight = 900.0f;
float maxWidth = 900.0f;
int newWidth;
int newHeight;
string extension;
Bitmap originalBMP = new Bitmap(sourcePath);
int originalWidth = originalBMP.Width;
int originalHeight = originalBMP.Height;
if (originalWidth > maxWidth || originalHeight > maxHeight)
{
// To preserve the aspect ratio
float ratioX = (float)maxWidth / (float)originalWidth;
float ratioY = (float)maxHeight / (float)originalHeight;
float ratio = Math.Min(ratioX, ratioY);
newWidth = (int)(originalWidth * ratio);
newHeight = (int)(originalHeight * ratio);
}
else
{
newWidth = (int)originalWidth;
newHeight = (int)originalHeight;
}
Bitmap bitMAP1 = new Bitmap(originalBMP, newWidth, newHeight);
Graphics imgGraph = Graphics.FromImage(bitMAP1);
extension = Path.GetExtension(targetPath);
if (extension == ".png" || extension == ".gif")
{
imgGraph.SmoothingMode = SmoothingMode.AntiAlias;
imgGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
imgGraph.DrawImage(originalBMP, 0, 0, newWidth, newHeight);
bitMAP1.Save(targetPath, image.RawFormat);
bitMAP1.Dispose();
imgGraph.Dispose();
originalBMP.Dispose();
}
else if (extension == ".jpg")
{
imgGraph.SmoothingMode = SmoothingMode.AntiAlias;
imgGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
imgGraph.DrawImage(originalBMP, 0, 0, newWidth, newHeight);
ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);
Encoder myEncoder = Encoder.Quality;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 50L);
myEncoderParameters.Param[0] = myEncoderParameter;
bitMAP1.Save(targetPath, jpgEncoder, myEncoderParameters);
bitMAP1.Dispose();
imgGraph.Dispose();
originalBMP.Dispose();
}
}
}
catch (Exception)
{
throw;
}
}
public static ImageCodecInfo GetEncoder(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
}
}
https://www.c-sharpcorner.com/UploadFile/85ed7a/compress-and-resize-the-image-using-web-api/

GIf image is not animating

I have written the following code to upload different types of images.
public static void CompressImageWithNewDimensions(Stream stream, string targetPath, double fileSizeKB)
{
try
{
using (var image = Image.FromStream(stream))
{
double scaleFactor;
if (fileSizeKB <= 900)
{
scaleFactor = 0.9;
}
else if (fileSizeKB <= 1500)
{
scaleFactor = 0.8;
}
else if (fileSizeKB <= 2000)
{
scaleFactor = 0.7;
}
else
{
scaleFactor = 0.3;
}
var newWidth = (int)(image.Width * scaleFactor);
var newHeight = (int)(image.Height * scaleFactor);
var CompressImage = new Bitmap(newWidth, newHeight);
var CompressImageGraph = Graphics.FromImage(CompressImage);
CompressImageGraph.CompositingQuality = CompositingQuality.HighQuality;
CompressImageGraph.SmoothingMode = SmoothingMode.HighQuality;
CompressImageGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
var imageRectangle = new Rectangle(0, 0, newWidth, newHeight);
CompressImageGraph.DrawImage(image, imageRectangle);
//CompressImage.Save(targetPath, image.RawFormat);
CompressImage.Save(targetPath, System.Drawing.Imaging.ImageFormat.Gif);
}
}
catch (Exception)
{
}
}
Now I have successfully uploaded GIF file in my folder, but in the folder when I am opening the image, it is not animating.

Crop image without distorting pixels in c#

The image gets distorted while cropping it into various sizes. How do I do this without affecting the image quality? My current result is a distorted blurry image. Please help.
Here is my code:
var common = new Common();
string filesPath = HttpContext.Current.Server.MapPath(Const.directoryPath);
string imageUrl1 = UploadImageToAzure(1123, "\\Configurator\\_trunk\\Content\\TempImages\\eddaec5aa33e4b1593b304674a842874.jpeg, "eddaec5aa33e4b1593b304674a842874_260x190.jpeg", cloudstorage, containerName);
string cropimage260x190 = CropImagewithName(inputStream/*System.Io.Stream*/, 260, 190, cropedImageName);
public string CropImagewithName(Stream stream, int width, int height, string name)
{
int bmpW = 0;
int bmpH = 0;
string filePath = string.Empty;
string imgName = string.Empty;
try
{
{
bmpW = width;
bmpH = height;
int newWidth = bmpW;
int newHeight = bmpH;
imgName = name;
imgName = imgName.Replace("-", "");
filePath = Const.directoryPath + imgName;
this.upBmp = new Bitmap(stream);
this.newBmp = new Bitmap(newWidth, newHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
this.newBmp.SetResolution(300, 300);
int upWidth = this.upBmp.Width;
int upHeight = this.upBmp.Height;
int newX = 0;
int newY = 0;
decimal reDuce;
if (upWidth > upHeight)
{
reDuce = Convert.ToDecimal(newWidth) / Convert.ToDecimal(upWidth);
newHeight = Convert.ToInt32((Convert.ToDecimal(upHeight) * reDuce));
newY = (bmpH - newHeight) / 2;
newX = 0;
}
else if (upWidth < upHeight)
{
reDuce = Convert.ToDecimal(newHeight) / Convert.ToDecimal(upHeight);
newWidth = Convert.ToInt32((Convert.ToDecimal(upWidth) * reDuce));
newX = (bmpW - newWidth) / 2;
newY = 0;
}
else if (upWidth == upHeight) //
{
reDuce = Convert.ToDecimal(newHeight) / Convert.ToDecimal(upHeight);
newWidth = Convert.ToInt32((Convert.ToDecimal(upWidth) * reDuce));
newX = (bmpW - newWidth) / 2;
newY = (bmpH - newHeight) / 2;
}
newGraphic = Graphics.FromImage(newBmp);
this.newGraphic.Clear(Color.White);
this.newGraphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
this.newGraphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
newGraphic.DrawImage(upBmp, newX, newY, newWidth, newHeight);
newBmp.Save(HttpContext.Current.Server.MapPath(filePath), System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
catch (Exception)
{
}
finally
{
this.upBmp.Dispose();
this.newBmp.Dispose();
this.newGraphic.Dispose();
}
return imgName;
}
You are experiencing JPEG compression artifacts, not geometrical distortion. You need to set JPEG compression quality before saving your image. Here is how you can save your image with highest quality (look for 100L in the code below):
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == ImageFormat.Jpeg.Guid)
{
var myEncoder = System.Drawing.Imaging.Encoder.Quality;
var myEncoderParameter = new EncoderParameter(myEncoder, 100L);
var myEncoderParameters = new EncoderParameters(1) { Param = { [0] = myEncoderParameter } };
newBmp.Save(#"C:\qqq\111.jpeg", codec, myEncoderParameters);
break;
}
}
Here is the MSDN article for it: https://msdn.microsoft.com/en-us/library/bb882583(v=vs.110).aspx

Overlay watermark PNG on JPG file centered

I have a method that takes an image and resizes it and saves it preserving the exif information. What I want to do now is overlay a transparent PNG image on top of the image as a watermark. The size of the png will always be larger than any of the images I want to place it on. I would like to center it on top of the image preserving the watermark's aspect ratio. Here is the code as I have it so far:
private static void ResizeImage(Image theImage, int newSize, string savePath, IEnumerable<PropertyItem> propertyItems)
{
int width;
int height;
CalculateNewRatio(theImage.Width, theImage.Height, newSize, out width, out height);
using (var b = new Bitmap(width, height))
{
using (var g = Graphics.FromImage(b))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
using(var a = Image.FromFile("Watermark.png"))
{
g.DrawImage(); //What to do here?
}
g.DrawImage(theImage, new Rectangle(0, 0, width, height));
var qualityParam = new EncoderParameter(Encoder.Quality, 80L);
var codecs = ImageCodecInfo.GetImageEncoders();
var jpegCodec = codecs.FirstOrDefault(t => t.MimeType == "image/jpeg");
var encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
foreach(var item in propertyItems)
{
b.SetPropertyItem(item);
}
b.Save(savePath, jpegCodec, encoderParams);
}
}
}
I figured out the solution, the code is below. May not be the optimal code but it is fast and does what I need it to do which is take all JPG images in a directory and re-size them to full and thumb images for a photo gallery while overlaying a watermark on the image.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace ImageResize
{
internal class Program
{
private static readonly string directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
private static void Main()
{
var strFiles = Directory.GetFiles(directory, "*.jpg");
//Using parallel processing for performance
Parallel.ForEach(strFiles, strFile =>
{
using (var image = Image.FromFile(strFile, true))
{
var exif = image.PropertyItems;
var b = directory + "\\" + Path.GetFileNameWithoutExtension(strFile);
ResizeImage(image, 800, b + "_FULL.jpg", exif);
ResizeImage(image, 200, b + "_THUMB.jpg", exif);
}
File.Delete(strFile);
});
}
private static void ResizeImage(Image theImage, int newSize, string savePath, IEnumerable<PropertyItem> propertyItems)
{
try
{
int width;
int height;
CalculateNewRatio(theImage.Width, theImage.Height, newSize, out width, out height);
using (var b = new Bitmap(width, height))
{
using (var g = Graphics.FromImage(b))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage(theImage, new Rectangle(0, 0, width, height));
//Using FileStream to avoid lock issues because of the parallel processing
using (var stream = new FileStream(directory + "\\Watermark.png", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (var overLay = Image.FromStream(stream))
{
stream.Close();
int newWidth;
int newHeight;
CalculateNewRatio(overLay.Width, overLay.Height, height > width ? width : newSize, out newWidth, out newHeight);
var x = (b.Width - newWidth) / 2;
var y = (b.Height - newHeight) / 2;
g.DrawImage(overLay, new Rectangle(x, y, newWidth, newHeight));
}
}
var qualityParam = new EncoderParameter(Encoder.Quality, 80L);
var codecs = ImageCodecInfo.GetImageEncoders();
var jpegCodec = codecs.FirstOrDefault(t => t.MimeType == "image/jpeg");
var encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
foreach (var item in propertyItems)
{
b.SetPropertyItem(item);
}
b.Save(savePath, jpegCodec, encoderParams);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private static void CalculateNewRatio(int width, int height, int desiredSize, out int newWidth, out int newHeight)
{
if ((width >= height && width > desiredSize) || (width <= height && height > desiredSize))
{
if (width > height)
{
newWidth = desiredSize;
newHeight = height*newWidth/width;
}
else if (width < height)
{
newHeight = desiredSize;
newWidth = width*newHeight/height;
}
else
{
newWidth = desiredSize;
newHeight = desiredSize;
}
}
else
{
newWidth = width;
newHeight = height;
}
}
}
}
To scale an image onto a canvas for the best fit while preserving the aspect ratio, the process is fairly simple:
double widthFactor = b.Width / a.Width;
double heightFactor = b.Height / a.Height;
double scaleFactor = Math.Min(widthFactor, heightFactor);
int newWidth = a.Width * scaleFactor;
int newHeight = a.Width * scaleFactor;
To calculate the position to center the image just requires a little more math:
int left = (b.Width - newWidth) / 2;
int top = (b.Height - newHeight) / 2;
Then use the appropriate form of the Graphics.DrawImage method.

Resize JPEG image to fixed width, while keeping aspect ratio as it is

How would you resize a JPEG image, to a fixed width whilst keeping aspect ratio? In a simple way, whilst preserving quality.
This will scale in the vertical axis only:
public static Image ResizeImageFixedWidth(Image imgToResize, int width)
{
int sourceWidth = imgToResize.Width;
int sourceHeight = imgToResize.Height;
float nPercent = ((float)width / (float)sourceWidth);
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap b = new Bitmap(destWidth, destHeight);
Graphics g = Graphics.FromImage((Image)b);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return (Image)b;
}
If you are reducing the width by 25 percent to a fixed value, you must reduce the height by 25 percent.
If you are increasing the width by 25 percent to a fixed value, you must increasing the height by 25 percent.
It's really straight forward.
Assuming there is a (double width) variable:
Image imgOriginal = Bitmap.FromFile(path);
double height = (imgOriginal.Height * width) / imgOriginal.Width;
Image imgnew = new Bitmap((int)width, (int)height, PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(imgnew);
g.DrawImage(imgOriginal, new Point[]{new Point(0,0), new Point(width, 0), new Point(0, height)}, new Rectangle(0,0,imgOriginal.Width, imgOriginal.Height), GraphicsUnit.Pixel);
In the end you´ll have a new image with widthxheight, then, you´ll need to flush the graphics e save the imgnew.
I think there are plenty of samples of this if you search for them. Here's the one I commonly use...
public static Stream ResizeGdi(Stream stream, System.Drawing.Size size)
{
Image image = Image.FromStream(stream);
int width = image.Width;
int height = image.Height;
int sourceX = 0, sourceY = 0, destX = 0, destY = 0;
float percent = 0, percentWidth = 0, percentHeight = 0;
percentWidth = ((float)size.Width / (float)width);
percentHeight = ((float)size.Height / (float)height);
int destW = 0;
int destH = 0;
if (percentHeight < percentWidth)
{
percent = percentHeight;
}
else
{
percent = percentWidth;
}
destW = (int)(width * percent);
destH = (int)(height * percent);
MemoryStream mStream = new MemoryStream();
if (destW == 0
&& destH == 0)
{
image.Save(mStream, System.Drawing.Imaging.ImageFormat.Jpeg);
return mStream;
}
using (Bitmap bitmap = new Bitmap(destW, destH, System.Drawing.Imaging.PixelFormat.Format48bppRgb))
{
using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmap))
{
//graphics.Clear(Color.Red);
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.DrawImage(image,
new Rectangle(destX, destY, destW, destH),
new Rectangle(sourceX, sourceY, width, height),
GraphicsUnit.Pixel);
}
bitmap.Save(mStream, System.Drawing.Imaging.ImageFormat.Jpeg);
}
mStream.Position = 0;
return mStream as Stream;
}
Example of the calling code...
Stream stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.None);
resizedStream = ImageUtility.ResizeGdi(stream, new System.Drawing.Size(resizeWidth, resizeHeight));
A quick search on code project has found the following article. It allows for resizing of images which accepts a boolean to restrain the new image to keep the originals aspect ratio. I'm unsure of what the quality is like as no screenshots were provided. See the article here

Categories

Resources