This project has moved and is read-only. For the latest updates, please go here.

AddProfile causes NullReferenceException

May 12, 2016 at 11:06 AM
Hey guys I have the following code:
        public static void ConvertRawImage(string path)
        {
            ImageProfile exif = new ExifProfile(path);

            MagickReadSettings settings = new MagickReadSettings();
            settings.Format = MagickFormat.Cr2;          
            try
            {
                using (MagickImage image = new MagickImage(path, settings))
                {
                    if (exif != null)
                    {
                        image.AddProfile(exif);
                    }
                    image.Quality = 95;
                    image.Write(GetFullPathWithoutExtension(path) + ".jpg");
                }
            }
            catch (MagickException ex)
            {
                Console.WriteLine(ex.Message);
            }

            var rawDir = System.IO.Directory.CreateDirectory(Path.GetDirectoryName(path) + @"\RAW");
            File.Move(path, rawDir.FullName + @"\" + Path.GetFileName(path));
        }
I get the following exception:
System.NullReferenceException was unhandled
  HResult=-2147467261
  Message=Object reference not set to an instance of an object.
  Source=Magick.NET-Q16-AnyCPU
  StackTrace:
       at ImageMagick.ExifWriter.GetIndexes(ExifParts part, ExifTag[] tags)
       at ImageMagick.ExifWriter..ctor(Collection`1 values, ExifParts allowedParts, Boolean bestPrecision)
       at ImageMagick.ExifProfile.UpdateData()
       at ImageMagick.ImageProfile.ToByteArray()
       at ImageMagick.MagickImage.AddProfile(ImageProfile profile, Boolean overwriteExisting)
       at ShooterSoftware.Toolbox.ConvertRawImage(string path) i C:\_gitProjects\ShooterSoftware\ShooterSoftware\Util\Toolbox.cs:linje 383
       at RotateImageTest.Program.RawTest() i C:\_gitProjects\ShooterSoftware\RotateImageTest\Program.cs:linje 24
       at RotateImageTest.Program.Main(String[] args) i C:\_gitProjects\ShooterSoftware\RotateImageTest\Program.cs:linje 14
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
So there is one thing which might seem odd in my code, I am not getting the ExifProfile from the image that I have just loaded (image.GetExifProfile();) but from the exact same filepath (new ExifProfile(path);)
The reason for this is that "image.GetExifProfile();" returns null which oddly enough is not the case with "new ExifProfile(path);".

Any help would be appreciated! Do not hesitate to ask me for more info if needed be.

Kind Regards,
Lorentzen1337
May 12, 2016 at 1:12 PM
Edited May 12, 2016 at 1:16 PM
More info:
I am using Magick.NET-Q16-AnyCPU version 7.0.1.101 installed through nuget.

It seems that the error is that the ExifProfile sometimes have no Values attached, I have noticed this by parsing the same file several times:
            int exifRetries = 0;
            ExifProfile exif = new ExifProfile(path);

            while(exif != null && exif.Values.Count() == 0 && exifRetries < 5)
            {
                exif = new ExifProfile(path);
                exifRetries++;
            }
And when Values are empty AddProfile fails.
I am still wondering why the Values are parsed some of the times and other times it isn't even though I am using the same file?
Furthermore it still bothers me that image.GetExifProfile() returns null when new ExifProfile(path) doesn't?

EDIT:
I have alterede my AddProfile according to the finds:
                    if (exif != null && exif.Values.Count() > 0)
                    {
                        image.AddProfile(exif);
                    }
May 12, 2016 at 8:19 PM
I am not sure if you understand how the ExifProfile constructor works. You cannot use it to read the exif profile from an image file. That constructor expects only image data. I just pushed a patch to the git repository to fix the exception. I don't understand why it sometime works and sometimes doesn't with the same file. The values should always be null but should not crash. Can you share the file so I can try to reproduce this.

Also checking 'if (exif != null)' makes no sense to me because you are using a constructor.
May 13, 2016 at 9:14 AM
I think I was aware of how the constructor worked, I only used the constructer to generate the Exif from the path to my image file which should be allowed according to the specification. I think i misunderstood the GetExifProfile method on a MagickImage, I thought it would be able to pull out the Exif data from the image i loaded into the MagickImage that's at least the way i understood the documentation: Read exif data this did not work however, simply returned null even though the constructor new ExifProfile(path) references the same image file.
The error with Exif not always being loaded I had trouble recreating, I might have tested that with a .crw which didn't contain Exif data and hence hit the exception when adding the profile, so thus far I don't think sharing the image makes any sense :)

I did however stumble upon another interesting thing where I can share some images with you:
Converting .cr2 files to .jpg files mirrors the image(flips/flops it) at least when the Exif orientation is 6 or 8(this didn't happen when orientation was 1).
You should notice it with the following files:
https://www.rawsamples.ch/raws/canon/1dsm2/RAW_CANON_1DSM2.CR2 (Orientation 8)
https://www.rawsamples.ch/raws/canon/RAW_CANON_EOS70D.CR2 (Orientation 6)

So far I changed my code so that it flips/flops the image if it is 6 or 8, I do not know whether or not it happens with other raw formats but with all Canon's it is the case.
I parsed the images through the following code to notice it:
        public static void ConvertRawImage(string path)
        {
            ExifProfile exif = new ExifProfile(path);

            MagickReadSettings settings = new MagickReadSettings();
            settings.Format = MagickFormat.Cr2;
            try
            {
                using (MagickImage image = new MagickImage(path, settings))
                {
                    if (exif.Values.Count() > 0)
                    {
                        image.AddProfile(exif);
                    }
                    image.Quality = 95;

                    image.Write(GetFullPathWithoutExtension(path) + ".jpg");
                }
            }
            catch (MagickException ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
"Also checking 'if (exif != null)' makes no sense to me because you are using a constructor." I think, I went into a rampage trying to find the null exception, this of course isn't needed as you pointed out, I have cleaned up my code :)

Thanks for the answers so far! :)