C # Image Resizing - EXIF ​​Loss

Yes, yes ... I saw other posts related to this problem, and yes ... I was looking for this information.

But so far I have not managed to get to the desired result.

I upload a large image made at 300 dpi and I need to resize it.

I know ... I know that ... dpi is relative and doesn't really matter ... What are the pixel sizes in pixels:

DPI is, in fact, the number of pixels corresponding to an inch when the image is not printed when it is viewed on the screen. Therefore, by increasing the DPI of an image, you do not increase the size of the image on the screen. You only increase print quality. A.

Even though the DPI information stored in the EXIF ​​image is somewhat useless, it causes me problems.

I resize the image , losing the original exif information , including horizontal and vertical resolution (dpi), and thus it saves with 96 dpi by default. A possible reason for this is that only JPEG and another format can contain metadata information.

The result of the final image should look like this: 275x375 at 300 dpi Instead, it looks like this: 275x375 at 96dpi

You can claim that they are the same, and I agree, but we have a corel script binding that was used to load these images, and since this dpi information is different from others, it puts it in different sizes in the document.

Here is what I use to resize:

public System.Drawing.Bitmap ResizeImage(System.Drawing.Image image, int width, int height) { Bitmap result = new Bitmap(width, height); // set the resolutions the same to avoid cropping due to resolution differences result.SetResolution(image.HorizontalResolution, image.VerticalResolution); //use a graphics object to draw the resized image into the bitmap using (Graphics graphics = Graphics.FromImage(result)) { //set the resize quality modes to high quality graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High; graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; //draw the image into the target bitmap graphics.DrawImage(image, 0, 0, result.Width, result.Height); } //return the resulting bitmap return result; } 

This works very well, but loses EXIF ​​information.

Setting SetResolution to SetResolution (300, 300) does not work!

I looked at reading and changing EXIF ​​image information, and I tried:

 public void setImageDpi(string Filename, string NewRes) { Image Pic; PropertyItem[] PropertyItems; byte[] bDescription = new Byte[NewRes.Length]; int i; string FilenameTemp; System.Drawing.Imaging.Encoder Enc = System.Drawing.Imaging.Encoder.Transformation; EncoderParameters EncParms = new EncoderParameters(1); EncoderParameter EncParm; ImageCodecInfo CodecInfo = GetEncoderInfo("image/jpeg"); // copy description into byte array for (i = 0; i < NewRes.Length; i++) bDescription[i] = (byte)NewRes[i]; // load the image to change Pic = Image.FromFile(Filename); foreach (PropertyItem item in Pic.PropertyItems) { if (item.Id == 282 || item.Id == 283) { PropertyItem myProperty = item; myProperty.Value = bDescription; myProperty.Type = 2; myProperty.Len = NewRes.Length; Pic.SetPropertyItem(item); Console.WriteLine(item.Type); } } // we cannot store in the same image, so use a temporary image instead FilenameTemp = Filename + ".temp"; // for lossless rewriting must rotate the image by 90 degrees! EncParm = new EncoderParameter(Enc, (long)EncoderValue.TransformRotate90); EncParms.Param[0] = EncParm; // now write the rotated image with new description Pic.Save(FilenameTemp, CodecInfo, EncParms); // for computers with low memory and large pictures: release memory now Pic.Dispose(); Pic = null; GC.Collect(); // delete the original file, will be replaced later System.IO.File.Delete(Filename); // now must rotate back the written picture Pic = Image.FromFile(FilenameTemp); EncParm = new EncoderParameter(Enc, (long)EncoderValue.TransformRotate270); EncParms.Param[0] = EncParm; Pic.Save(Filename, CodecInfo, EncParms); // release memory now Pic.Dispose(); Pic = null; GC.Collect(); // delete the temporary picture System.IO.File.Delete(FilenameTemp); } 

That didn't work either.

I tried to look at and change the EXIF ​​information for DPI (282 and 283) later in the process:

  Encoding _Encoding = Encoding.UTF8; Image theImage = Image.FromFile("somepath"); PropertyItem propItem282 = theImage.GetPropertyItem(282); propItem282.Value = _Encoding.GetBytes("300" + '\0'); theImage.SetPropertyItem(propItem282); PropertyItem propItem283 = theImage.GetPropertyItem(283); propItem283.Value = _Encoding.GetBytes("300" + '\0'); theImage.SetPropertyItem(propItem283); theImage.Save("somepath"); 

But the program displays a message that the Property could not be found.

If the property does not exist, apparently I cannot add it:

PropertyItem is not intended to be used as a separate object. The PropertyItem is intended for use by classes derived from Image. The PropertyItem is used to retrieve and modify the metadata of existing image files, and not to create metadata. Therefore, the PropertyItem class does not have a specific Public constructor, and you cannot create an instance of the PropertyItem object.

I'm stuck ... all I need is a resized image with a dpi resolution of 300 should not be so complicated.

Any help is greatly appreciated. Thanks

+4
source share
1 answer

The following code worked for me:

 const string InputFileName = "test_input.jpg"; const string OutputFileName = "test_output.jpg"; var newSize = new Size(640, 480); using (var bmpInput = Image.FromFile(InputFileName)) { using (var bmpOutput = new Bitmap(bmpInput, newSize)) { foreach (var id in bmpInput.PropertyIdList) bmpOutput.SetPropertyItem(bmpInput.GetPropertyItem(id)); bmpOutput.SetResolution(300.0f, 300.0f); bmpOutput.Save(OutputFileName, ImageFormat.Jpeg); } } 

When I check the output file, I can see the EXIF ​​data, and the DPI has been changed to 300.

+12
source

Source: https://habr.com/ru/post/1492990/


All Articles