3

I am doing a 90° rotation with minimal loss, using the following code:

System.Drawing.Image originalImage = System.Drawing.Image.FromFile("input.jpg");
ImageFormat sourceFormat = originalImage.RawFormat;
EncoderParameters encoderParams = null;
try
{
    if (sourceFormat.Guid == ImageFormat.Jpeg.Guid)
    {
        encoderParams = new EncoderParameters(1);
        encoderParams.Param[0] = new EncoderParameter(Encoder.Transformation,
            (long)EncoderValue.TransformRotate90);
    }
    originalImage.Save("output.jpg", GetEncoder(sourceFormat), encoderParams);
}
finally
{
    if (encoderParams != null)
        encoderParams.Dispose();
}

However the Save function seems to create EXIF metadata from the original (pure, no EXIF) JPEG COM marker (0xFE). I do not want EXIF markers in the output JPEG. I also want to preserve the original COM marked. What C# API in my application can I use instead to save my rotated buffer ?

Using jpegdump (dicom3tools package):

$ jpegdump < input.jpg
[...]
Offset 0x0014 Marker 0xfffe COM Comment length variable 0x10

While:

$ jpegdump < output.jpg
[...]
Offset 0x0014 Marker 0xffe1 APP1 Reserved for Application Use length variable 0x5a
malat
  • 12,152
  • 13
  • 89
  • 158
  • Does this help? https://stackoverflow.com/questions/21189242/how-do-i-add-jpeg-comment-com-to-an-image – T.Schwarz Jul 08 '21 at 12:32
  • 1
    You might want to look into the [jpegtran code](https://github.com/cloudflare/jpegtran/blob/master/jpegtran.c) ([Wikipedia entry](https://en.wikipedia.org/wiki/Libjpeg#jpegtran)). It can do lossless rotations on jpegs as long as the dimensions are full MCU blocks, i.e. dimensions are divisible by 8 or 16, depending upon the image. – StarGeek Jul 08 '21 at 15:07
  • What does `GetEncoder` do? I would expect something on the lines of `ImageCodecInfo.GetImageEncoders().FirstOrDefault(e => e.FormatID == sourceFormat.Guid)` – Charlieface Jul 07 '22 at 02:48

2 Answers2

1

Turns out the only working solution I could come up with, was saving the JPEG to a MemoryStream and then post process this temporary Stream using the solution described at:

Pseudo code:

var jpegPatcher = new JpegPatcher();
FileStream outFile = new FileStream(fileName, FileMode.Open, FileAccess.Write);
jpegPatcher.PatchAwayExif(inStream, outFile);

I used the code from the blog, which does:

private void SkipAppHeaderSection(Stream inStream)
...
  while (header[0] == 0xff && (header[1] >= 0xe0 && header[1] <= 0xef))

So the function name PatchAwayExif is a bit odd since it also remove the APP0 (aka JFIF) segment...but that was something I also needed.

malat
  • 12,152
  • 13
  • 89
  • 158
-1

I may be wrong but when the way you are rotating the image, you are not transforming the pixel matrix but simply changing the EXIF data to tell what the image orientation is.

So when you are saving it, it is just adding in the EXIF orientation flag to the original.

If you removed that EXIF data the image would lose its 90º rotation.

More info on rotation EXIF flag - here

Example of rotating an image by changing EXIF - here

If you do physically rotate the image using Image.RotateFlip you can remobve the exif data using originalImage.RemovePropertyItem(0x0112)

herostwist
  • 3,778
  • 1
  • 26
  • 34