We have two images, one after saving from memory to disk takes 3 MB, the other 2 MB.

How to get the weight (size) of the image in megabytes before saving?

  • Maybe even show the code, what bitmap do you use? In general, it all depends on the degree of compression. If without compression, it is quite simple to calculate. If with compression, I suppose, nothing. - ixSci
  • @ixSci, I meant the general algorithm of actions for a similar task. I did not mean a specific format or compression ratio. Maybe there are some kind of regular means or ready-made classes / libraries? - Alexis
  • @ixSci, or just give a simple example on any format that is convenient for you. - Alexis

2 answers 2

Let's try to figure out how to get the size, using the example System.Drawing.Bitmap . In my opinion, we can distinguish 2 cases:

  1. We want to know the size of the output file in raw
  2. We want to know the size of the output file in a compressed form.

The first method is quite simple, and we have all the data in the object itself to calculate the size. So, the size of the resulting file will be as follows:

Размер = Высота*Ширина*КоличествоБайтНаКаждыйПиксель 

Where Высота is Bitmap.Height , Ширина is Bitmap.Width , and Bitmap.Width can be obtained from the Bitmap.PixelFormat property

It is quite another thing when we use any kind of compression (JPEG, PNG, etc.). Here we just can not count. So let's go the other way. Let's use the Bitmap.Save(Stream, ImageFormat) method Bitmap.Save(Stream, ImageFormat) and write our file to the System.IO.MemoryStream , the size of which will be contained in the Length property.

  • Oh, not so simple for Bitmap. Unfortunately, the proposed option does not work: there are more titles, plus a palette, minus RLE compression (yes, it is compressed, although not much))) - Sergey Rufanov
  • @SergeyRufanov, what kind of compression? I was talking about a stupid dump of "pixels" to a file Yes, it would be nice to add windth / height / pixel format there, for later reading. But this is all a maximum of 12 bytes, which does not matter, in the overall picture. - ixSci
  • A, clear. I was just thinking about saving Bitmap to BMP, via the Save () method. If you simply serialize the pixels, then yes - so count it out. - Sergey Rufanov

Fit image size and quality of compression to the desired volume on the disk: http://bbs.vbstreets.ru/viewtopic.php?f=2&t=43424

Here is the code from there (it would be necessary to add more using'i to stream'am):

 Imports System.IO Imports System.Drawing.Imaging Module All Public Function GetJpegContent(ByVal Pct As Image) As Byte() Dim File As New MemoryStream Pct.Save(File, ImageFormat.Jpeg) Return File.ToArray() End Function Public Function GetJpegContent(ByVal Pct As Image, ByVal Quality As Long) As Byte() Dim File As New MemoryStream Dim EncoderParams As New EncoderParameters(1) EncoderParams.Param(0) = New EncoderParameter(Encoder.Quality, Quality) Pct.Save(File, GetEncoderInfo("image/jpeg"), EncoderParams) Return File.ToArray() End Function Private Function GetEncoderInfo(ByVal MimeType As String) As ImageCodecInfo For Each Codec As ImageCodecInfo In ImageCodecInfo.GetImageEncoders() If Codec.MimeType = MimeType Then Return Codec Next Codec Return Nothing End Function Public Function ReduceByQuality(ByVal Pct As Image, ByVal Lim As Integer) As Byte() Dim LastOk() As Byte = Nothing, Res() As Byte Dim L As Integer = 0, R As Integer = 100, Cur As Integer Do While L < R Cur = (L + R + 1) >> 1 Res = GetJpegContent(Pct, Cur) If Res.Length > Lim Then R = Cur - 1 Else L = Cur LastOk = Res End If Loop Return LastOk End Function Public Function ReduceBySize(ByVal Pct As Image, ByVal Lim As Integer) As Byte() Dim LastOk() As Byte = Nothing, Res() As Byte Dim LHeight As Integer = 0, RHeight As Integer = Pct.Height, CurHeight As Integer Dim LWidth As Integer = 0, RWidth As Integer = Pct.Width, CurWidth As Integer Do While LHeight < RHeight CurHeight = (LHeight + RHeight + 1) >> 1 CurWidth = (LWidth + RWidth + 1) >> 1 Res = GetJpegContent(New System.Drawing.Bitmap(CType(Pct, Bitmap), CurWidth, CurHeight)) If Res.Length > Lim Then RHeight = CurHeight - 1 RWidth = CurWidth - 1 Else LHeight = CurHeight LWidth = CurWidth LastOk = Res End If Loop Return LastOk End Function Public Sub Main() My.Computer.FileSystem.WriteAllBytes("ReduceByQuality.jpg", ReduceByQuality(Bitmap.FromFile("input.jpg"), 307200), False) My.Computer.FileSystem.WriteAllBytes("ReduceBySize.jpg", ReduceBySize(Bitmap.FromFile("input.jpg"), 307200), False) MsgBox("Ready") End Sub End Module 

The same on C #:

 using System.IO; using System.Drawing.Imaging; public static class All { public static byte[] GetJpegContent(Image pct) { using (var file = new MemoryStream()) { pct.Save(file, ImageFormat.Jpeg); return file.ToArray(); } } public static byte[] GetJpegContent(Image pct, long quality) { using (var file = new MemoryStream()) { var encoderParams = new EncoderParameters(1); encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, quality); pct.Save(file, GetEncoderInfo("image/jpeg"), EncoderParams); return file.ToArray(); } } static ImageCodecInfo GetEncoderInfo(string mimeType) { return ImageCodecInfo.GetImageEncoders() .FirstOrDefault(codec => codec.MimeType == mimeType); } public byte[] ReduceByQuality(Image pct, int lim) { byte[] laskOK = null; byte[] res; int l = 0, r = 100, cur; while (l < r) { cur = (L + R + 1) / 2; res = GetJpegContent(pct, cur); if (res.Length > lim) { r = cur - 1; } else { l = cur; lastOk = res; } } return lastOk; } public byte[] ReduceBySize(Image pct, int lim) { byte[] lastOk = null; byte[] res; int lHeight = 0, rHeight = pct.Height, curHeight; int lWidth = 0, rWidth = Pct.Width, curWidth; while (lHeight < rHeight) { curHeight = (lHeight + rHeight + 1) / 2; curWidth = (lWidth + rWidth + 1) / 2; res = GetJpegContent( new System.Drawing.Bitmap((Bitmap)pct, cCurWidth, curHeight)); if (res.Length > lim) { rHeight = curHeight - 1; rWidth = curWidth - 1; } else { lHeight = curHeight; lWidth = curWidth; lastOk = res; } } return lastOk; } } class Test { public static Main() { File.WriteAllBytes( "ReduceByQuality.jpg", All.ReduceByQuality(Bitmap.FromFile("input.jpg"), 307200), false); File.WriteAllBytes( "ReduceBySize.jpg", All.ReduceBySize(Bitmap.FromFile("input.jpg"), 307200), false); } } 
  • one
    binary search with jpeg packaging at every step? o_O - VladD
  • one
    @VladD, how would you do it? - Qwertiy
  • one
    would you mind if I recoded to c # (right in this answer)? - VladD
  • one
    @VladD, wait. I think the code with the bug copied. I will correct now. - Qwertiy
  • one
    @VladD, replaced the code. Against converting to C #, I don’t mind if 1. the code remains in both languages, 2. C # code is normally written, and not the result of applying the converter with a bunch of questionable operations. There is also a disadvantage in it that usings on bitmaps and streams are not placed. - Qwertiy