Mercurial > octave-libtiff
view scripts/image/private/__tiff_imwrite__.m @ 31198:93eb0d6e7f62
__tiff_imwrite__: converted to private octave function
* libinterp/corefcn/__tiff__.cc: removed internal function __tiff_imwrite__.
* scripts/image/private/__tiff_imwrite__.m: added private function
__tiff_imwrite__.
* scripts/image/module.mk: added entry for __tiff_imwrite__.m.
author | magedrifaat <magedrifaat@gmail.com> |
---|---|
date | Fri, 02 Sep 2022 03:06:29 +0200 |
parents | |
children | 30b28458bb06 |
line wrap: on
line source
function __tiff_imwrite__ (img, varargin) ## A lot of the input sanitising logic here is copied from ## scripts/image/__imwrite__.m and adapted to the needs of the Tiff ## interface if (nargin < 2 || ! (isnumeric (img) || islogical (img))) print_usage ("imwrite"); endif [filename, ext, map, param_list] = imwrite_filename (varargin{:}); if (isempty (img)) error ("imwrite: invalid empty image"); elseif (issparse (img) || issparse (map)) error ("imwrite: sparse images are not supported"); endif if (rem (numel (param_list), 2) != 0) error ("imwrite: no pair for all arguments (odd number left)"); endif writemode = "w"; compression = Tiff.Compression.None; rows_per_strip = -1; res = [72, 72]; description = ""; alpha = []; for idx = 1:2:numel (param_list) switch (tolower (param_list{idx})) case "alpha" alpha = param_list{idx + 1}; if (! isnumeric (alpha)) error ("imwrite: value for %s option must be a numeric matrix", param_list{idx}); elseif (size (alpha, 3) != 1) error ("imwrite: 3rd dimension of matrix for %s must be singleton", param_list{idx}); elseif (ndims (alpha) > 4 || any (size (alpha)([1 2]) != size (img)([1 2])) || size (alpha, 4) != size (img, 4)) error ("imwrite: matrix for %s must have same dimension as image", param_list{idx}); endif case "colorspace" ## Matlab specifies three colorspaces: RGB, CIELAB and ICCLAB. ## Of the three, only RGB is currently supported so this tag ## can be ignored. case "compression" switch (tolower (param_list{idx + 1})) case "packbits" compression = Tiff.Compression.PackBits; case "lzw" compression = Tiff.Compression.LZW; case "deflate" compression = Tiff.Compression.Deflate; case "jpeg" compression = Tiff.Compression.JPEG; case "ccitt" compression = Tiff.Compression.CCITTRLE; case "fax3" compression = Tiff.Compression.CCITTFax3; case "fax4" compression = Tiff.Compression.CCITTFax4; otherwise error ("imwrite: invalid compression '%s'", compression); endswitch case "description" if (! ischar (param_list{idx + 1})) error ("imwrite: value for %s option must be a string", param_list{idx}); endif description = param_list{idx + 1}; case "resolution" if (! isnumeric (param_list{idx + 1}) || all (numel (param_list) != [1, 2])) error ("imwrite: value for %s option must be either a scalar value or a two-element vector", param_list{idx}); endif resolution = param_list{idx + 1}; if (numel (resolution) == 1) resolution(2) = resolution(1); endif case "rowsperstrip" if (! isnumeric (param_list{idx + 1}) || ! isscalar (param_list{idx + 1})) error ("imwrite: value for %s option must be a numeric scalar", param_list{idx}); endif rows_per_strip = param_list{idx + 1}; case "writemode" if (! ischar (param_list{idx + 1}) || ! any (strcmpi (param_list{idx + 1}, {"append", "overwrite"}))) error ('imwrite: value for %s option must be "append" or "overwrite"', param_list{idx}); endif if (strcmpi (param_list{idx + 1}, {"append"})) writemode = "a"; endif otherwise error ("imwrite: invalid PARAMETER '%s'", param_list{idx}); endswitch endfor if (! isempty (map)) if (! iscolormap (map)) error ("imwrite: invalid MAP for indexed image"); elseif (ndims (img) != 2) error ("imwrite: indexed image must have 2 (found %i)", ndims (img)); endif ## If the image is floating point, then we convert it to integer because ## it represents indices of the color map which must be integers. Also, ## if it's floating point, it has an offset of 1 if (isfloat (img)) if (rows (map) <= 256) img = uint8 (img - 1); else img = uint16 (img - 1); endif endif ## Fill in the colormap as required with rgb (0, 0, 0) nColors = rows (map); if (islogical (img)) required_colors = 2; else required_colors = double (intmax (class (img))) + 1; endif if (nColors < required_colors) warning ("imwrite: MAP has not enough colors. Filling with black"); map(nColors+1:required_colors,:) = 0; endif endif if (ndims (img) > 4) error ("imwrite: invalid %d-dimensional image data", ndims (img)); elseif (all (size (img, 3) != [1 3 4])) ## 1, 3, or 4 for grayscle, RGB, and CMYK respectively error ("imwrite: IMG 3rd dimension must be 1, 3, or 4"); endif ## Matlab specifies that JPEG compression must also specify RowsPerStrip ## and must be a value divisible by 8 if (compression == Tiff.Compression.JPEG && (rows_per_strip == -1 || rem (rows_per_strip, 8) != 0)) error ("imwrite: RowsPerStrip option must be specified for jpeg compression and must be divisible by 8"); endif ## These compression schemes are only available for binary images if (! (islogical (img)) && any (compression == [Tiff.Compression.CCITTRLE, Tiff.Compression.CCITTFax3, Tiff.Compression.CCITTFax4])) error ("imwrite: the specified compression scheme is for binary images only"); endif ## Set the image tag data tags.ImageLength = size (img, 1); tags.ImageWidth = size (img, 2); ## See if SamplesPerPixel should account for the alpha channel if (! isempty (alpha)) tags.SamplesPerPixel = size (img, 3) + 1; tags.ExtraSamples = Tiff.ExtraSamples.AssociatedAlpha; else tags.SamplesPerPixel = size (img, 3); endif tags.PlanarConfiguration = Tiff.PlanarConfiguration.Chunky; tags.Compression = compression; tags.XResolution = res(1); tags.YResolution = res(2); tags.ImageDescription = description; tags.BitsPerSample = infer_bitdepth (class (img)); ## Infer the photometric interpretation of the image from the color map ## and the number of channels of the input tags.Photometric = Tiff.Photometric.MinIsBlack; if (! isempty (map)) tags.Photometric = Tiff.Photometric.Palette; tags.ColorMap = map; elseif (size(img, 3) == 3) tags.Photometric = Tiff.Photometric.RGB; elseif (size(img, 3) == 4) tags.Photometric = Tiff.Photometric.CMYK; endif ## Set the correct sample format for floating-point and signed types if (isfloat (img)) tags.SampleFormat = Tiff.SampleFormat.IEEEFP; elseif (any (strcmp (class (img), {"int8", "int16", "int32"}))) tags.SampleFormat = Tiff.SampleFormat.Int; endif ## Add the alpha channel to the image data if (! isempty (alpha)) img = cat (3, img, alpha); endif tif = Tiff (filename, writemode); for dir_idx = 1:size(img, 4) tif.setTag (tags); ## Try to get a reasonable size for RowsPerStrip if not set ## This must be done after the other tags are set so LibTIFF ## can make an informed calculation. % if (rows_per_strip == -1) % rows_per_strip = tif.getDefaultStripLength (); % endif if (rows_per_strip != -1) tif.setTag (Tiff.TagID.RowsPerStrip, rows_per_strip); endif tif.write (img(:,:,:, dir_idx)); tif.writeDirectory (); endfor tif.close (); endfunction function bitdepth = infer_bitdepth (img_class) switch (img_class) case "logical" bitdepth = 1; case {"int8", "uint8"} bitdepth = 8; case {"int16", "uint16"} bitdepth = 16; case {"int32", "uint32", "single"} bitdepth = 32; case "double" bitdepth = 64; otherwise error ("imwrite: Unsupported data type for image data"); endswitch endfunction