Commit e742b18e99f0ef9977f787fd4ec66a1293248b4b

Authored by Daniel Bourgault
1 parent 4f1faf35
Exists in master

Addition of the function g_geotiff.m to help make geotif figures

Examples/Lab/parameters.dat
... ... @@ -25,7 +25,7 @@ hfov = 62.00; % Field of view of the camera
25 25 lambda = 53.0; % Dip angle below horizontal (e.g. straight down = 90, horizontal = 0)
26 26 phi = 1.0; % Tilt angle (generally close to 0).
27 27 H = 1.755; % Camera altitude (m)
28   -theta = 180.0; % View angle anticlockwise from North (e.g. straight East = 270)
  28 +theta = 180.0; % View angle clockwise from North (e.g. straight East = 90)
29 29  
30 30 % Uncertainty in parameters. Set the uncertainty to 0.0 for fixed parameters.
31 31 dhfov = 5.0;
... ...
src/g_rect/g_geotiff.m 0 โ†’ 100644
... ... @@ -0,0 +1,86 @@
  1 +function [] = g_geotiff(LON,LAT,dx,lon_min,lon_max,lat_min,lat_max)
  2 +%
  3 +% This function creates geotiff images given the longitudes (LON)
  4 +% and latitudes (LAT) of every pixels of the associated jpeg images found
  5 +% in the current folder. The matrices LON and LAT typically come from the
  6 +% g_rect package.
  7 +%
  8 +% The geotiff images are constructed by interpolating on a regular grid of
  9 +% size dx (in m) the irregularly-spaced pixel intensities defined by the
  10 +% LON-LAT pair.
  11 +%
  12 +% INPUT PARAMETERS:
  13 +%
  14 +% LON: A matrix of size identical to the associated images in the current
  15 +% folder that gives the longitude of every pixel of those images.
  16 +% This matrix would typically come from the g_rect package.
  17 +%
  18 +% LAT: Same as LON but for the latitude.
  19 +%
  20 +% dx: The grid size (in m) of the regularly-spaced interpolated
  21 +% geotif image
  22 +%
  23 +% lon_min: The longitude of the southwest corner of the desired
  24 +% geotif image.
  25 +%
  26 +% lon_max: The longitude of the northeastcorner of the desired
  27 +% geotif image.
  28 +%
  29 +% lat_min: The latitude of the southwest corner of the desired
  30 +% geotif image.
  31 +%
  32 +% lat_max: The latitude of the northeastcorner of the desired
  33 +% geotif image.
  34 +%
  35 +% OUTPUT:
  36 +%
  37 +% This function writes geotiff images that have the same name as the
  38 +% jpeg images but with the extension .tif
  39 +%
  40 +% LAST REVISION: 5 May 2020
  41 +%
  42 +% AUTHOR:
  43 +% - Daniel Bourgault (daniel_bourgault@uqar.ca)
  44 +%
  45 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  46 +
  47 +% Construct the vectors 'lon' and 'lat' that define the interpolating
  48 +% grid of constant resolution dx (in m)
  49 +lat0 = (lat_min + lat_max)/2;
  50 +dlat = dx/(1852*60);
  51 +dlon = dlat/cosd(lat0);
  52 +lon = [lon_min:dlon:lon_max];
  53 +lat = [lat_min:dlat:lat_max];
  54 +
  55 +% Find the indices of only the finite values in the matrix LON
  56 +% so that the interpolation is only done on finite values and does
  57 +% not spend time interpolating NaNs.
  58 +ifinite = find(isfinite(LON) == 1);
  59 +
  60 +% Find all .jpg images in the current folder
  61 +img_fname = dir('*.jpg');
  62 +N_img = length(img_fname);
  63 +
  64 +% Loop over all images
  65 +for i = 1:N_img
  66 +
  67 + img = imread(img_fname(i).name);
  68 +
  69 + % Convert to gray scale
  70 + img = rgb2gray(img);
  71 + img = double(img);
  72 + img = img';
  73 +
  74 + % Interpolate on the regular grid defined above by the vector
  75 + % lon and lat
  76 + img_interp = griddata(LON(ifinite),LAT(ifinite),img(ifinite),lon,lat');
  77 +
  78 + % Convert real numbers to unsigned integers
  79 + img_interp = uint8(img_interp);
  80 +
  81 + % Write the geotiff file
  82 + geotif_img_fname = [img_fname(i).name(1:end-3),'tif']
  83 + bbox = [lon_min, lat_min; lon_max, lat_max];
  84 + geotiffwrite(geotif_img_fname, bbox, flipud(img_interp),8);
  85 +
  86 +end
0 87 \ No newline at end of file
... ...
src/g_rect/g_rect.m
... ... @@ -116,7 +116,7 @@ end
116 116 fclose(fid);
117 117  
118 118 %% Import the GCP data (4 column) at the end of the parameter file
119   -gcp = importdata(inputFname,' ',nHeaderLine);
  119 +gcp = importdata(inputFname,' ',nHeaderLine)
120 120 i_gcp = gcp.data(:,1);
121 121 j_gcp = gcp.data(:,2);
122 122 lon_gcp = gcp.data(:,3);
... ...
src/utilities/DNG2jpg/Sumner_2014.pdf 0 โ†’ 100644
No preview for this file type
src/utilities/geotiffwrite_20121203/geotiffwrite.m 0 โ†’ 100755
... ... @@ -0,0 +1,1248 @@
  1 +%GEOTIFFWRITE Write a 2D or 3D array to a single or multi-band GeoTIFF file
  2 +%
  3 +% MATLAB's Mapping Toolbox only provides a "geotiffread" function, but
  4 +% it does not have a "geotiffwrite" function (Note). This is the MATLAB
  5 +% program to write a 2D or 3D array to a single or multi-band GeoTIFF
  6 +% file, where data can be either 1-bit monochrome data (i.e. binary or
  7 +% bilevel), 8-bit unsigned integer, 16-bit signed / unsigned integer,
  8 +% 32-bit signed integer, or 32-bit floating point.
  9 +%
  10 +% Note: Starting from version R2011a, MATLAB's Mapping Toolbox also
  11 +% provides its own "geotiffwrite" function
  12 +% (http://www.mathworks.com/help/toolbox/map/rn/bsq4us7-1.html#bsu1ro5-1).
  13 +%
  14 +% This program is based on GeoTIFF Format Specification under:
  15 +% http://www.remotesensing.org/geotiff/spec/geotiffhome.html
  16 +% or http://download.osgeo.org/geotiff/spec
  17 +%
  18 +% It does not need MATLAB's Mapping Toolbox, or any other library.
  19 +%
  20 +% The motivation to create such a program is because I want to convert
  21 +% the free satelite data from NASA & USGS to the GARMIN topo map for my
  22 +% Garmin GPS. DEM2TOPO (http://people.uleth.ca/~brad.gom/dem2topo) is a
  23 +% wonderful program that can nicely extract contours from the elevation
  24 +% data. However, only 1201x1201 pixels data are supported. For USGS24K
  25 +% DEM data, 1-arc-second SRTM1 data, etc, DEM2TOPO cannot process them
  26 +% directly, which must be converted into GeoTIFF format first (see
  27 +% "Known Issues" in the above site). Although there is a free Windows
  28 +% program "3DEM" that can convert USGS24K DEM & SRTM1 data into GeoTIFF
  29 +% format, sometimes you will still need to interpolate those DEM data
  30 +% for void or missing elevation points.
  31 +%
  32 +% If you just want to write DEM data to a GeoTIFF file, all you have to
  33 +% provide is a bounding box (2 latitude & 2 longitude), and a 2D or 3D
  34 +% array. Otherwise, you can provide proper GeoTIFF fields to the option
  35 +% argument. To make your life easier, a GUI program "make_option.m"
  36 +% is also provided. So you can select the proper GeoTIFF fields to
  37 +% generate the option argument.
  38 +%
  39 +% I recommend that you use "make_option" program to generate option
  40 +% argument instead of constructing it manually.
  41 +%
  42 +% Usage: [option bbox] = make_option([bbox]);
  43 +% geotiffwrite(filename, bbox, image, [bit_depth, option]);
  44 +%
  45 +% filename - GeoTIFF file name to be written.
  46 +%
  47 +% bbox - Bounding box with West/East of longitude and South/North of
  48 +% latitude. The latitude & longitude must be in Decimal Degree
  49 +% (DD) format, and they must be in a 2x2 array with the order
  50 +% of:
  51 +%
  52 +% [ longitude_West, latitude_South;
  53 +% longitude_East, latitude_North ]
  54 +%
  55 +% Note: If GTModelTypeGeoKey is not ModelTypeGeographic, bbox
  56 +% will be reset to empty.
  57 +%
  58 +% image - 2D or 3D array. Although any orientation can be specified
  59 +% through option.Orientation, it is simpler to just use the
  60 +% following default orientation:
  61 +%
  62 +% First row at North edge; last row at South edge;
  63 +% First column at West edge; last column at East edge;
  64 +%
  65 +% Note: By default, "geotiffwrite" assumes intensity image and
  66 +% option.FullColor is 0. So the third dimension of a 3D
  67 +% image represents different bands. If option.FullColor
  68 +% is 1, the third dimension of 3D image must be 3, which
  69 +% indicates R,G,B. i.e. when the third dimension of a 3D
  70 +% array equals to 3, it represents a 3-band GeoTIFF
  71 +% image, unless the option.FullColor is set to 1. When
  72 +% option.ColorMap is set, the specified palette will be
  73 +% used, and you cannot set option.FullColor to 1 at the
  74 +% same time.
  75 +%
  76 +% bit_depth - (optional) Number of bits to represent a data point (i.e.
  77 +% bits per sample):
  78 +%
  79 +% 1 for 1-bit monochrome data (i.e. binary or bilevel)
  80 +% 8 for 8-bit unsigned integer
  81 +% 16 for 16-bit signed integer
  82 +% 32 for 32-bit floating point (default)
  83 +% -16 for 16-bit unsigned integer
  84 +% -32 for 32-bit signed integer
  85 +%
  86 +% Note: If you set values for option.ColorMap, 16 will be for
  87 +% 16-bit unsigned integer, and you cannot write in 32-bit
  88 +% depth or 1-bit depth. If you set option.FullColor to 1,
  89 +% 8-bit unsigned integer will be used, and you cannot
  90 +% change bit_depth for Full Color image.
  91 +%
  92 +% option - (optional) A structure of GeoTIFF fields:
  93 +%
  94 +% First, please run: [option bbox] = make_option( [bbox] ); This
  95 +% will include most fields, except the following:
  96 +%
  97 +% option.NaN
  98 +% By default, NaN value (void data point) in the image
  99 +% variable will be kept untouched. However, if you decide
  100 +% to replace it with other value (e.g. -32768), you can
  101 +% define it here.
  102 +%
  103 +% option.FullColor = [0] | 1
  104 +% 0: Intensity or ColorMap image; (default)
  105 +% 1: FullColor (24-bit RGB) image;
  106 +%
  107 +% option.ColorMap [Nx3 array]
  108 +% Where N = 2^bit_depth, and bit_depth can only be 8 or 16.
  109 +% Values in option.ColorMap range from 0 to 65535, and value
  110 +% 0 in image points to the first row in the ColorMap. Columns
  111 +% in option.ColorMap are [R G B]. Black is represented by
  112 +% [0 0 0], and white is represented by [65535 65535 65535].
  113 +%
  114 +% option.Orientation = [1] | 2 | 3 | 4 | 5 | 6 | 7 | 8
  115 +% 1: Row from Top, Col from Left; (default)
  116 +% 2: Row from Top, Col from Right;
  117 +% 3: Row from Bottom, Col from Right;
  118 +% 4: Row from Bottom, Col from Left;
  119 +% 5: Row from Left, Col from Top;
  120 +% 6: Row from Right, Col from Top;
  121 +% 7: Row from Right, Col from Bottom;
  122 +% 8: Row from Left, Col from Bottom;
  123 +%
  124 +% option.ModelTransformationTag [4x4 array]
  125 +% In most case, ModelPixelScaleTag and ModelTiepointTag from
  126 +% "make_option.m" program is sufficient to transform from raster
  127 +% to model space. If raster image requires rotation or shearing,
  128 +% you can use this ModelTransformationTag to define a 4x4 affine
  129 +% transformation matrix.
  130 +%
  131 +% Examples:
  132 +% - Although not illustrated, it would be easier to use "make_option.m"
  133 +% for option argument
  134 +%
  135 +% Data from UTM projected coordinate systems:
  136 +% ftp://ftp.remotesensing.org/pub/geotiff/samples/spot/chicago/UTM2GTIF.TIF
  137 +% or http://download.osgeo.org/geotiff/samples/spot/chicago/UTM2GTIF.TIF
  138 +% img = imread('UTM2GTIF.TIF');
  139 +% clear option
  140 +% option.GTModelTypeGeoKey = 1;
  141 +% option.ModelPixelScaleTag = [10;10;0];
  142 +% option.ModelTiepointTag = [0;0;0;444650;4640510;0];
  143 +% option.GeogEllipsoidGeoKey = 7008;
  144 +% option.ProjectedCSTypeGeoKey = 26716;
  145 +% option.GTCitationGeoKey = 'UTM Zone 16N NAD27"';
  146 +% option.GeogCitationGeoKey = 'Clarke, 1866 by Default';
  147 +% geotiffwrite('UTM2GTIFX.TIF',[],img,8,option);
  148 +%
  149 +% Data from colormap indexed scan image:
  150 +% ftp://ftp.remotesensing.org/pub/geotiff/samples/usgs/o41078a5.tif
  151 +% or http://download.osgeo.org/geotiff/samples/usgs/o41078a5.tif
  152 +% [img cmap] = imread('o41078a5.tif');
  153 +% clear option
  154 +% option.GTModelTypeGeoKey = 1;
  155 +% option.ModelPixelScaleTag = [2.4384;2.4384;0];
  156 +% option.ModelTiepointTag = [0;0;0;698753.304798;4556059.506392;0];
  157 +% option.ProjectedCSTypeGeoKey = 32617;
  158 +% option.PCSCitationGeoKey = 'UTM Zone 17 N with WGS84';
  159 +% option.ColorMap = 65535*cmap;
  160 +% geotiffwrite('o41078a5X.tif',[],img,8,option);
  161 +%
  162 +% DEM data:
  163 +% ftp://ftp.remotesensing.org/pub/geotiff/samples/usgs/mlatlon.tif
  164 +% or http://download.osgeo.org/geotiff/samples/usgs/mlatlon.tif
  165 +% img = imread('mlatlon.tif');
  166 +% clear option
  167 +% option.GeographicTypeGeoKey = 4267;
  168 +% option.GTCitationGeoKey = 'Geographic Model/GeoTIFF 1.0';
  169 +% option.GeogCitationGeoKey = 'NAD 27 Datum';
  170 +% geotiffwrite('mlatlonX.tif',[-122.6261,37.4531;-122.0777,38],img,16,option);
  171 +%
  172 +% Even simpler:
  173 +% http://dds.cr.usgs.gov/srtm/version2_1/SRTM3/North_America/N46W082.hgt.zip
  174 +% srtm = load_srtm('N46W082.hgt');
  175 +% geotiffwrite('N46W082.tif',[-82,46;-81,47],flipud(srtm.dat));
  176 +%
  177 +% - Jimmy Shen (jimmy@rotman-baycrest.on.ca)
  178 +%
  179 +function geotiffwrite(filename, bbox, image, bit_depth, option)
  180 +
  181 + % Set default inputs
  182 + %
  183 + if nargin < 5
  184 + option = [];
  185 +
  186 + if isempty(bbox)
  187 + help geotiffwrite;
  188 + error('Because you did not specify bounding box, please assign proper values to option argument');
  189 + end
  190 + end
  191 +
  192 + if nargin < 4
  193 + bit_depth = [];
  194 + end
  195 +
  196 + if nargin < 3
  197 + error('Usage: geotiffwrite(filename, bbox, image, [bit_depth, option])');
  198 + end
  199 +
  200 + if isempty(bit_depth)
  201 + bit_depth = 32;
  202 + end
  203 +
  204 + if isfield(option, 'FullColor') & option.FullColor == 1
  205 + bit_depth = 8;
  206 +
  207 + if isfield(option, 'ColorMap')
  208 + error('If you set option.FullColor to 1, you cannot set option.ColorMap.');
  209 + end
  210 + else
  211 + option.FullColor = 0;
  212 + end
  213 +
  214 + if isfield(option, 'ColorMap') & ( abs(bit_depth)==32 | abs(bit_depth)==1 )
  215 + error('If you set values to option.ColorMap, you cannot write in 32-bit depth or 1-bit depth.');
  216 + end
  217 +
  218 + % Set void data: GeoTIFF set void data to -32768, while data from
  219 + % other software can be -32767 or NaN.
  220 + %
  221 +% if strcmpi( class(image), 'double' )
  222 + % image(find(isnan(image))) = -32768;
  223 + % end
  224 +
  225 + % Only for int16 DEM data
  226 + %
  227 +% if bit_depth == 16
  228 + % image(find(image==-32767)) = -32768;
  229 + % end
  230 +
  231 + if isfield(option, 'NaN')
  232 + image(find(isnan(image))) = option.NaN;
  233 + end
  234 +
  235 + % Set Orientation, 274
  236 + %
  237 + if isfield(option, 'Orientation')
  238 + ifd.Orientation = option.Orientation;
  239 +
  240 + for i = 1:size(image,3)
  241 + switch ifd.Orientation
  242 + case 2
  243 + image(:,:,i) = fliplr(image(:,:,i));
  244 + case 3
  245 + image(:,:,i) = fliplr(flipud(image(:,:,i)));
  246 + case 4
  247 + image(:,:,i) = flipud(image(:,:,i));
  248 + case 5
  249 + image(:,:,i) = flipud(rot90(image(:,:,i)));
  250 + case 6
  251 + image(:,:,i) = rot90(image(:,:,i));
  252 + case 7
  253 + image(:,:,i) = fliplr(rot90(image(:,:,i)));
  254 + case 8
  255 + image(:,:,i) = fliplr(flipud(rot90(image(:,:,i))));
  256 + end
  257 + end
  258 + else
  259 + % First row at North edge; last row at South edge;
  260 + % First column at West edge; last column at East edge;
  261 + %
  262 + ifd.Orientation = 1;
  263 + end
  264 +
  265 + if abs(bit_depth) == 1 & mod(size(image,2),8) ~= 0
  266 + error('Please use integral multiple of 8 for 1-bit image size.');
  267 + end
  268 +
  269 +
  270 + GeoAsciiParamsTag = '';
  271 + GeoDoubleParamsTag = [];
  272 + GeoAsciiOffset = 0;
  273 + GeoDoubleOffset = 0;
  274 + NumberOfKeys = 0;
  275 + GeoKeyDirectoryTag = [1 1 0 NumberOfKeys];
  276 +
  277 + % Set GTModelTypeGeoKey, 1024
  278 + %
  279 + NumberOfKeys = NumberOfKeys + 1;
  280 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  281 +
  282 + if isfield(option, 'GTModelTypeGeoKey') & option.GTModelTypeGeoKey ~= 2
  283 + code = option.GTModelTypeGeoKey;
  284 + bbox = [];
  285 + disp('Warning: Since your Model Type is not Geographic, bbox is reset to empty.');
  286 + else
  287 + code = 2; % ModelTypeGeographic
  288 + end
  289 +
  290 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [1024 0 1 code]];
  291 +
  292 + % Set GTRasterTypeGeoKey, 1025
  293 + %
  294 + NumberOfKeys = NumberOfKeys + 1;
  295 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  296 +
  297 + if isfield(option, 'GTRasterTypeGeoKey')
  298 + code = option.GTRasterTypeGeoKey;
  299 + else
  300 + code = 1; % RasterPixelIsArea
  301 + end
  302 +
  303 + gifd.GTRasterTypeGeoKey = code;
  304 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [1025 0 1 code]];
  305 +
  306 + % Set GTCitationGeoKey, 1026
  307 + %
  308 + if isfield(option, 'GTCitationGeoKey')
  309 + NumberOfKeys = NumberOfKeys + 1;
  310 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  311 + code = [option.GTCitationGeoKey(:); '|']; cnt = length(code);
  312 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [1026 34737 cnt GeoAsciiOffset]];
  313 + GeoAsciiParamsTag = [GeoAsciiParamsTag; code];
  314 + GeoAsciiOffset = GeoAsciiOffset + cnt;
  315 + end
  316 +
  317 + % Set GeographicTypeGeoKey, 2048
  318 + %
  319 + if isfield(option, 'GeographicTypeGeoKey')
  320 + NumberOfKeys = NumberOfKeys + 1;
  321 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  322 + code = option.GeographicTypeGeoKey;
  323 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [2048 0 1 code]];
  324 + elseif ~isempty(bbox)
  325 + NumberOfKeys = NumberOfKeys + 1;
  326 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  327 +% code = 4267; % GCS_NAD27
  328 +% code = 4322; % GCS_WGS_72
  329 + code = 4326; % GCS_WGS_84
  330 +% code = 4269; % GCS_NAD83
  331 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [2048 0 1 code]];
  332 + end
  333 +
  334 + % Set GeogCitationGeoKey, 2049
  335 + %
  336 + if isfield(option, 'GeogCitationGeoKey')
  337 + NumberOfKeys = NumberOfKeys + 1;
  338 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  339 + code = [option.GeogCitationGeoKey(:); '|']; cnt = length(code);
  340 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [2049 34737 cnt GeoAsciiOffset]];
  341 + GeoAsciiParamsTag = [GeoAsciiParamsTag; code];
  342 + GeoAsciiOffset = GeoAsciiOffset + cnt;
  343 + end
  344 +
  345 + % Set GeogGeodeticDatumGeoKey, 2050
  346 + %
  347 + if isfield(option, 'GeogGeodeticDatumGeoKey')
  348 + NumberOfKeys = NumberOfKeys + 1;
  349 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  350 + code = option.GeogGeodeticDatumGeoKey;
  351 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [2050 0 1 code]];
  352 + end
  353 +
  354 + % Set GeogPrimeMeridianGeoKey, 2051
  355 + %
  356 + if isfield(option, 'GeogPrimeMeridianGeoKey')
  357 + NumberOfKeys = NumberOfKeys + 1;
  358 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  359 + code = option.GeogPrimeMeridianGeoKey;
  360 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [2051 0 1 code]];
  361 + end
  362 +
  363 + % Set GeogLinearUnitsGeoKey, 2052
  364 + %
  365 + if isfield(option, 'GeogLinearUnitsGeoKey')
  366 + NumberOfKeys = NumberOfKeys + 1;
  367 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  368 + code = option.GeogLinearUnitsGeoKey;
  369 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [2052 0 1 code]];
  370 + end
  371 +
  372 + % Set GeogLinearUnitSizeGeoKey, 2053
  373 + %
  374 + if isfield(option, 'GeogLinearUnitSizeGeoKey')
  375 + NumberOfKeys = NumberOfKeys + 1;
  376 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  377 + code = option.GeogLinearUnitSizeGeoKey;
  378 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [2053 34736 1 GeoDoubleOffset]];
  379 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  380 + GeoDoubleOffset = GeoDoubleOffset + 1;
  381 + end
  382 +
  383 + % Set GeogAngularUnitsGeoKey, 2054
  384 + %
  385 + if isfield(option, 'GeogAngularUnitsGeoKey')
  386 + NumberOfKeys = NumberOfKeys + 1;
  387 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  388 + code = option.GeogAngularUnitsGeoKey;
  389 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [2054 0 1 code]];
  390 + end
  391 +
  392 + % Set GeogAngularUnitSizeGeoKey, 2055
  393 + %
  394 + if isfield(option, 'GeogAngularUnitSizeGeoKey')
  395 + NumberOfKeys = NumberOfKeys + 1;
  396 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  397 + code = option.GeogAngularUnitSizeGeoKey;
  398 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [2055 34736 1 GeoDoubleOffset]];
  399 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  400 + GeoDoubleOffset = GeoDoubleOffset + 1;
  401 + end
  402 +
  403 + % Set GeogEllipsoidGeoKey, 2056
  404 + %
  405 + if isfield(option, 'GeogEllipsoidGeoKey')
  406 + NumberOfKeys = NumberOfKeys + 1;
  407 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  408 + code = option.GeogEllipsoidGeoKey;
  409 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [2056 0 1 code]];
  410 + end
  411 +
  412 + % Set GeogSemiMajorAxisGeoKey, 2057
  413 + %
  414 + if isfield(option, 'GeogSemiMajorAxisGeoKey')
  415 + NumberOfKeys = NumberOfKeys + 1;
  416 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  417 + code = option.GeogSemiMajorAxisGeoKey;
  418 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [2057 34736 1 GeoDoubleOffset]];
  419 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  420 + GeoDoubleOffset = GeoDoubleOffset + 1;
  421 + end
  422 +
  423 + % Set GeogSemiMinorAxisGeoKey, 2058
  424 + %
  425 + if isfield(option, 'GeogSemiMinorAxisGeoKey')
  426 + NumberOfKeys = NumberOfKeys + 1;
  427 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  428 + code = option.GeogSemiMinorAxisGeoKey;
  429 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [2058 34736 1 GeoDoubleOffset]];
  430 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  431 + GeoDoubleOffset = GeoDoubleOffset + 1;
  432 + end
  433 +
  434 + % Set GeogInvFlatteningGeoKey, 2059
  435 + %
  436 + if isfield(option, 'GeogInvFlatteningGeoKey')
  437 + NumberOfKeys = NumberOfKeys + 1;
  438 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  439 + code = option.GeogInvFlatteningGeoKey;
  440 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [2059 34736 1 GeoDoubleOffset]];
  441 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  442 + GeoDoubleOffset = GeoDoubleOffset + 1;
  443 + end
  444 +
  445 + % Set GeogAzimuthUnitsGeoKey, 2060
  446 + %
  447 + if isfield(option, 'GeogAzimuthUnitsGeoKey')
  448 + NumberOfKeys = NumberOfKeys + 1;
  449 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  450 + code = option.GeogAzimuthUnitsGeoKey;
  451 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [2060 0 1 code]];
  452 + end
  453 +
  454 + % Set GeogPrimeMeridianLongGeoKey, 2061
  455 + %
  456 + if isfield(option, 'GeogPrimeMeridianLongGeoKey')
  457 + NumberOfKeys = NumberOfKeys + 1;
  458 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  459 + code = option.GeogPrimeMeridianLongGeoKey;
  460 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [2061 34736 1 GeoDoubleOffset]];
  461 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  462 + GeoDoubleOffset = GeoDoubleOffset + 1;
  463 + end
  464 +
  465 + % Set ProjectedCSTypeGeoKey, 3072
  466 + %
  467 + if isfield(option, 'ProjectedCSTypeGeoKey')
  468 + NumberOfKeys = NumberOfKeys + 1;
  469 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  470 + code = option.ProjectedCSTypeGeoKey;
  471 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3072 0 1 code]];
  472 + end
  473 +
  474 + % Set PCSCitationGeoKey, 3073
  475 + %
  476 + if isfield(option, 'PCSCitationGeoKey')
  477 + NumberOfKeys = NumberOfKeys + 1;
  478 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  479 + code = [option.PCSCitationGeoKey(:); '|']; cnt = length(code);
  480 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3073 34737 cnt GeoAsciiOffset]];
  481 + GeoAsciiParamsTag = [GeoAsciiParamsTag; code];
  482 + GeoAsciiOffset = GeoAsciiOffset + cnt;
  483 + end
  484 +
  485 + % Set ProjectionGeoKey, 3074
  486 + %
  487 + if isfield(option, 'ProjectionGeoKey')
  488 + NumberOfKeys = NumberOfKeys + 1;
  489 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  490 + code = option.ProjectionGeoKey;
  491 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3074 0 1 code]];
  492 + end
  493 +
  494 + % Set ProjCoordTransGeoKey, 3075
  495 + %
  496 + if isfield(option, 'ProjCoordTransGeoKey')
  497 + NumberOfKeys = NumberOfKeys + 1;
  498 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  499 + code = option.ProjCoordTransGeoKey;
  500 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3075 0 1 code]];
  501 + end
  502 +
  503 + % Set ProjLinearUnitsGeoKey, 3076
  504 + %
  505 + if isfield(option, 'ProjLinearUnitsGeoKey')
  506 + NumberOfKeys = NumberOfKeys + 1;
  507 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  508 + code = option.ProjLinearUnitsGeoKey;
  509 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3076 0 1 code]];
  510 + end
  511 +
  512 + % Set ProjLinearUnitSizeGeoKey, 3077
  513 + %
  514 + if isfield(option, 'ProjLinearUnitSizeGeoKey')
  515 + NumberOfKeys = NumberOfKeys + 1;
  516 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  517 + code = option.ProjLinearUnitSizeGeoKey;
  518 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3077 34736 1 GeoDoubleOffset]];
  519 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  520 + GeoDoubleOffset = GeoDoubleOffset + 1;
  521 + end
  522 +
  523 + % Set ProjStdParallel1GeoKey, 3078
  524 + %
  525 + if isfield(option, 'ProjStdParallel1GeoKey')
  526 + NumberOfKeys = NumberOfKeys + 1;
  527 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  528 + code = option.ProjStdParallel1GeoKey;
  529 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3078 34736 1 GeoDoubleOffset]];
  530 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  531 + GeoDoubleOffset = GeoDoubleOffset + 1;
  532 + end
  533 +
  534 + % Set ProjStdParallel2GeoKey, 3079
  535 + %
  536 + if isfield(option, 'ProjStdParallel2GeoKey')
  537 + NumberOfKeys = NumberOfKeys + 1;
  538 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  539 + code = option.ProjStdParallel2GeoKey;
  540 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3079 34736 1 GeoDoubleOffset]];
  541 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  542 + GeoDoubleOffset = GeoDoubleOffset + 1;
  543 + end
  544 +
  545 + % Set ProjNatOriginLongGeoKey, 3080
  546 + %
  547 + if isfield(option, 'ProjNatOriginLongGeoKey')
  548 + NumberOfKeys = NumberOfKeys + 1;
  549 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  550 + code = option.ProjNatOriginLongGeoKey;
  551 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3080 34736 1 GeoDoubleOffset]];
  552 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  553 + GeoDoubleOffset = GeoDoubleOffset + 1;
  554 + end
  555 +
  556 + % Set ProjNatOriginLatGeoKey, 3081
  557 + %
  558 + if isfield(option, 'ProjNatOriginLatGeoKey')
  559 + NumberOfKeys = NumberOfKeys + 1;
  560 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  561 + code = option.ProjNatOriginLatGeoKey;
  562 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3081 34736 1 GeoDoubleOffset]];
  563 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  564 + GeoDoubleOffset = GeoDoubleOffset + 1;
  565 + end
  566 +
  567 + % Set ProjFalseEastingGeoKey, 3082
  568 + %
  569 + if isfield(option, 'ProjFalseEastingGeoKey')
  570 + NumberOfKeys = NumberOfKeys + 1;
  571 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  572 + code = option.ProjFalseEastingGeoKey;
  573 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3082 34736 1 GeoDoubleOffset]];
  574 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  575 + GeoDoubleOffset = GeoDoubleOffset + 1;
  576 + end
  577 +
  578 + % Set ProjFalseNorthingGeoKey, 3083
  579 + %
  580 + if isfield(option, 'ProjFalseNorthingGeoKey')
  581 + NumberOfKeys = NumberOfKeys + 1;
  582 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  583 + code = option.ProjFalseNorthingGeoKey;
  584 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3083 34736 1 GeoDoubleOffset]];
  585 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  586 + GeoDoubleOffset = GeoDoubleOffset + 1;
  587 + end
  588 +
  589 + % Set ProjFalseOriginLongGeoKey, 3084
  590 + %
  591 + if isfield(option, 'ProjFalseOriginLongGeoKey')
  592 + NumberOfKeys = NumberOfKeys + 1;
  593 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  594 + code = option.ProjFalseOriginLongGeoKey;
  595 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3084 34736 1 GeoDoubleOffset]];
  596 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  597 + GeoDoubleOffset = GeoDoubleOffset + 1;
  598 + end
  599 +
  600 + % Set ProjFalseOriginLatGeoKey, 3085
  601 + %
  602 + if isfield(option, 'ProjFalseOriginLatGeoKey')
  603 + NumberOfKeys = NumberOfKeys + 1;
  604 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  605 + code = option.ProjFalseOriginLatGeoKey;
  606 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3085 34736 1 GeoDoubleOffset]];
  607 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  608 + GeoDoubleOffset = GeoDoubleOffset + 1;
  609 + end
  610 +
  611 + % Set ProjFalseOriginEastingGeoKey, 3086
  612 + %
  613 + if isfield(option, 'ProjFalseOriginEastingGeoKey')
  614 + NumberOfKeys = NumberOfKeys + 1;
  615 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  616 + code = option.ProjFalseOriginEastingGeoKey;
  617 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3086 34736 1 GeoDoubleOffset]];
  618 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  619 + GeoDoubleOffset = GeoDoubleOffset + 1;
  620 + end
  621 +
  622 + % Set ProjFalseOriginNorthingGeoKey, 3087
  623 + %
  624 + if isfield(option, 'ProjFalseOriginNorthingGeoKey')
  625 + NumberOfKeys = NumberOfKeys + 1;
  626 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  627 + code = option.ProjFalseOriginNorthingGeoKey;
  628 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3087 34736 1 GeoDoubleOffset]];
  629 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  630 + GeoDoubleOffset = GeoDoubleOffset + 1;
  631 + end
  632 +
  633 + % Set ProjCenterLongGeoKey, 3088
  634 + %
  635 + if isfield(option, 'ProjCenterLongGeoKey')
  636 + NumberOfKeys = NumberOfKeys + 1;
  637 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  638 + code = option.ProjCenterLongGeoKey;
  639 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3088 34736 1 GeoDoubleOffset]];
  640 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  641 + GeoDoubleOffset = GeoDoubleOffset + 1;
  642 + end
  643 +
  644 + % Set ProjCenterLatGeoKey, 3089
  645 + %
  646 + if isfield(option, 'ProjCenterLatGeoKey')
  647 + NumberOfKeys = NumberOfKeys + 1;
  648 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  649 + code = option.ProjCenterLatGeoKey;
  650 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3089 34736 1 GeoDoubleOffset]];
  651 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  652 + GeoDoubleOffset = GeoDoubleOffset + 1;
  653 + end
  654 +
  655 + % Set ProjCenterEastingGeoKey, 3090
  656 + %
  657 + if isfield(option, 'ProjCenterEastingGeoKey')
  658 + NumberOfKeys = NumberOfKeys + 1;
  659 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  660 + code = option.ProjCenterEastingGeoKey;
  661 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3090 34736 1 GeoDoubleOffset]];
  662 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  663 + GeoDoubleOffset = GeoDoubleOffset + 1;
  664 + end
  665 +
  666 + % Set ProjCenterOriginNorthingGeoKey, 3091
  667 + %
  668 + if isfield(option, 'ProjCenterOriginNorthingGeoKey')
  669 + NumberOfKeys = NumberOfKeys + 1;
  670 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  671 + code = option.ProjCenterOriginNorthingGeoKey;
  672 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3091 34736 1 GeoDoubleOffset]];
  673 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  674 + GeoDoubleOffset = GeoDoubleOffset + 1;
  675 + end
  676 +
  677 + % Set ProjScaleAtNatOriginGeoKey, 3092
  678 + %
  679 + if isfield(option, 'ProjScaleAtNatOriginGeoKey')
  680 + NumberOfKeys = NumberOfKeys + 1;
  681 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  682 + code = option.ProjScaleAtNatOriginGeoKey;
  683 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3092 34736 1 GeoDoubleOffset]];
  684 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  685 + GeoDoubleOffset = GeoDoubleOffset + 1;
  686 + end
  687 +
  688 + % Set ProjScaleAtCenterGeoKey, 3093
  689 + %
  690 + if isfield(option, 'ProjScaleAtCenterGeoKey')
  691 + NumberOfKeys = NumberOfKeys + 1;
  692 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  693 + code = option.ProjScaleAtCenterGeoKey;
  694 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3093 34736 1 GeoDoubleOffset]];
  695 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  696 + GeoDoubleOffset = GeoDoubleOffset + 1;
  697 + end
  698 +
  699 + % Set ProjAzimuthAngleGeoKey, 3094
  700 + %
  701 + if isfield(option, 'ProjAzimuthAngleGeoKey')
  702 + NumberOfKeys = NumberOfKeys + 1;
  703 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  704 + code = option.ProjAzimuthAngleGeoKey;
  705 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3094 34736 1 GeoDoubleOffset]];
  706 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  707 + GeoDoubleOffset = GeoDoubleOffset + 1;
  708 + end
  709 +
  710 + % Set ProjStraightVertPoleLongGeoKey, 3095
  711 + %
  712 + if isfield(option, 'ProjStraightVertPoleLongGeoKey')
  713 + NumberOfKeys = NumberOfKeys + 1;
  714 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  715 + code = option.ProjStraightVertPoleLongGeoKey;
  716 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [3095 34736 1 GeoDoubleOffset]];
  717 + GeoDoubleParamsTag = [GeoDoubleParamsTag; code];
  718 + GeoDoubleOffset = GeoDoubleOffset + 1;
  719 + end
  720 +
  721 + % Set VerticalCSTypeGeoKey, 4096
  722 + %
  723 + if isfield(option, 'VerticalCSTypeGeoKey')
  724 + NumberOfKeys = NumberOfKeys + 1;
  725 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  726 + code = option.VerticalCSTypeGeoKey;
  727 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [4096 0 1 code]];
  728 + end
  729 +
  730 + % Set VerticalCitationGeoKey, 4097
  731 + %
  732 + if isfield(option, 'VerticalCitationGeoKey')
  733 + NumberOfKeys = NumberOfKeys + 1;
  734 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  735 + code = [option.VerticalCitationGeoKey(:); '|']; cnt = length(code);
  736 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [4097 34737 cnt GeoAsciiOffset]];
  737 + GeoAsciiParamsTag = [GeoAsciiParamsTag; code];
  738 + GeoAsciiOffset = GeoAsciiOffset + cnt;
  739 + end
  740 +
  741 + % Set VerticalUnitsGeoKey, 4099
  742 + %
  743 + if isfield(option, 'VerticalUnitsGeoKey')
  744 + NumberOfKeys = NumberOfKeys + 1;
  745 + GeoKeyDirectoryTag(1, 4) = NumberOfKeys;
  746 + code = option.VerticalUnitsGeoKey;
  747 + GeoKeyDirectoryTag = [GeoKeyDirectoryTag; [4099 0 1 code]];
  748 + end
  749 +
  750 + % Set ifd.ImageWidth, 256
  751 + %
  752 + ifd.ImageWidth = size(image, 2);
  753 +
  754 + % Set ifd.ImageLength, 257
  755 + %
  756 + ifd.ImageLength = size(image, 1);
  757 +
  758 + % Set ifd.BitsPerSample, 258
  759 + %
  760 + ifd.BitsPerSample = abs(bit_depth)*ones(size(image,3),1);
  761 +
  762 + % Set ifd.Compression, 259
  763 + %
  764 + ifd.Compression = 1; % Uncompressed
  765 +
  766 + % Set ifd.PhotometricInterpretation, 262
  767 + %
  768 + if isfield(option, 'ColorMap')
  769 + ifd.PhotometricInterpretation = 3; % Palette color
  770 + elseif isfield(option, 'FullColor') & option.FullColor == 1
  771 + ifd.PhotometricInterpretation = 2; % RGB
  772 + else
  773 + ifd.PhotometricInterpretation = 1; % BlackIsZero
  774 + end
  775 +
  776 + % Set ifd.StripOffsets, 273
  777 + %
  778 + ifd.StripOffsets = ones(ifd.ImageLength,1) * ifd.ImageWidth ...
  779 + * abs(bit_depth)/8 * size(image,3); % Num of bytes in a strip
  780 + ifd.StripOffsets = cumsum(ifd.StripOffsets);
  781 + ifd.StripOffsets(end) = [];
  782 + ifd.StripOffsets = [0; ifd.StripOffsets];
  783 + ifd.StripOffsets = ifd.StripOffsets + 8; % 8 bytes before 1st strip
  784 +
  785 + % Set ifd.SamplesPerPixel, 277
  786 + %
  787 + ifd.SamplesPerPixel = size(image, 3); % Gray level intensity
  788 +
  789 + % Set ifd.RowsPerStrip, 278
  790 + %
  791 + ifd.RowsPerStrip = 1; % rows per strip
  792 +
  793 + % Set ifd.StripByteCounts, 279
  794 + %
  795 + ifd.StripByteCounts = ones(ifd.ImageLength,1) * ifd.ImageWidth ...
  796 + * abs(bit_depth)/8 * size(image,3); % Num of bytes in a strip
  797 +
  798 + % Set ifd.XResolution, 282
  799 + %
  800 + ifd.XResolution = 96; % 96 dpi
  801 +
  802 + % Set ifd.YResolution, 283
  803 + %
  804 + ifd.YResolution = 96; % 96 dpi
  805 +
  806 + % Set ifd.PlanarConfiguration, 284
  807 + %
  808 + ifd.PlanarConfiguration = 1; % Chunky
  809 +
  810 + % Set ifd.ResolutionUnit, 296
  811 + %
  812 + ifd.ResolutionUnit = 2; % Inch
  813 +
  814 + % Set ifd.ColorMap, 320
  815 + %
  816 + if isfield(option, 'ColorMap')
  817 + ifd.ColorMap = option.ColorMap(:);
  818 + end
  819 +
  820 + % Set ifd.ExtraSamples, 338
  821 + %
  822 + if ndims(image) > 2
  823 + ifd.ExtraSamples = zeros((size(image,3)-1),1);
  824 + end
  825 +
  826 + % Set ifd.SampleFormat, 339
  827 + %
  828 + switch bit_depth
  829 + case {1, -1}
  830 + ifd.SampleFormat = 4*ones(size(image,3),1); % Undefined
  831 + case {8, -16}
  832 + ifd.SampleFormat = ones(size(image,3),1); % Unsigned integer
  833 + case {16, -32}
  834 + ifd.SampleFormat = 2*ones(size(image,3),1); % Signed integer
  835 + case 32
  836 + ifd.SampleFormat = 3*ones(size(image,3),1); % Floating point
  837 + end
  838 +
  839 + if isfield(ifd, 'ColorMap') & bit_depth == 16
  840 + ifd.SampleFormat = ones(size(image,3),1); % Unsigned integer
  841 + end
  842 +
  843 + if ~isempty(bbox)
  844 +
  845 + % Set gifd.ModelPixelScaleTag, 33550
  846 + %
  847 + if gifd.GTRasterTypeGeoKey == 1
  848 + Sx = (bbox(2) - bbox(1)) / ifd.ImageWidth;
  849 + Sy = (bbox(4) - bbox(3)) / ifd.ImageLength;
  850 + elseif gifd.GTRasterTypeGeoKey == 2
  851 + Sx = (bbox(2) - bbox(1)) / (ifd.ImageWidth-1);
  852 + Sy = (bbox(4) - bbox(3)) / (ifd.ImageLength-1);
  853 + else
  854 + error('Incorrect option.GTRasterTypeGeoKey value');
  855 + end
  856 +
  857 + gifd.ModelPixelScaleTag = [Sx Sy 0];
  858 +
  859 + % Set gifd.ModelTiepointTag, 33922
  860 + %
  861 + RasterTiepoint = [0 0 0];
  862 + ModelTiepoint = [bbox(1) bbox(4) 0];
  863 + gifd.ModelTiepointTag = [RasterTiepoint ModelTiepoint];
  864 + else
  865 + if isfield(option, 'ModelPixelScaleTag')
  866 + gifd.ModelPixelScaleTag = option.ModelPixelScaleTag(:);
  867 + else
  868 +% error('ModelPixelScale is required when your Model Type is not Geographic.');
  869 + end
  870 +
  871 + if isfield(option, 'ModelTiepointTag')
  872 + gifd.ModelTiepointTag = option.ModelTiepointTag(:);
  873 + end
  874 +
  875 + if isfield(option, 'ModelTransformationTag')
  876