Shrink photos for use in a digital photo frame

This program is provided as source free and its state is “as-is”. There is no guarantee that it will do exactly what you want, but it was written with the best intentions.

The program maintains aspect ratio and follows maximum height and width settings. The smaller files that result allow you to fit more photos onto limited drive space and maintain sufficient resolution on balance.

For safety’s sake it will only write files to an empty directory and will not write to the Windows folder. Make sure that the destination is where you want it to be.

EXIF data options have been added and are under testing.

If you wish to support this work you can make a donation to New Zealand bank account: 06-0313-0252831-00 Microtron Ltd NZ.

Acknowledgement of microtron.co.nz in your derived software or source would be fair.

  • MCU units with sensors and datalogging.
  • Break out boards with user interface. Suitable for datalogging and interactive function including stepper motors.
  • Break out board customizations. Sensors, stepper motors, WiFi, SD cards and Fram.
  • Design of circuit boards, including design of circuit boards that are a customization of a break out board pilot project.
  • WiFi and server collection of data.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Windows.Forms;
using static System.Net.Mime.MediaTypeNames;
using Ini;
using System.Globalization;

namespace ShrinkPhotosForViewerCsharp
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            String inipath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\MicrotronNZ";
            String inifilepath = inipath + "\\ShrinkPhotos.ini";
            if(!Directory.Exists(inipath)) Directory.CreateDirectory(inipath);
            ini = new IniFile(inifilepath);
            String xmaxstr = ini.IniReadValue("global", "xmax");
            String ymaxstr = ini.IniReadValue("global", "ymax");
            if (xmaxstr == "") numericUpDownX.Value = 800;
            else { numericUpDownX.Value = (decimal)Convert.ToInt32(xmaxstr); }
            if (ymaxstr == "") numericUpDownY.Value = 800;
            else { numericUpDownY.Value = (decimal)Convert.ToInt32(ymaxstr); }

            baseDirectoryNameSource = ini.IniReadValue("global", "source") == "" ? "unspecified" : ini.IniReadValue("global", "source");
            baseDirectoryNameDest = ini.IniReadValue("global", "destination") == "" ? "unspecified" : ini.IniReadValue("global", "destination");

            textBoxSource.Text = baseDirectoryNameSource;
            textBoxDest.Text = baseDirectoryNameDest;
           
            String readpausestr = ini.IniReadValue("global", "pause");
            if (readpausestr == "") checkBoxPause.Checked = false;
            else { checkBoxPause.Checked = readpausestr == "1" ? true : false; }

            String readmoviesstr = ini.IniReadValue("global", "movies");
            if (readmoviesstr == "") checkBoxMovies.Checked = false;
            else { checkBoxMovies.Checked = readmoviesstr == "1" ? true : false; }

            String exifstr = ini.IniReadValue("global", "exif");
            if (exifstr == "") comboBoxProperties.SelectedIndex = 3;
            else {
                int i = 0;
                foreach (var item in comboBoxProperties.Items)
                { 
                    if (comboBoxProperties.GetItemText(item) == exifstr)
                    { comboBoxProperties.SelectedIndex = i; }
                    i++;
                }
            }            
        }

        IniFile ini;
        String baseDirectoryNameSource;
        String baseDirectoryNameDest;
        volatile int keycontinue = 0;
        volatile bool allowpause = false;
        volatile bool copymovies = false;
        volatile int comboindex;
        private const int exifOrientationID = 0x112; //274


        private void buttonSource_Click(object sender, EventArgs e)
        {
            DialogResult result = folderBrowserDialogSource.ShowDialog();

            if (result == DialogResult.OK)
            {
                baseDirectoryNameSource = folderBrowserDialogSource.SelectedPath;
                ini.IniWriteValue("global", "source", baseDirectoryNameSource);
            }
            textBoxSource.Text = baseDirectoryNameSource;
        }

        private void buttonDest_Click(object sender, EventArgs e)
        {
            DialogResult result = folderBrowserDialogDest.ShowDialog();

            if (result == DialogResult.OK)
            {
                baseDirectoryNameDest = folderBrowserDialogDest.SelectedPath;
                ini.IniWriteValue("global", "destination", baseDirectoryNameDest);
            }
            textBoxDest.Text = baseDirectoryNameDest;
        }
        public static System.Drawing.Image ResizeImage(System.Drawing.Image sourceImage, int maxWidth, int maxHeight)
        {
            // Internet example
            // Determine which ratio is greater, the width or height, and use
            // this to calculate the new width and height. Effectually constrains
            // the proportions of the resized image to the proportions of the original.
            double xRatio = (double)sourceImage.Width / maxWidth;
            double yRatio = (double)sourceImage.Height / maxHeight;
            double ratioToResizeImage = Math.Max(xRatio, yRatio);
            int newWidth = (int)Math.Floor(sourceImage.Width / ratioToResizeImage);
            int newHeight = (int)Math.Floor(sourceImage.Height / ratioToResizeImage);

            // Create new image canvas -- use maxWidth and maxHeight in this function call if you wish
            // to set the exact dimensions of the output image.
            Bitmap newImage = new Bitmap(newWidth, newHeight, PixelFormat.Format32bppArgb);

            // Render the new image, using a graphic object
            using (Graphics newGraphic = Graphics.FromImage(newImage))
            {
                //using (var wrapMode = new ImageAttributes())
                //{
                //    wrapMode.SetWrapMode(WrapMode.TileFlipXY);
                //    newGraphic.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
                //}

                // Set the background color to be transparent (can change this to any color)
                newGraphic.Clear(Color.Transparent);

                // Set the method of scaling to use -- HighQualityBicubic is said to have the best quality
                newGraphic.InterpolationMode = InterpolationMode.HighQualityBicubic;

                // Apply the transformation onto the new graphic
                Rectangle sourceDimensions = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height);
                Rectangle destinationDimensions = new Rectangle(0, 0, newWidth, newHeight);
                newGraphic.DrawImage(sourceImage, destinationDimensions, sourceDimensions, GraphicsUnit.Pixel);
            }

            // Image has been modified by all the references to it's related graphic above. Return changes.
            return newImage;
        }

       
        void setButtonsEnabled(bool enabled) 
        {
            buttonRun.Enabled = enabled;
            buttonDest.Enabled = enabled;
            buttonSource.Enabled = enabled;
        }
       
        private void buttonRun_Click(object sender, EventArgs e)
        {
            setButtonsEnabled(false);
            richTextBox1.Clear();
            if (Directory.Exists(baseDirectoryNameDest))
            {
                
                if(Directory.GetDirectories(baseDirectoryNameDest).Length != 0 || Directory.GetFiles(baseDirectoryNameDest, "*.*").Length != 0)
                {
                    richTextBox1.Clear();
                    richTextBox1.AppendText("\n" + baseDirectoryNameDest + " not empty.");
                    setButtonsEnabled(true);
                    return;
                }
                
            }
            else
            {
                richTextBox1.Clear();
                richTextBox1.AppendText("\n" + baseDirectoryNameDest + " does not exist.");
                setButtonsEnabled(true);
                return;
            }

            if(baseDirectoryNameSource == baseDirectoryNameDest)
            {
                richTextBox1.Clear();
                richTextBox1.AppendText("\n" + baseDirectoryNameDest + " is the same as the source.");
                setButtonsEnabled(true);
                return;
            }

            String destpathwithoutdrive = baseDirectoryNameDest.Substring(Path.GetPathRoot(baseDirectoryNameDest).Length); 
            if (destpathwithoutdrive.StartsWith("Windows"))
            {
                richTextBox1.Clear();
                richTextBox1.AppendText("\n" + baseDirectoryNameDest + " is in the Windows folder.");
                setButtonsEnabled(true);
                return;
            }

            
            String[] srcdirs = Directory.GetDirectories(baseDirectoryNameSource, "*.*", SearchOption.AllDirectories);
            foreach (String srcdir in srcdirs)
            {
                if (Directory.Exists(srcdir) && Directory.Exists(baseDirectoryNameDest))
                {
                    String newdir = srcdir.Replace(baseDirectoryNameSource, baseDirectoryNameDest);
                    if (!Directory.Exists(newdir))
                    {
                        Directory.CreateDirectory(newdir);
                        richTextBox1.AppendText(newdir + "\t\t\tcreated\n");
                        richTextBox1.ScrollToCaret();
                    }
                }
                System.Windows.Forms.Application.DoEvents();
            }
            richTextBox1.AppendText("created directories" + "\n");


            richTextBox1.AppendText("\n");
            int n = 1;

            if (copymovies)
            {
                if (allowpause) richTextBox1.AppendText("space to continue, esc to exit" + "\n");
                richTextBox1.ScrollToCaret();

                keycontinue = 0;
                while (allowpause)
                {
                    if (keycontinue == 0) { this.Activate(); System.Windows.Forms.Application.DoEvents(); System.Threading.Thread.Sleep(100); continue; }
                    else if (keycontinue == 1) { break; }
                    else { setButtonsEnabled(true); richTextBox1.AppendText("task aborted" + "\n"); richTextBox1.ScrollToCaret(); return; }
                }

                
                String[] movsrcfiles1 = Directory.GetFiles(baseDirectoryNameSource, "*.mp4", SearchOption.AllDirectories);
                String[] movsrcfiles2 = Directory.GetFiles(baseDirectoryNameSource, "*.mpg", SearchOption.AllDirectories);
                String[] movsrcfiles3 = Directory.GetFiles(baseDirectoryNameSource, "*.mov", SearchOption.AllDirectories);

                List<String> strlist = new List<String>();
                foreach (String str in movsrcfiles1)
                {
                    strlist.Add(str);
                }
                foreach (String str in movsrcfiles2)
                {
                    strlist.Add(str);
                }
                foreach (String str in movsrcfiles3)
                {
                    strlist.Add(str);
                }

                foreach (String srcfile in strlist)
                {
                    if (File.Exists(srcfile) && Directory.Exists(baseDirectoryNameDest))
                    {
                        String newfile = srcfile.Replace(baseDirectoryNameSource, baseDirectoryNameDest);
                        if (!newfile.Contains(baseDirectoryNameDest)) continue;

                        if (!File.Exists(newfile))
                        {
                            richTextBox1.AppendText(newfile + "   " + n + "\n");
                            richTextBox1.ScrollToCaret();
                            try
                            {
                                File.Copy(srcfile, newfile);
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show("An exception was thrown. " + ex.Message);
                            }
                        }
                        n++;
                        //if (n++ >= 10) break;                        
                    }
                    System.Windows.Forms.Application.DoEvents();
                }
                if (n > 1) richTextBox1.AppendText("Movies copied unchanged" + "\n");
            }

            if (allowpause) richTextBox1.AppendText("space to continue, esc to exit" + "\n");
            richTextBox1.ScrollToCaret();

            keycontinue = 0;
            while (allowpause)
            {
                if (keycontinue == 0) { this.Activate(); System.Windows.Forms.Application.DoEvents(); System.Threading.Thread.Sleep(100); continue; }
                else if (keycontinue == 1) { break; }
                else { setButtonsEnabled(true); richTextBox1.AppendText("task aborted" + "\n"); richTextBox1.ScrollToCaret(); return; }
            }

            n = 1;
            String[] srcfiles1 = Directory.GetFiles(baseDirectoryNameSource, "*.jpg", SearchOption.AllDirectories);
            String[] srcfiles2 = Directory.GetFiles(baseDirectoryNameSource, "*.jpeg", SearchOption.AllDirectories);
            String[] srcfiles3 = Directory.GetFiles(baseDirectoryNameSource, "*.png", SearchOption.AllDirectories);

            List<String> photostrlist = new List<String>();
            foreach (String str in srcfiles1)
            {
                photostrlist.Add(str);
            }
            foreach (String str in srcfiles2)
            {
                photostrlist.Add(str);
            }
            foreach (String str in srcfiles3)
            {
                photostrlist.Add(str);
            }

            int norotated = 0;
            foreach (String srcfile in photostrlist)
            {                
                if (File.Exists(srcfile) && Directory.Exists(baseDirectoryNameDest))
                {
                    String newfile = srcfile.Replace(baseDirectoryNameSource, baseDirectoryNameDest);
                    if (!newfile.Contains(baseDirectoryNameDest)) continue;                    

                    if (!File.Exists(newfile))
                    {
                        bool rotated = false;
                        try
                        {
                            using (System.Drawing.Image image = System.Drawing.Image.FromFile(srcfile))
                            {                                
                                System.Drawing.Image imageout = ResizeImage(image, (int)numericUpDownX.Value, (int)numericUpDownY.Value); //800 800

                                //if (comboBoxProperties.SelectedItem != comboBoxProperties.Items[0]) //  1 2 & 3
                                if(comboindex != 0)
                                {
                                    //if (comboBoxProperties.SelectedItem == comboBoxProperties.Items[2]) // 2
                                    if (comboindex == 2)
                                        if (ExifRotate(image)) { norotated++; rotated = true; }

                                    foreach (var propertyItem in image.PropertyItems)
                                    {
                                        //if (comboBoxProperties.SelectedItem != comboBoxProperties.Items[3])
                                        if(comboindex != 3)
                                        { if (propertyItem.Id == 0x0112) continue; } // 1 & 2
                                        imageout.SetPropertyItem(propertyItem);  //  1 2 & 3
                                    }
                                }
                                else
                                {
                                    foreach (var propertyItem in imageout.PropertyItems)
                                    {                                        
                                        imageout.RemovePropertyItem(propertyItem.Id);
                                    }
                                }

                                imageout.Save(newfile);
                            }
                        }
                        catch (Exception ex) { MessageBox.Show("An exception was thrown.\n" + ex.Message); }

                        richTextBox1.AppendText(newfile + "   " + n + (rotated ? "    rotated" : "") + "\n");
                        richTextBox1.ScrollToCaret();                        
                    }
                    n++;
                    //if (n++ >= 10) break;
                }
                System.Windows.Forms.Application.DoEvents();
            }

            if(norotated > 0) richTextBox1.AppendText("No. rotated " + norotated + "\n");
            richTextBox1.AppendText("Task ended" + "\n");
            richTextBox1.ScrollToCaret();
            setButtonsEnabled(true);
        }

        public static bool ExifRotate(System.Drawing.Image img)
        {
            if (!img.PropertyIdList.Contains(exifOrientationID))
                return false;

            var prop = img.GetPropertyItem(exifOrientationID);
            int val = BitConverter.ToUInt16(prop.Value, 0);
            var rot = RotateFlipType.RotateNoneFlipNone;

            if (val == 3 || val == 4)
                rot = RotateFlipType.Rotate180FlipNone;
            else if (val == 5 || val == 6)
                rot = RotateFlipType.Rotate90FlipNone;
            else if (val == 7 || val == 8)
                rot = RotateFlipType.Rotate270FlipNone;

            if (val == 2 || val == 4 || val == 5 || val == 7)
                rot |= RotateFlipType.RotateNoneFlipX;

            if (rot != RotateFlipType.RotateNoneFlipNone)
            {
                img.RotateFlip(rot);
                img.RemovePropertyItem(exifOrientationID);
                return true;
            }
            return false;
        }

        private void numericUpDownX_ValueChanged(object sender, EventArgs e)
        {
            ini.IniWriteValue("global", "xmax", ((int)numericUpDownX.Value).ToString());
        }

        private void numericUpDownY_ValueChanged(object sender, EventArgs e)
        {
            ini.IniWriteValue("global", "ymax", ((int)numericUpDownY.Value).ToString());
        }
        
        private void checkBoxPause_CheckedChanged(object sender, EventArgs e)
        {
            allowpause = checkBoxPause.Checked;
            ini.IniWriteValue("global", "pause", allowpause ? "1" : "0");
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            //MessageBox.Show("key down");
            if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Space)
            {
                keycontinue = 1;
                e.Handled = e.SuppressKeyPress = true;
            }
            if (e.KeyCode == Keys.Escape || e.KeyCode == Keys.X)
                keycontinue = 2;
        }

        private void checkBoxMovies_CheckedChanged(object sender, EventArgs e)
        {
            copymovies = checkBoxMovies.Checked;
            ini.IniWriteValue("global", "movies", copymovies ? "1" : "0");
        }

        private void comboBoxProperties_SelectedIndexChanged(object sender, EventArgs e)
        {
            comboindex = comboBoxProperties.SelectedIndex;
            if (comboBoxProperties.SelectedIndex < 0) return;
            ini.IniWriteValue("global", "exif", comboBoxProperties.GetItemText(comboBoxProperties.Items[comboBoxProperties.SelectedIndex]));
            
        }
    }
}          

/*
 * 
 * 
0x0000 | GpsVer
0x0001 | GpsLatitudeRef
0x0002 | GpsLatitude
0x0003 | GpsLongitudeRef
0x0004 | GpsLongitude
0x0005 | GpsAltitudeRef
0x0006 | GpsAltitude
0x0007 | GpsGpsTime
0x0008 | GpsGpsSatellites
0x0009 | GpsGpsStatus
0x000A | GpsGpsMeasureMode
0x000B | GpsGpsDop
0x000C | GpsSpeedRef
0x000D | GpsSpeed
0x000E | GpsTrackRef
0x000F | GpsTrack
0x0010 | GpsImgDirRef
0x0011 | GpsImgDir
0x0012 | GpsMapDatum
0x0013 | GpsDestLatRef
0x0014 | GpsDestLat
0x0015 | GpsDestLongRef
0x0016 | GpsDestLong
0x0017 | GpsDestBearRef
0x0018 | GpsDestBear
0x0019 | GpsDestDistRef
0x001A | GpsDestDist
0x00FE | NewSubfileType
0x00FF | SubfileType
0x0100 | ImageWidth
0x0101 | ImageHeight
0x0102 | BitsPerSample
0x0103 | Compression
0x0106 | PhotometricInterp
0x0107 | ThreshHolding
0x0108 | CellWidth
0x0109 | CellHeight
0x010A | FillOrder
0x010D | DocumentName
0x010E | ImageDescription
0x010F | EquipMake
0x0110 | EquipModel
0x0111 | StripOffsets
0x0112 | Orientation
0x0115 | SamplesPerPixel
0x0116 | RowsPerStrip
0x0117 | StripBytesCount
0x0118 | MinSampleValue
0x0119 | MaxSampleValue
0x011A | XResolution
0x011B | YResolution
0x011C | PlanarConfig
0x011D | PageName
0x011E | XPosition
0x011F | YPosition
0x0120 | FreeOffset
0x0121 | FreeByteCounts
0x0122 | GrayResponseUnit
0x0123 | GrayResponseCurve
0x0124 | T4Option
0x0125 | T6Option
0x0128 | ResolutionUnit
0x0129 | PageNumber
0x012D | TransferFunction
0x0131 | SoftwareUsed
0x0132 | DateTime
0x013B | Artist
0x013C | HostComputer
0x013D | Predictor
0x013E | WhitePoint
0x013F | PrimaryChromaticities
0x0140 | ColorMap
0x0141 | HalftoneHints
0x0142 | TileWidth
0x0143 | TileLength
0x0144 | TileOffset
0x0145 | TileByteCounts
0x014C | InkSet
0x014D | InkNames
0x014E | NumberOfInks
0x0150 | DotRange
0x0151 | TargetPrinter
0x0152 | ExtraSamples
0x0153 | SampleFormat
0x0154 | SMinSampleValue
0x0155 | SMaxSampleValue
0x0156 | TransferRange
0x0200 | JPEGProc
0x0201 | JPEGInterFormat
0x0202 | JPEGInterLength
0x0203 | JPEGRestartInterval
0x0205 | JPEGLosslessPredictors
0x0206 | JPEGPointTransforms
0x0207 | JPEGQTables
0x0208 | JPEGDCTables
0x0209 | JPEGACTables
0x0211 | YCbCrCoefficients
0x0212 | YCbCrSubsampling
0x0213 | YCbCrPositioning
0x0214 | REFBlackWhite
0x0301 | Gamma
0x0302 | ICCProfileDescriptor
0x0303 | SRGBRenderingIntent
0x0320 | ImageTitle
0x5001 | ResolutionXUnit
0x5002 | ResolutionYUnit
0x5003 | ResolutionXLengthUnit
0x5004 | ResolutionYLengthUnit
0x5005 | PrintFlags
0x5006 | PrintFlagsVersion
0x5007 | PrintFlagsCrop
0x5008 | PrintFlagsBleedWidth
0x5009 | PrintFlagsBleedWidthScale
0x500A | HalftoneLPI
0x500B | HalftoneLPIUnit
0x500C | HalftoneDegree
0x500D | HalftoneShape
0x500E | HalftoneMisc
0x500F | HalftoneScreen
0x5010 | JPEGQuality
0x5011 | GridSize
0x5012 | ThumbnailFormat
0x5013 | ThumbnailWidth
0x5014 | ThumbnailHeight
0x5015 | ThumbnailColorDepth
0x5016 | ThumbnailPlanes
0x5017 | ThumbnailRawBytes
0x5018 | ThumbnailSize
0x5019 | ThumbnailCompressedSize
0x501A | ColorTransferFunction
0x501B | ThumbnailData
0x5020 | ThumbnailImageWidth
0x5021 | ThumbnailImageHeight
0x5022 | ThumbnailBitsPerSample
0x5023 | ThumbnailCompression
0x5024 | ThumbnailPhotometricInterp
0x5025 | ThumbnailImageDescription
0x5026 | ThumbnailEquipMake
0x5027 | ThumbnailEquipModel
0x5028 | ThumbnailStripOffsets
0x5029 | ThumbnailOrientation
0x502A | ThumbnailSamplesPerPixel
0x502B | ThumbnailRowsPerStrip
0x502C | ThumbnailStripBytesCount
0x502D | ThumbnailResolutionX
0x502E | ThumbnailResolutionY
0x502F | ThumbnailPlanarConfig
0x5030 | ThumbnailResolutionUnit
0x5031 | ThumbnailTransferFunction
0x5032 | ThumbnailSoftwareUsed
0x5033 | ThumbnailDateTime
0x5034 | ThumbnailArtist
0x5035 | ThumbnailWhitePoint
0x5036 | ThumbnailPrimaryChromaticities
0x5037 | ThumbnailYCbCrCoefficients
0x5038 | ThumbnailYCbCrSubsampling
0x5039 | ThumbnailYCbCrPositioning
0x503A | ThumbnailRefBlackWhite
0x503B | ThumbnailCopyRight
0x5090 | LuminanceTable
0x5091 | ChrominanceTable
0x5100 | FrameDelay
0x5101 | LoopCount
0x5102 | GlobalPalette
0x5103 | IndexBackground
0x5104 | IndexTransparent
0x5110 | PixelUnit
0x5111 | PixelPerUnitX
0x5112 | PixelPerUnitY
0x5113 | PaletteHistogram
0x8298 | Copyright
0x829A | ExifExposureTime
0x829D | ExifFNumber
0x8769 | ExifIFD
0x8773 | ICCProfile
0x8822 | ExifExposureProg
0x8824 | ExifSpectralSense
0x8825 | GpsIFD
0x8827 | ExifISOSpeed
0x8828 | ExifOECF
0x9000 | ExifVer
0x9003 | ExifDTOrig
0x9004 | ExifDTDigitized
0x9101 | ExifCompConfig
0x9102 | ExifCompBPP
0x9201 | ExifShutterSpeed
0x9202 | ExifAperture
0x9203 | ExifBrightness
0x9204 | ExifExposureBias
0x9205 | ExifMaxAperture
0x9206 | ExifSubjectDist
0x9207 | ExifMeteringMode
0x9208 | ExifLightSource
0x9209 | ExifFlash
0x920A | ExifFocalLength
0x927C | ExifMakerNote
0x9286 | ExifUserComment
0x9290 | ExifDTSubsec
0x9291 | ExifDTOrigSS
0x9292 | ExifDTDigSS
0xA000 | ExifFPXVer
0xA001 | ExifColorSpace
0xA002 | ExifPixXDim
0xA003 | ExifPixYDim
0xA004 | ExifRelatedWav
0xA005 | ExifInterop
0xA20B | ExifFlashEnergy
0xA20C | ExifSpatialFR
0xA20E | ExifFocalXRes
0xA20F | ExifFocalYRes
0xA210 | ExifFocalResUnit
0xA214 | ExifSubjectLoc
0xA215 | ExifExposureIndex
0xA217 | ExifSensingMethod
0xA300 | ExifFileSource
0xA301 | ExifSceneType
0xA302 | ExifCfaPattern
 * */