Mercurial > hg > octave-lojdl
changeset 17362:0e14b25c5f0f
Merge with main repository after solving conflicts in text renderers code.
author | Andrej Lojdl <andrej.lojdl@gmail.com> |
---|---|
date | Fri, 30 Aug 2013 12:21:22 +0200 |
parents | 4ee5b344a4e3 (current diff) 80bf005cdf8e (diff) |
children | 8a930cffa978 |
files | |
diffstat | 10 files changed, 498 insertions(+), 308 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/corefcn/load-save.cc +++ b/libinterp/corefcn/load-save.cc @@ -1326,6 +1326,8 @@ { for (int i = argv_idx; i < argc; i++) { + if (argv[i] == "") + continue; // Skip empty vars for Matlab compatibility if (! save_vars (os, argv[i], fmt, save_as_floats)) warning ("save: no such variable '%s'", argv[i].c_str ()); }
--- a/libinterp/corefcn/oct-hist.cc +++ b/libinterp/corefcn/oct-hist.cc @@ -755,12 +755,13 @@ @seealso{history_file, history_size, history_timestamp_format_string, history_save}\n\ @end deftypefn") { + octave_value retval; + std::string old_history_control = command_history::histcontrol (); std::string tmp = old_history_control; - octave_value retval = set_internal_variable (tmp, args, nargout, - "history_control"); + retval = set_internal_variable (tmp, args, nargout, "history_control"); if (tmp != old_history_control) command_history::process_histcontrol (tmp); @@ -778,13 +779,15 @@ @seealso{history_file, history_timestamp_format_string, history_save}\n\ @end deftypefn") { + octave_value retval; + int old_history_size = command_history::size (); int tmp = old_history_size; - octave_value retval = set_internal_variable (tmp, args, nargout, - "history_size", -1, - std::numeric_limits<int>::max ()); + retval = set_internal_variable (tmp, args, nargout, + "history_size", -1, + std::numeric_limits<int>::max ()); if (tmp != old_history_size) command_history::set_size (tmp); @@ -803,12 +806,13 @@ @seealso{history_size, history_save, history_timestamp_format_string}\n\ @end deftypefn") { + octave_value retval; + std::string old_history_file = command_history::file (); std::string tmp = old_history_file; - octave_value retval = set_internal_variable (tmp, args, nargout, - "history_file"); + retval = set_internal_variable (tmp, args, nargout, "history_file"); if (tmp != old_history_file) command_history::set_file (tmp); @@ -853,12 +857,13 @@ @seealso{history_control, history_file, history_size, history_timestamp_format_string}\n\ @end deftypefn") { + octave_value retval; + bool old_history_save = ! command_history::ignoring_entries (); bool tmp = old_history_save; - octave_value retval = set_internal_variable (tmp, args, nargout, - "history_save"); + retval = set_internal_variable (tmp, args, nargout, "history_save"); if (tmp != old_history_save) command_history::ignore_entries (! tmp);
--- a/libinterp/corefcn/oct-tex-symbols.in +++ b/libinterp/corefcn/oct-tex-symbols.in @@ -88,12 +88,12 @@ rightarrow 0x2192 0xF0AE Rightarrow 0x21D2 0xF0DE downarrow 0x2193 0xF0AF -circ 0x00B0 0xF0B0 +circ 0x2218 0xF0B0 pm 0x00B1 0xF0B1 geq 0x2265 0xF0B3 propto 0x221D 0xF0B5 partial 0x2202 0xF0B6 -bullet 0x2022 0xF0B7 +bullet 0x2219 0xF0B7 div 0x00F7 0xF0B8 neq 0x2260 0xF0B9 aleph 0x2135 0xF0C0 @@ -108,3 +108,5 @@ 0 0x2205 0xF0C6 mid 0x2223 0xF0BD copyright 0x00A9 0xF0E3 + +deg 0x00B0 0xF0B0
--- a/libinterp/dldfcn/__init_fltk__.cc +++ b/libinterp/dldfcn/__init_fltk__.cc @@ -255,7 +255,7 @@ }; // Parameter controlling how fast we zoom when using the scrool wheel. -static double wheel_zoom_speed = 0.05; +static double Vwheel_zoom_speed = 0.05; // Parameter controlling the GUI mode. static enum { pan_zoom, rotate_zoom, none } gui_mode; @@ -1392,7 +1392,8 @@ // Determine if we're zooming in or out. const double factor = - (Fl::event_dy () > 0) ? 1.0 + wheel_zoom_speed : 1.0 - wheel_zoom_speed; + (Fl::event_dy () > 0) ? 1.0 + Vwheel_zoom_speed + : 1.0 - Vwheel_zoom_speed; // Get the point we're zooming about. double x1, y1; @@ -2128,35 +2129,35 @@ return retval; } -// FIXME -- This function should be abstracted and made potentially +// FIXME: This function should be abstracted and made potentially // available to all graphics toolkits. This suggests putting it in // graphics.cc as is done for drawnow() and having the master // mouse_wheel_zoom function call fltk_mouse_wheel_zoom. The same // should be done for gui_mode and fltk_gui_mode. For now (2011.01.30), // just changing function names and docstrings. -DEFUN_DLD (mouse_wheel_zoom, args, , +DEFUN_DLD (mouse_wheel_zoom, args, nargout, "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {@var{speed} =} mouse_wheel_zoom ()\n\ -@deftypefnx {Built-in Function} {} mouse_wheel_zoom (@var{speed})\n\ +@deftypefn {Loadable Function} {@var{val} =} mouse_wheel_zoom ()\n\ +@deftypefnx {Loadable Function} {@var{old_val} =} mouse_wheel_zoom (@var{new_val})\n\ +@deftypefnx {Loadable Function} {} mouse_wheel_zoom (@var{new_val}, \"local\")\n\ Query or set the mouse wheel zoom factor.\n\ \n\ +The zoom factor is a number in the range (0,1) which is the percentage of the\n\ +current axis limits that will be used when zooming. For example, if the\n\ +current x-axis limits are [0, 50] and @code{mouse_wheel_zoom} is 0.4 (40%),\n\ +then a zoom operation will change the limits by 20.\n\ +\n\ +When called from inside a function with the @qcode{\"local\"} option, the\n\ +variable is changed locally for the function and any subroutines it calls. \n\ +The original variable value is restored when exiting the function.\n\ +\n\ This function is currently implemented only for the FLTK graphics toolkit.\n\ @seealso{gui_mode}\n\ @end deftypefn") { #ifdef HAVE_FLTK - octave_value retval = wheel_zoom_speed; - - if (args.length () == 1) - { - if (args(0).is_real_scalar ()) - wheel_zoom_speed = args(0).double_value (); - else - error ("mouse_wheel_zoom: SPEED must be a real scalar"); - } - - return retval; + return SET_INTERNAL_VARIABLE_WITH_LIMITS(wheel_zoom_speed, 0.0001, 0.9999); #else error ("mouse_wheel_zoom: not available without OpenGL and FLTK libraries"); return octave_value ();
--- a/libinterp/dldfcn/__magick_read__.cc +++ b/libinterp/dldfcn/__magick_read__.cc @@ -44,6 +44,73 @@ #include <Magick++.h> #include <clocale> +// In theory, it should be enough to check the class: +// Magick::ClassType +// PseudoClass: +// Image is composed of pixels which specify an index in a color palette. +// DirectClass: +// Image is composed of pixels which represent literal color values. +// +// GraphicsMagick does not really distinguishes between indexed and +// normal images. After reading a file, it decides itself the optimal +// way to store the image in memory, independently of the how the +// image was stored in the file. That's what ClassType returns. While +// it seems to match the original file most of the times, this is +// not necessarily true all the times. See +// https://sourceforge.net/mailarchive/message.php?msg_id=31180507 +// In addition to the ClassType, there is also ImageType which has a +// type for indexed images (PaletteType and PaletteMatteType). However, +// they also don't represent the original image. Not only does DirectClass +// can have a PaletteType, but also does a PseudoClass have non Palette +// types. +// +// We can't do better without having format specific code which is +// what we are trying to avoid by using a library such as GM. We at +// least create workarounds for the most common problems. +// +// 1) A grayscale jpeg image can report being indexed even though the +// JPEG format has no support for indexed images. We can at least +// fix this one. +static bool +is_indexed (const Magick::Image& img) +{ + bool retval = false; + + if (img.classType () == Magick::PseudoClass && img.magick () != "JPEG") + retval = true; + + return retval; +} + +// The depth from depth() is not always correct for us but seems to be the +// best value we can get. For example, a grayscale png image with 1 bit +// per channel should return a depth of 1 but instead we get 8. +// We could check channelDepth() but then, which channel has the data +// is not straightforward. So we'd have to check all +// the channels and select the highest value. But then, I also +// have a 16bit TIFF whose depth returns 16 (correct), but all of the +// channels gives 8 (wrong). No idea why, maybe a bug in GM? +// Anyway, using depth() seems that only causes problems for binary +// images, and the problem with channelDepth() is not making set them +// all to 1. So we will guess that if all channels have depth of 1, +// then we must have a binary image. +// Note that we can't use AllChannels it doesn't work for this. +// Instead of checking all of the individual channels, we check one +// from RGB, CMYK, grayscale, and transparency. +static octave_idx_type +get_depth (Magick::Image& img) +{ + octave_idx_type depth = img.depth (); + if (depth != 1 + && img.channelDepth (Magick::RedChannel) == 1 + && img.channelDepth (Magick::CyanChannel) == 1 + && img.channelDepth (Magick::OpacityChannel) == 1 + && img.channelDepth (Magick::GrayChannel) == 1) + depth = 1; + + return depth; +} + // We need this in case one of the sides of the image being read has // width 1. In those cases, the type will come as scalar instead of range // since that's the behaviour of the colon operator (1:1:1 will be a scalar, @@ -96,9 +163,30 @@ return region; } +static octave_value_list +read_maps (Magick::Image& img) +{ + // can't call colorMapSize on const Magick::Image + const octave_idx_type mapsize = img.colorMapSize (); + Matrix cmap = Matrix (mapsize, 3); // colormap + Matrix amap = Matrix (mapsize, 3); // alpha map + for (octave_idx_type i = 0; i < mapsize; i++) + { + const Magick::ColorRGB c = img.colorMap (i); + cmap(i,0) = c.red (); + cmap(i,1) = c.green (); + cmap(i,2) = c.blue (); + amap(i,0) = c.alpha (); + } + octave_value_list maps; + maps(0) = cmap; + maps(1) = amap; + return maps; +} + template <class T> static octave_value_list -read_indexed_images (std::vector<Magick::Image>& imvec, +read_indexed_images (const std::vector<Magick::Image>& imvec, const Array<octave_idx_type>& frameidx, const octave_idx_type& nargout, const octave_scalar_map& options) @@ -151,57 +239,36 @@ } retval(0) = octave_value (img); - // Do we need to get the colormap to interpret the image and alpha channel? +// Only bother reading the colormap if it was requested as output. if (nargout > 1) { - const octave_idx_type mapsize = imvec[def_elem].colorMapSize (); - Matrix cmap = Matrix (mapsize, 3); - // In theory, it should be possible for each frame of an image to // have different colormaps but for Matlab compatibility, we only - // return the colormap of the first frame. + // return the colormap of the first frame. To obtain the colormaps + // of different frames, one needs can either use imfinfo or a for + // loop around imread. + const octave_value_list maps = + read_maps (const_cast<Magick::Image&> (imvec[frameidx(def_elem)])); - // only get alpha channel if it exists and was requested as output + retval(1) = maps(0); + + // only interpret alpha channel if it exists and was requested as output if (imvec[def_elem].matte () && nargout >= 3) { - Matrix amap = Matrix (mapsize, 1); - for (octave_idx_type i = 0; i < mapsize; i++) - { - const Magick::ColorRGB c = imvec[def_elem].colorMap (i); - cmap(i,0) = c.red (); - cmap(i,1) = c.green (); - cmap(i,2) = c.blue (); - amap(i,0) = c.alpha (); - } + const Matrix amap = maps(1).matrix_value (); + const double* amap_fvec = amap.fortran_vec (); NDArray alpha (dim_vector (nRows, nCols, 1, nFrames)); - const octave_idx_type nPixels = alpha.numel (); - double* alpha_fvec = alpha.fortran_vec (); - idx = 0; + // GraphicsMagick stores the alpha values inverted, i.e., + // 1 for transparent and 0 for opaque so we fix that here. + const octave_idx_type nPixels = alpha.numel (); for (octave_idx_type pix = 0; pix < nPixels; pix++) - { - // GraphicsMagick stores the alpha values inverted, i.e., - // 1 for transparent and 0 for opaque so we fix that here. - alpha_fvec[idx] = 1 - amap(img(idx), 0); - idx++; - } + alpha_fvec[pix] = 1 - amap_fvec[static_cast<int> (img_fvec[3])]; + retval(2) = alpha; } - - else - { - for (octave_idx_type i = 0; i < mapsize; i++) - { - const Magick::ColorRGB c = imvec[def_elem].colorMap (i); - cmap(i,0) = c.red (); - cmap(i,1) = c.green (); - cmap(i,2) = c.blue (); - } - } - - retval(1) = cmap; } return retval; @@ -689,60 +756,8 @@ } } - // FIXME: the depth here is not always correct for us but seems to be the best - // value we can get. For example, a grayscale png image with 1 bit - // per channel should return a depth of 1 but instead we get 8. - // We could check channelDepth() but then, which channel has the data - // is not straightforward. So we'd have to check all - // the channels and select the highest value. But then, I also - // have a 16bit TIFF whose depth returns 16 (correct), but all of the - // channels gives 8 (wrong). No idea why, maybe a bug in GM? - // Anyway, using depth() seems that only causes problems for binary - // images, and the problem with channelDepth() is not making set them - // all to 1. So we will guess that if all channels have depth of 1, - // then we must have a binary image. - // Note that we can't use AllChannels it doesn't work for this. - // Instead of checking all of the individual channels, we check one - // from RGB, CMYK, grayscale, and transparency. - octave_idx_type depth = imvec[frameidx(0)].depth (); - if (depth != 1 - && imvec[frameidx(0)].channelDepth (Magick::RedChannel) == 1 - && imvec[frameidx(0)].channelDepth (Magick::CyanChannel) == 1 - && imvec[frameidx(0)].channelDepth (Magick::OpacityChannel) == 1 - && imvec[frameidx(0)].channelDepth (Magick::GrayChannel) == 1) - depth = 1; - - // Magick::ClassType - // PseudoClass: - // Image is composed of pixels which specify an index in a color palette. - // DirectClass: - // Image is composed of pixels which represent literal color values. - - Magick::ClassType klass = imvec[frameidx(0)].classType (); - // FIXME: GraphicsMagick does not really distinguishes between indexed and - // normal images. After reading a file, it decides itself the optimal - // way to store the image in memory, independently of the how the - // image was stored in the file. That's what ClassType returns. While - // it seems to match the original file most of the times, this is - // not necessarily true all the times. See - // https://sourceforge.net/mailarchive/message.php?msg_id=31180507 - // In addition to the ClassType, there is also ImageType which has a - // type for indexed images (PaletteType and PaletteMatteType). However, - // they also don't represent the original image. Interestingly, one - // would at least guess that PseudoClass would include only the Palette - // types but that does not happen. - // - // We can't do better without having format specific code which is - // what we are trying to avoid by using a library such as GM. We at - // least create workarounds for the most common problems. - - // 1) A grayscale jpeg image can report being indexed even though the - // JPEG format has no support for indexed images. We can at least - // fix this one. - if (klass == Magick::PseudoClass && imvec[0].magick () == "JPEG") - klass = Magick::DirectClass; - - if (klass == Magick::PseudoClass) + const octave_idx_type depth = get_depth (imvec[frameidx(0)]); + if (is_indexed (imvec[frameidx(0)])) { if (depth <= 1) output = read_indexed_images<boolNDArray> (imvec, frameidx, @@ -1396,82 +1411,173 @@ %!assert (1) */ -#ifdef HAVE_MAGICK +// Gets the minimum information from images such as its size and format. Much +// faster than using imfinfo, which slows down a lot since. Note than without +// this, we need to read the image once for imfinfo to set defaults (which is +// done in Octave language), and then again for the actual reading. +DEFUN_DLD (__magick_ping__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __magick_ping__ (@var{fname}, @var{idx})\n\ +Ping image information with GraphicsMagick or ImageMagick.\n\ +\n\ +This is a private internal function not intended for direct use.\n\ +\n\ +@seealso{imfinfo}\n\ +@end deftypefn") +{ + octave_value retval; +#ifndef HAVE_MAGICK + gripe_disabled_feature ("imfinfo", "Image IO"); +#else + maybe_initialize_magick (); -template<class T> -static octave_value -magick_to_octave_value (const T magick) -{ - return octave_value (magick); + if (args.length () < 1 || ! args(0).is_string ()) + { + print_usage (); + return retval; + } + const std::string filename = args(0).string_value (); + int idx; + if (args.length () > 1) + idx = args(1).int_value () -1; + else + idx = 0; + + Magick::Image img; + img.subImage (idx); + img.subRange (1); + img.ping (filename); + static const char *fields[] = {"rows", "columns", "format", 0}; + octave_scalar_map ping = octave_scalar_map (string_vector (fields)); + ping.setfield ("rows", octave_value (img.rows ())); + ping.setfield ("columns", octave_value (img.columns ())); + ping.setfield ("format", octave_value (img.magick ())); + retval = octave_value (ping); +#endif + return retval; } +#ifdef HAVE_MAGICK static octave_value -magick_to_octave_value (const Magick::EndianType magick) +magick_to_octave_value (const Magick::CompressionType& magick) { switch (magick) { - case Magick::LSBEndian: - return octave_value ("little-endian"); - - case Magick::MSBEndian: - return octave_value ("big-endian"); - + case Magick::NoCompression: + return octave_value ("none"); + case Magick::BZipCompression: + return octave_value ("bzip"); + case Magick::FaxCompression: + return octave_value ("fax3"); + case Magick::Group4Compression: + return octave_value ("fax4"); + case Magick::JPEGCompression: + return octave_value ("jpeg"); + case Magick::LZWCompression: + return octave_value ("lzw"); + case Magick::RLECompression: + // This is named "rle" for the HDF, but the same thing is named + // "ccitt" and "PackBits" for binary and non-binary images in TIFF. + return octave_value ("rle"); + case Magick::ZipCompression: + return octave_value ("deflate"); + case Magick::LZMACompression: + return octave_value ("lzma"); + case Magick::JPEG2000Compression: + return octave_value ("jpeg2000"); + case Magick::JBIG1Compression: + return octave_value ("jbig1"); + case Magick::JBIG2Compression: + return octave_value ("jbig2"); default: return octave_value ("undefined"); } } static octave_value -magick_to_octave_value (const Magick::ResolutionType magick) +magick_to_octave_value (const Magick::EndianType& magick) { switch (magick) { - case Magick::PixelsPerInchResolution: - return octave_value ("pixels per inch"); - - case Magick::PixelsPerCentimeterResolution: - return octave_value ("pixels per centimeter"); - + case Magick::LSBEndian: + return octave_value ("little-endian"); + case Magick::MSBEndian: + return octave_value ("big-endian"); default: return octave_value ("undefined"); } } static octave_value -magick_to_octave_value (const Magick::ImageType magick) +magick_to_octave_value (const Magick::OrientationType& magick) { switch (magick) { - case Magick::BilevelType: - case Magick::GrayscaleType: - case Magick::GrayscaleMatteType: - return octave_value ("grayscale"); + // Values come from the TIFF6 spec + case Magick::TopLeftOrientation: + return octave_value (1); + case Magick::TopRightOrientation: + return octave_value (2); + case Magick::BottomRightOrientation: + return octave_value (3); + case Magick::BottomLeftOrientation: + return octave_value (4); + case Magick::LeftTopOrientation: + return octave_value (5); + case Magick::RightTopOrientation: + return octave_value (6); + case Magick::RightBottomOrientation: + return octave_value (7); + case Magick::LeftBottomOrientation: + return octave_value (8); + default: + return octave_value (1); + } +} - case Magick::PaletteType: - case Magick::PaletteMatteType: - return octave_value ("indexed"); - - case Magick::TrueColorType: - case Magick::TrueColorMatteType: - case Magick::ColorSeparationType: - return octave_value ("truecolor"); - +static octave_value +magick_to_octave_value (const Magick::ResolutionType& magick) +{ + switch (magick) + { + case Magick::PixelsPerInchResolution: + return octave_value ("Inch"); + case Magick::PixelsPerCentimeterResolution: + return octave_value ("Centimeter"); default: return octave_value ("undefined"); } } -// We put this in a try-block because GraphicsMagick will throw -// exceptions if a parameter isn't present in the current image. -#define GET_PARAM(NAME, OUTNAME) \ - try \ - { \ - info.contents (OUTNAME)(frame,0) = magick_to_octave_value (im.NAME ()); \ - } \ - catch (Magick::Warning& w) \ - { \ +// We return a map so this can be used both in imwrite and imfinfo. +static std::map<octave_idx_type, std::string> +disposal_methods () +{ + // GIF Specifications: + // + // Disposal Method - Indicates the way in which the graphic is to + // be treated after being displayed. + // + // 0 - No disposal specified. The decoder is + // not required to take any action. + // 1 - Do not dispose. The graphic is to be left + // in place. + // 2 - Restore to background color. The area used by the + // graphic must be restored to the background color. + // 3 - Restore to previous. The decoder is required to + // restore the area overwritten by the graphic with + // what was there prior to rendering the graphic. + // 4-7 - To be defined. + static std::map<octave_idx_type, std::string> methods; + if (methods.empty ()) + { + methods[0] = "doNotSpecify"; + methods[1] = "leaveInPlace"; + methods[2] = "restoreBG"; + methods[3] = "restorePrevious"; } - + return methods; +} #endif DEFUN_DLD (__magick_finfo__, args, , @@ -1490,7 +1596,6 @@ #ifndef HAVE_MAGICK gripe_disabled_feature ("imfinfo", "Image IO"); #else - maybe_initialize_magick (); if (args.length () < 1 || ! args(0).is_string ()) @@ -1498,117 +1603,184 @@ print_usage (); return retval; } - const std::string filename = args(0).string_value (); - try + std::vector<Magick::Image> imvec; + read_file (filename, imvec); + if (error_state) + return retval; + + // Matlab has different list of fields for each file format. We don't. + static const char *fields[] = { - // Read the file. - std::vector<Magick::Image> imvec; - Magick::readImages (&imvec, args(0).string_value ()); - int nframes = imvec.size (); - - // Create the right size for the output. + // These are fields that must always appear for Matlab. + "Filename", + "FileModDate", + "FileSize", + "Format", + "FormatVersion", + "Width", + "Height", + "BitDepth", + "ColorType", - static const char *fields[] = - { - "Filename", - "FileModDate", - "FileSize", - "Height", - "Width", - "BitDepth", - "Format", - "LongFormat", - "XResolution", - "YResolution", - "TotalColors", - "TileName", - "AnimationDelay", - "AnimationIterations", - "ByteOrder", - "Gamma", - "Matte", - "ModulusDepth", - "Quality", - "QuantizeColors", - "ResolutionUnits", - "ColorType", - "View", - 0 - }; - - octave_map info (dim_vector (nframes, 1), string_vector (fields)); - - file_stat fs (filename); - - std::string filetime; - - if (fs) - { - octave_localtime mtime = fs.mtime (); - - filetime = mtime.strftime ("%e-%b-%Y %H:%M:%S"); - } - else - { - std::string msg = fs.error (); + // These are format specific or not existent in Matlab. The most + // annoying thing is that Matlab may have different names for the + // same thing, in different formats. + "DelayTime", + "DisposalMethod", + "LoopCount", + "ByteOrder", + "Gamma", + "Chromaticities", + "Comment", + "Quality", + "Compression", // same as CompressionType + "Colormap", // same as ColorTable (in PNG) + "Orientation", + "ResolutionUnit", + "XResolution", + "YResolution", + 0 + }; - error ("imfinfo: error reading '%s': %s", - filename.c_str (), msg.c_str ()); - - return retval; - } + // Notes for the future: GM allows to get many attributes, and even has + // attribute() to obtain arbitrary ones, that may be set in only some + // cases. The following is a list of some methods and into what possible + // Matlab value they may be converted. + // + // colorSpace() -> PhotometricInterpretation + // backgroundColor() -> BackgroundColor + // interlaceType() -> Interlaced, InterlaceType, and PlanarConfiguration + // label() -> Title - // For each frame in the image (some images contain multiple - // layers, each to be treated like a separate image). - for (int frame = 0; frame < nframes; frame++) - { - Magick::Image im = imvec[frame]; - - // Add file name and timestamp. - info.contents ("Filename")(frame,0) = filename; - info.contents ("FileModDate")(frame,0) = filetime; + // Create the right size for the output. + const octave_idx_type nFrames = imvec.size (); + octave_map info (dim_vector (nFrames, 1), string_vector (fields)); - // Annoying CamelCase naming is for Matlab compatibility. - GET_PARAM (fileSize, "FileSize") - GET_PARAM (rows, "Height") - GET_PARAM (columns, "Width") - GET_PARAM (depth, "BitDepth") - GET_PARAM (magick, "Format") - GET_PARAM (format, "LongFormat") - GET_PARAM (xResolution, "XResolution") - GET_PARAM (yResolution, "YResolution") - GET_PARAM (totalColors, "TotalColors") - GET_PARAM (tileName, "TileName") - GET_PARAM (animationDelay, "AnimationDelay") - GET_PARAM (animationIterations, "AnimationIterations") - GET_PARAM (endian, "ByteOrder") - GET_PARAM (gamma, "Gamma") - GET_PARAM (matte, "Matte") - GET_PARAM (modulusDepth, "ModulusDepth") - GET_PARAM (quality, "Quality") - GET_PARAM (quantizeColors, "QuantizeColors") - GET_PARAM (resolutionUnits, "ResolutionUnits") - GET_PARAM (type, "ColorType") - GET_PARAM (view, "View") - } + const std::string format (imvec[0].magick ()); + // For each frame in the image (some images contain multiple + // layers, each to be treated like a separate image). So we create + // octave_scalar_map and insert them in the octave_map during the + // loop. Since some fields will never change value, we set the + // template + octave_scalar_map template_info = (string_vector (fields)); + + template_info.setfield ("Format", octave_value (format)); + // We can't actually get FormatVersion but even Matlab sometimes can't. + template_info.setfield ("FormatVersion", octave_value ("")); - retval = octave_value (info); - } - catch (Magick::Warning& w) + const file_stat fs (filename); + if (fs) { - warning ("Magick++ warning: %s", w.what ()); + const octave_localtime mtime (fs.mtime ()); + const std::string filetime = mtime.strftime ("%e-%b-%Y %H:%M:%S"); + template_info.setfield ("Filename", octave_value (filename)); + template_info.setfield ("FileModDate", octave_value (filetime)); + template_info.setfield ("FileSize", octave_value (fs.size ())); } - catch (Magick::ErrorCoder& e) + else { - warning ("Magick++ coder error: %s", e.what ()); - } - catch (Magick::Exception& e) - { - error ("Magick++ exception: %s", e.what ()); + error ("imfinfo: error reading '%s': %s", + filename.c_str (), fs.error ().c_str ()); return retval; } + + std::map<octave_idx_type, std::string> gif_methods = disposal_methods (); + + for (octave_idx_type frame = 0; frame < nFrames; frame++) + { + octave_scalar_map info_frame (template_info); + const Magick::Image img = imvec[frame]; + + info_frame.setfield ("Width", octave_value (img.columns ())); + info_frame.setfield ("Height", octave_value (img.rows ())); + info_frame.setfield ("BitDepth", + octave_value (get_depth (const_cast<Magick::Image&> (img)))); + + // Stuff related to colormap, image class and type + // Because GM is too smart for us... Read the comments in is_indexed() + { + std::string color_type; + Matrix cmap; + if (is_indexed (img)) + { + color_type = "indexed"; + cmap = read_maps (const_cast<Magick::Image&> (img))(0).matrix_value (); + } + else + { + switch (img.type ()) + { + case Magick::BilevelType: + case Magick::GrayscaleType: + case Magick::GrayscaleMatteType: + color_type = "grayscale"; + break; + + case Magick::TrueColorType: + case Magick::TrueColorMatteType: + color_type = "truecolor"; + break; + + case Magick::PaletteType: + case Magick::PaletteMatteType: + // we should never get here or is_indexed needs to be fixed + color_type = "indexed"; + break; + + case Magick::ColorSeparationType: + case Magick::ColorSeparationMatteType: + color_type = "CMYK"; + break; + + default: + color_type = "undefined"; + } + } + info_frame.setfield ("ColorType", octave_value (color_type)); + info_frame.setfield ("Colormap", octave_value (cmap)); + } + + info_frame.setfield ("Gamma", octave_value (img.gamma ())); + { + // Not all images have chroma values. In such cases, they'll + // be all zeros. SO rather than send a matrix of zeros, we will + // check for that, and send an empty vector instead. + RowVector chromaticities (8); + double* chroma_fvec = chromaticities.fortran_vec (); + img.chromaWhitePoint (&chroma_fvec[0], &chroma_fvec[1]); + img.chromaRedPrimary (&chroma_fvec[2], &chroma_fvec[3]); + img.chromaGreenPrimary (&chroma_fvec[4], &chroma_fvec[5]); + img.chromaBluePrimary (&chroma_fvec[6], &chroma_fvec[7]); + if (chromaticities.nnz () == 0) + chromaticities = RowVector (0); + info_frame.setfield ("Chromaticities", octave_value (chromaticities)); + } + + info_frame.setfield ("XResolution", octave_value (img.xResolution ())); + info_frame.setfield ("YResolution", octave_value (img.yResolution ())); + info_frame.setfield ("DelayTime", octave_value (img.animationDelay ())); + info_frame.setfield ("LoopCount", octave_value (img.animationIterations ())); + info_frame.setfield ("Quality", octave_value (img.quality ())); + info_frame.setfield ("Comment", octave_value (img.comment ())); + + info_frame.setfield ("DisposalMethod", + octave_value (format == "GIF"? + gif_methods[img.gifDisposeMethod ()] : "")); + + info_frame.setfield ("Compression", + magick_to_octave_value (img.compressType ())); + info_frame.setfield ("Orientation", + magick_to_octave_value (img.orientation ())); + info_frame.setfield ("ResolutionUnit", + magick_to_octave_value (img.resolutionUnits ())); + info_frame.setfield ("ByteOrder", + magick_to_octave_value (img.endian ())); + + info.fast_elem_insert (frame, info_frame); + } + retval = octave_value (info); #endif return retval; } @@ -1618,8 +1790,6 @@ %!assert (1) */ -#undef GET_PARAM - DEFUN_DLD (__magick_formats__, args, , "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {} __magick_imformats__ (@var{formats})\n\
--- a/scripts/image/imfinfo.m +++ b/scripts/image/imfinfo.m @@ -33,11 +33,14 @@ ## @item Filename ## The full name of the image file. ## +## @item FileModDate +## Date of last modification to the file. +## ## @item FileSize ## Number of bytes of the image on disk ## -## @item FileModDate -## Date of last modification to the file. +## @item Format +## Image format (e.g., @qcode{"jpeg"}). ## ## @item Height ## Image height in pixels. @@ -48,11 +51,9 @@ ## @item BitDepth ## Number of bits per channel per pixel. ## -## @item Format -## Image format (e.g., @qcode{"jpeg"}). -## -## @item LongFormat -## Long form image format description. +## @item ColorType +## Image type. Value is @qcode{"grayscale"}, @qcode{"indexed"}, +## @qcode{"truecolor"}, @qcode{"CMYK"}, or @qcode{"undefined"}. ## ## @item XResolution ## X resolution of the image. @@ -60,19 +61,16 @@ ## @item YResolution ## Y resolution of the image. ## -## @item TotalColors -## Number of unique colors in the image. +## @item ResolutionUnit +## Units of image resolution. Value is @qcode{"Inch"}, +## @qcode{"Centimeter"}, or @qcode{"undefined"}. ## -## @item TileName -## Tile name. -## -## @item AnimationDelay +## @item DelayTime ## Time in 1/100ths of a second (0 to 65535) which must expire before displaying ## the next image in an animated sequence. ## -## @item AnimationIterations -## Number of iterations to loop an animation (e.g., Netscape loop extension) -## for. +## @item LoopCount +## Number of iterations to loop an animation. ## ## @item ByteOrder ## Endian option for formats that support it. Value is @qcode{"little-endian"}, @@ -82,29 +80,35 @@ ## Gamma level of the image. The same color image displayed on two different ## workstations may look different due to differences in the display monitor. ## -## @item Matte -## @code{true} if the image has transparency. +## @item Quality +## JPEG/MIFF/PNG compression level. Value is an integer in the range [0 100]. ## -## @item ModulusDepth -## Image modulus depth (minimum number of bits required to support -## red/green/blue components without loss of accuracy). +## @item DisposalMethod +## Only valid for GIF images, control how successive frames are rendered (how +## the preceding frame is disposed of) when creating a GIF animation. Values +## can be @qcode{"doNotSpecify"}, @qcode{"leaveInPlace"}, @qcode{"restoreBG"}, +## or @qcode{"restorePrevious"}. For non-GIF files, value is an empty string. ## -## @item Quality -## JPEG/MIFF/PNG compression level. +## @item Chromaticities +## Value is a 1x8 Matrix with the x,y chromaticity values for white, red, +## green, and blue points, in that order. ## -## @item QuantizeColors -## Preferred number of colors in the image. -## -## @item ResolutionUnits -## Units of image resolution. Value is @qcode{"pixels per inch"}, -## @qcode{"pixels per centimeter"}, or @qcode{"undefined"}. +## @item Comment +## Image comment. ## -## @item ColorType -## Image type. Value is @qcode{"grayscale"}, @qcode{"indexed"}, -## @qcode{"truecolor"}, or @qcode{"undefined"}. +## @item Compression +## Compression type. Value can be @qcode{"none"}, @qcode{"bzip"}, +## @qcode{"fax3"}, @qcode{"fax4"}, @qcode{"jpeg"}, @qcode{"lzw"}, +## @qcode{"rle"}, @qcode{"deflate"}, @qcode{"lzma"}, @qcode{"jpeg2000"}, +## @qcode{"jbig2"}, @qcode{"jbig2"}, or @qcode{"undefined"}. ## -## @item View -## FlashPix viewing parameters. +## @item Colormap +## Colormap for each image. +## +## @item Orientation +## The orientation of the image with respect to the rows and columns. Value +## is an integer between 1 and 8 as defined in the TIFF 6 specifications, and +## for @sc{Matlab} compatibility. ## @end table ## ## @seealso{imread, imwrite, imshow, imformats}
--- a/scripts/image/imformats.m +++ b/scripts/image/imformats.m @@ -277,7 +277,7 @@ function bool = isa_magick (coder, filename) bool = false; try - info = __imfinfo__ (filename); + info = __magick_ping__ (filename, 1); bool = strcmp (coder, info.Format); end_try_catch endfunction
--- a/scripts/image/imread.m +++ b/scripts/image/imread.m @@ -39,12 +39,17 @@ ## @nospell{MxNx3} matrix. Gray-level and black-and-white images are ## of size @nospell{MxN}. Multipage images will have an additional 4th ## dimension. +## ## The bit depth of the image determines the -## class of the output: @qcode{"uint8"} or @qcode{"uint16"} for gray -## and color, and @qcode{"logical"} for black and white. +## class of the output: @qcode{"uint8"}, @qcode{"uint16"} or @qcode{"single"} +## for gray and color, and @qcode{"logical"} for black and white. ## Note that indexed images always return the indexes for a colormap, ## independent if @var{map} is a requested output. To obtain the actual -## RGB image, use @code{ind2rgb}. +## RGB image, use @code{ind2rgb}. When more than one indexed image is being +## read, @var{map} is obtained from the first. In some rare cases this +## may be incorrect and @code{imfinfo] can be used to obtain the colormap of +## each image. +## ## See the Octave manual for more information in representing images. ## ## Some file formats, such as TIFF and GIF, are able to store multiple
--- a/scripts/image/private/__imread__.m +++ b/scripts/image/private/__imread__.m @@ -92,10 +92,10 @@ try ## Use information from the first image to be read to set defaults. - info = imfinfo (fn)(options.index(1)); + info = __magick_ping__ (fn, options.index(1)); ## Set default for options. - options.region = {1:1:info.Height 1:1:info.Width}; + options.region = {1:1:info.rows 1:1:info.columns}; for idx = offset:2:(numel (varargin) - offset + 1) switch (tolower (varargin{idx})) @@ -120,9 +120,9 @@ floor (options.region{reg_idx}(2)): ... floor (options.region{reg_idx}(3)); endfor - if (options.region{1}(end) > info.Height) + if (options.region{1}(end) > info.rows) error ("imread: end ROWS for PixelRegions option is larger than image height"); - elseif (options.region{2}(end) > info.Width) + elseif (options.region{2}(end) > info.columns) error ("imread: end COLS for PixelRegions option is larger than image width"); endif
--- a/scripts/plot/private/__patch__.m +++ b/scripts/plot/private/__patch__.m @@ -29,6 +29,7 @@ function [h, failed] = __patch__ (p, varargin) + keyboard h = NaN; failed = false; @@ -148,7 +149,7 @@ args{7} = "facecolor"; args{8} = "interp"; args{9} = "cdata"; - agrs{10} = c; + args{10} = c; else error ("patch: color value not valid"); endif