Compress image asp.net - asp.net

i am new for asp.net . I having a problem now. I need to compress my image before storing to my database. I googling quite lot time.
But most of the tutorial is guiding me need to resize the width and height before store to the database. so nw is my question is it possible to compress the image without resize the width and height before store to the database. Please guide me solution .
For instance http://compressnow.com/

You may want to use GZIP
byte[] fileBytes = File.ReadAllBytes(FilePath);
byte[] compressedFileBytes = Compress(fileBytes); //compress
byte[] decompressedFileBytes = Decompress(compressedFileBytes); //decompress
byte[] Compress(byte[] b)
{
using (MemoryStream ms = new MemoryStream())
{
using (GZipStream z = new GZipStream(ms, CompressionMode.Compress, true))
z.Write(b, 0, b.Length);
return ms.ToArray();
}
}
byte[] Decompress(byte[] b)
{
using (var ms = new MemoryStream())
{
using (var bs = new MemoryStream(b))
using (var z = new GZipStream(bs, CompressionMode.Decompress))
z.CopyTo(ms);
return ms.ToArray();
}
}

Related

Unable to copy to memorystream from gzipstream

I want to compress a binary file in memory using System.IO.Compression.GZipStream. For this, I am using the following method
public byte[] Encrypt()
{
var payload = GetPayload();
Console.WriteLine("[!] Payload Size: {0} bytes", payload.Length);
using (var compressedStream = new MemoryStream(payload))
using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress))
using (var resultStream = new MemoryStream())
{
zipStream.CopyTo(resultStream);
return resultStream.ToArray();
}
}
But while .CopyTo, I am getting System.NotSupportedException: Stream does not support reading.
You need to "inverse" your logic: create GZipStream over empty MemoryStream and copy your original content into this gzip stream:
using var compressedData = new MemoryStream();
using var gzip = new GZipStream(compressedData);
originalUncompressedStream.CopyTo(gzip); // <- "magic" happens here
gzip.Flush();
// and "rewind" result stream back to beginning (for next reads)
compressedData.Position = 0;

Streaming a blob from Azure storage - Cannot access a closed Stream

I am using asp.net webforms.
I have pdfs in Azure storage that I need to process. I am using PDFJet library in order to do that.
I would like to
stream the pdf without downloading it as I have to process a large number of pdfs.
I am using the following function to stream the pdfs from Azure:
public MemoryStream DownloadToMemoryStream(DTO.BlobUpload b)
{
CloudStorageAccount storageAccount = Conn.SNString(b.OrgID);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(b.Container);
CloudBlockBlob blob = container.GetBlockBlobReference(b.FileName);
var sasToken = blob.GetSharedAccessSignature(new SharedAccessBlobPolicy()
{
Permissions = SharedAccessBlobPermissions.Read,
SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(10),//assuming the blob can be downloaded in 10 miinutes
}, new SharedAccessBlobHeaders()
{
ContentDisposition = "attachment; filename=file-name"
});
using (MemoryStream ms = new MemoryStream())
{
blob.DownloadToStream(ms);
return ms;
}
}
And in the aspx.cs page the following code to read the pdf stream:
BufferedStream pdfScript = new BufferedStream(new FileStream(ScriptPath + Script, FileMode.Open));
SortedDictionary<Int32, PDFobj> objects = pdfFinalScript.Read(pdfScript);
However I get the error message: Cannot access a closed Stream
If I download the pdf to disk, this is the function I use, this work but it is not practical:
blockBlob.DownloadToFile(b.LocalPath + b.FileName, FileMode.Create);
BufferedStream pdfScript = new BufferedStream(new FileStream(ScriptPath + Script, FileMode.Open));
Thank you for your help.
Cannot access a closed Stream
According to error information, it indicates that you need to reset stream position.
Please have a try to reset the stream position before return it.
blob.DownloadToStream(ms);
ms.Position = 0; //add this code
return ms;
Updated:
ms was closed if out of using section. So please have a try to use the following code.
MemoryStream stream = new MemoryStream();
using (MemoryStream ms = new MemoryStream())
{
blob.DownloadToStream(ms);
ms.Position = 0
ms.CopyTo(stream);
stream.Position = 0;
return stream;
}

Get image from URL and upload to Amazon S3

I'd like to load an image directly from a URL but without saving it on the server, I want to upload it directly from memory to Amazon S3 server.
This is my code:
Dim wc As New WebClient
Dim fileStream As IO.Stream = wc.OpenRead("http://www.domain.com/image.jpg")
Dim request As New PutObjectRequest()
request.BucketName = "mybucket"
request.Key = "file.jpg"
request.InputStream = fileStream
client.PutObject(request)
The Amazon API gives me the error "Could not determine content length". The stream fileStream ends up as "System.Net.ConnectStream" which I'm not sure if it's correct.
The exact same code works with files from the HttpPostedFile but I need to use it in this way now.
Any ideas how I can convert the stream to become what Amazon API is expecting (with the length intact)?
I had the same problem when I'm using the GetObjectResponse() method and its propertie ResponseStream to copy a file from a folder to another in same bucket. I noted that the AWS SDK (2.3.45) have some faults like a another method called WriteResponseStreamToFile in GetObjectResponse() that simply doesn't work. These lacks of functions needs some workarounds.
I solved the problem openning the file in array of bytes and putting it in a MemoryStream object.
Try this (C# code)
WebClient wc = new WebClient();
Stream fileStream = wc.OpenRead("http://www.domain.com/image.jpg");
byte[] fileBytes = fileStream.ToArrayBytes();
PutObjectRequest request = new PutObjectRequest();
request.BucketName = "mybucket";
request.Key = "file.jpg";
request.InputStream = new MemoryStream(fileBytes);
client.PutObject(request);
The extesion method
public static byte[] ToArrayBytes(this Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
You can also create a MemoryStream without an array of bytes. But after the first PutObject in S3, the MemoryStream will be discarted. If you need to put others objects, I recommend the first option
WebClient wc = new WebClient();
Stream fileStream = wc.OpenRead("http://www.domain.com/image.jpg");
MemoryStream fileMemoryStream = fileStream.ToMemoryStream();
PutObjectRequest request = new PutObjectRequest();
request.BucketName = "mybucket";
request.Key = "file.jpg";
request.InputStream = fileMemoryStream ;
client.PutObject(request);
The extesion method
public static MemoryStream ToMemoryStream(this Stream input)
{
byte[] buffer = new byte[16 * 1024];
int read;
MemoryStream ms = new MemoryStream();
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms;
}
I had the same problem in a similar scenario.
The reason for the error is that to upload an object the SDK needs to know the whole content length that is going to be uploaded. To be able to obtain stream length it must be seekable, but the stream returned from WebClient is not. To indicate the expected length set Headers.ContentLength in PutObjectRequest. The SDK will use this value if it cannot determine length from the stream object.
To make your code work, obtain content length from the response headers returned by the call made by WebClient. Then set PutObjectRequest.Headers.ContentLength. Of course this relies on the server returned content length value.
Dim wc As New WebClient
Dim fileStream As IO.Stream = wc.OpenRead("http://www.example.com/image.jpg")
Dim contentLength As Long = Long.Parse(client.ResponseHeaders("Content-Length"))
Dim request As New PutObjectRequest()
request.BucketName = "mybucket"
request.Key = "file.jpg"
request.InputStream = fileStream
request.Headers.ContentLength = contentLength
client.PutObject(request)
I came up with a solution that uses UploadPart when the length is not available by any other means, plus this does not load the entire file into memory.
if (args.DocumentContents.CanSeek)
{
PutObjectRequest r = new PutObjectRequest();
r.InputStream = args.DocumentContents;
r.BucketName = s3Id.BucketName;
r.Key = s3Id.ObjectKey;
foreach (var item in args.CustomData)
{
r.Metadata[item.Key] = item.Value;
}
await S3Client.PutObjectAsync(r);
}
else
{
// if stream does not allow seeking, S3 client will throw error:
// Amazon.S3.AmazonS3Exception : Could not determine content length
// as a work around, if cannot use length property, will chunk
// file into sections and use UploadPart, so do not have to load
// entire file into memory as a single MemoryStream.
var r = new InitiateMultipartUploadRequest();
r.BucketName = s3Id.BucketName;
r.Key = s3Id.ObjectKey;
foreach (var item in args.CustomData)
{
r.Metadata[item.Key] = item.Value;
}
var multipartResponse = await S3Client.InitiateMultipartUploadAsync(r);
try
{
var completeRequest = new CompleteMultipartUploadRequest
{
UploadId = multipartResponse.UploadId,
BucketName = s3Id.BucketName,
Key = s3Id.ObjectKey,
};
// just using this size, because it is the max for Azure File Share, but it could be any size
// for S3, even a configured value
const int blockSize = 4194304;
// BinaryReader gives us access to ReadBytes
using (var reader = new BinaryReader(args.DocumentContents))
{
var partCounter = 1;
while (true)
{
byte[] buffer = reader.ReadBytes(blockSize);
if (buffer.Length == 0)
break;
using (MemoryStream uploadChunk = new MemoryStream(buffer))
{
uploadChunk.Position = 0;
var uploadRequest = new UploadPartRequest
{
BucketName = s3Id.BucketName,
Key = s3Id.ObjectKey,
UploadId = multipartResponse.UploadId,
PartNumber = partCounter,
InputStream = uploadChunk,
};
// could call UploadPart on multiple threads, instead of using await, but that would
// cause more data to be loaded into memory, which might be too much
var part2Task = await S3Client.UploadPartAsync(uploadRequest);
completeRequest.AddPartETags(part2Task);
}
partCounter++;
}
var completeResponse = await S3Client.CompleteMultipartUploadAsync(completeRequest);
}
}
catch
{
await S3Client.AbortMultipartUploadAsync(s3Id.BucketName, s3Id.ObjectKey
, multipartResponse.UploadId);
throw;
}
}

Strange wikipedia mojibake (faulty coding)

This is the first Wikipedia page that appears a problem to me. When I use HttpWebResponse.GetResponseStream() to open this page https://en.wikipedia.org/wiki/London, it's full of mojibake. But my browser can encode it without problems.
I have used three methods to download the text file. And all of them get different files.
The first method downloaded a file of 274,851 bytes
string TargetUri = "https://en.wikipedia.org/wiki/London";
HttpWebRequest queryPage = (HttpWebRequest)WebRequest.Create(TargetUri);
queryPage.Credentials = CredentialCache.DefaultCredentials;
using (HttpWebResponse response = (HttpWebResponse)queryPage.GetResponse())
{
using (Stream PageRawCode = response.GetResponseStream())
{
using (MemoryStream PageRawCodeDuplicate = new MemoryStream())
{
byte[] buffer = new byte[1024];
int ByteCount;
do
{
ByteCount = PageRawCode.Read(buffer, 0, buffer.Length);
PageRawCodeDuplicate.Write(buffer, 0, ByteCount);
} while (ByteCount > 0);
PageRawCodeDuplicate.Seek(0, SeekOrigin.Begin);
using (StreamReader CodeInUTF8 = new StreamReader(PageRawCodeDuplicate))
{
string PageText = CodeInUTF8.ReadToEnd();
using (StreamWriter sw = new StreamWriter(#"E:\My Documents\Desktop\london1.html"))
{
sw.Write(PageText);
}
}
}
}
}
The second method is
WebClient myWebClient = new WebClient();
myWebClient.DownloadFile("https://en.wikipedia.org/wiki/London", #"E:\My Documents\Desktop\london2.html");
This method only downloaded a file of 152.297 bytes
The third method is to open the https://en.wikipedia.org/wiki/London, and save the source code file. This method will get a file of 1,746,420 bytes
I don't understand why there is a such a difference using different method get a text file.
I have used ASCII, BigEndianUnicode, Unicode, UTF32, UTF7, UTF8 to read the first 2 files. None of them shows the code correctly.
then I read the hex code of the files. The first 32 characters of london1.html is
1FEFBFBD0800000000000003EFBFBDEF
The first 32 characters of london2.html is
1F8B0800000000000003ECFD4B8F1C49
Obviously they are not <!DOCTYPE html>
What are these two files? I don't even know how to inspect them.
There is a simple issue in your code. You forgot to flush the memorystream. I've also added a second solution that doesn't copy the Stream in memory first...
If I run this slightly adapted code, I get a complete html file:
using (HttpWebResponse response = (HttpWebResponse)queryPage.GetResponse())
{
using (Stream PageRawCode = response.GetResponseStream())
{
using (MemoryStream PageRawCodeDuplicate = new MemoryStream())
{
byte[] buffer = new byte[1024];
int ByteCount;
do
{
ByteCount = PageRawCode.Read(buffer, 0, buffer.Length);
PageRawCodeDuplicate.Write(buffer, 0, ByteCount);
} while (ByteCount > 0);
// FLUSH!
PageRawCodeDuplicate.Flush();
PageRawCodeDuplicate.Seek(0, SeekOrigin.Begin);
// Pick an encoding here
using (StreamReader CodeInUTF8 = new StreamReader(
PageRawCodeDuplicate, Encoding.UTF8))
{
string PageText = CodeInUTF8.ReadToEnd();
using (StreamWriter sw = new StreamWriter(#"london1.html"))
{
sw.Write(PageText);
}
}
}
}
}
Direct copy of the stream
using (HttpWebResponse response = (HttpWebResponse)queryPage.GetResponse())
{
using (Stream PageRawCode = response.GetResponseStream())
{
using (StreamReader CodeInUTF8 = new StreamReader(
PageRawCode, Encoding.UTF8))
{
using (StreamWriter sw = new StreamWriter(#"london1.html"))
{
while (!CodeInUTF8.EndOfStream)
{
sw.WriteLine(CodeInUTF8.ReadLine());
}
}
}
}
}
Finally mystery SOLVED! The text stream is a GZipStream. Using GZipStream decompress can read the code.
http://msdn.microsoft.com/en-us/library/system.io.compression.gzipstream.aspx
It's hard to imagine how much the browser does behind

Saving/Loading Images from/to stream instead of a disk

I have the following code which takes an improperly saved Image from the database converts it to a Jpeg and returns the Image in a byte array;
public Byte[] GetImageFromDB(int id)
{
var imageData = _repository.GetImage(id);
var newImageData = ConvertCorruptedImage(imageData, id);
return newImageData;
}
private byte[] ConvertCorruptedImage(byte[] imageData, int id)
{
// Save DB Image as a file.
MemoryStream img = new MemoryStream(imageData);
var saveDBImage = Image.FromStream(img);
string originalFileName = #"c:\original_" + id.ToString() + ".jpg";
string newFileName = #"C:\new" + id.ToString() + ".jpg";
// Delete if already Exists
DeleteImageFile(originalFileName);
saveDBImage.Save(originalFileName);
// Read Saved DB Image From Saved File & Save as jpeg
Bitmap bm = new Bitmap(originalFileName);
bm.Save(newFileName , ImageFormat.Jpeg);
// Return Converted JPEG Image
var newImage = ImageToByte(Image.FromFile(newFileName));
//DeleteCreatedImage(newFileName);
//DeleteCreatedImage(originalFileName);
return newImage;
}
private byte[] ImageToByte(Image img)
{
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(img, typeof(byte[]));
}
public static void DeleteImageFile(string fileName)
{
FileInfo file = new FileInfo(fileName);
if (file.Exists && !file.IsReadOnly)
{
System.IO.File.Delete(fileName);
}
}
I was wondering if there was a way to do this without saving a file to the hard disk or if i do save it then deleting it once i am done with it.
I've tried adding a delete for each images (check the commented out portion of the ConvertCorruptedImage method) but i keep getting the following error:
The process cannot access the file 'C:\new_xx.jpg' because it is being used by another process.
I really don't want to be saving images to a hard disk.
Thanks in advance
something along the lines of
var image = Image.FromStream(new MemoryStream(imageData));
Bitmap bmp = new Bitmap(image);
MemoryStream outStream = new MemoryStream();
bmp.Save(outStream,ImageFormat.Jpeg);
return outStream.ToArray();
Use the overload of Bitmap.Save that writes to a Stream.
var stream = new MemoryStream();
bm.Save(stream, ImageFormat.Jpeg);
You can load the bitmap directly from your MemoryStream:
Bitmap bm = new Bitmap(imgStream);
You can also save the bitmap to a stream:
MemoryStream newImgStream = new MemoryStream();
bm.Save(newMemoryStream, ImageFormat.Jpeg);

Resources