comparison libinterp/dldfcn/__magick_read__.cc @ 17855:bfbe5dcc9943

imwrite: implement DisposalMethod option. * __magick_read__.cc (F__magick_write__): set gifDisposeMethod() when writing an image to implement the DisposalMethod option. Set all the options in a single option rather than a loop per option. (init_reverse_disposal_methods): new method to return a reversed std::map of the disposal methods. (init_disposal_methods): move up, to be closer to the new init_reverse_disposal_methods() * private/__imwrite__.m: input check for the new option DisposalMethod and set its default. * imwrite.m: document new option.
author Carnë Draug <carandraug@octave.org>
date Tue, 05 Nov 2013 07:05:30 +0000
parents adb0ba0d0c13
children 870f3e12e163
comparison
equal deleted inserted replaced
17854:adb0ba0d0c13 17855:bfbe5dcc9943
1250 error ("__magick_write__: unrecognized Magick::ImageType"); 1250 error ("__magick_write__: unrecognized Magick::ImageType");
1251 return; 1251 return;
1252 } 1252 }
1253 } 1253 }
1254 return; 1254 return;
1255 }
1256
1257 // Meant to be shared with both imfinfo and imwrite.
1258 static std::map<octave_idx_type, std::string>
1259 init_disposal_methods ()
1260 {
1261 // GIF Specifications:
1262 //
1263 // Disposal Method - Indicates the way in which the graphic is to
1264 // be treated after being displayed.
1265 //
1266 // 0 - No disposal specified. The decoder is
1267 // not required to take any action.
1268 // 1 - Do not dispose. The graphic is to be left
1269 // in place.
1270 // 2 - Restore to background color. The area used by the
1271 // graphic must be restored to the background color.
1272 // 3 - Restore to previous. The decoder is required to
1273 // restore the area overwritten by the graphic with
1274 // what was there prior to rendering the graphic.
1275 // 4-7 - To be defined.
1276 static std::map<octave_idx_type, std::string> methods;
1277 if (methods.empty ())
1278 {
1279 methods[0] = "doNotSpecify";
1280 methods[1] = "leaveInPlace";
1281 methods[2] = "restoreBG";
1282 methods[3] = "restorePrevious";
1283 }
1284 return methods;
1285 }
1286 static std::map<std::string, octave_idx_type>
1287 init_reverse_disposal_methods ()
1288 {
1289 static std::map<std::string, octave_idx_type> methods;
1290 if (methods.empty ())
1291 {
1292 methods["donotspecify"] = 0;
1293 methods["leaveinplace"] = 1;
1294 methods["restorebg"] = 2;
1295 methods["restoreprevious"] = 3;
1296 }
1297 return methods;
1255 } 1298 }
1256 1299
1257 void static 1300 void static
1258 write_file (const std::string& filename, 1301 write_file (const std::string& filename,
1259 const std::string& ext, 1302 const std::string& ext,
1382 { 1425 {
1383 error ("__magick_write__: indexed image must be uint8, uint16 or float."); 1426 error ("__magick_write__: indexed image must be uint8, uint16 or float.");
1384 return retval; 1427 return retval;
1385 } 1428 }
1386 } 1429 }
1430 static std::map<std::string, octave_idx_type> disposal_methods
1431 = init_reverse_disposal_methods ();
1387 1432
1388 const octave_idx_type nFrames = imvec.size (); 1433 const octave_idx_type nFrames = imvec.size ();
1389 1434
1390 const octave_idx_type quality = options.getfield ("quality").int_value (); 1435 const octave_idx_type quality = options.getfield ("quality").int_value ();
1436 const ColumnVector delaytime = options.getfield ("delaytime").column_vector_value ();
1437 const Array<std::string> disposalmethod = options.getfield ("disposalmethod").cellstr_value ();
1391 for (octave_idx_type i = 0; i < nFrames; i++) 1438 for (octave_idx_type i = 0; i < nFrames; i++)
1392 imvec[i].quality (quality); 1439 {
1393 1440 imvec[i].quality (quality);
1394 const ColumnVector delaytime = options.getfield ("delaytime").column_vector_value (); 1441 imvec[i].animationDelay (delaytime(i));
1395 for (octave_idx_type i = 0; i < nFrames; i++) 1442 imvec[i].gifDisposeMethod (disposal_methods[disposalmethod(i)]);
1396 imvec[i].animationDelay (delaytime(i)); 1443 }
1397 1444
1398 // If writemode is set to append, read the image and append to it. Even 1445 // If writemode is set to append, read the image and append to it. Even
1399 // if set to append, make sure that something was read at all. 1446 // if set to append, make sure that something was read at all.
1400 const std::string writemode = options.getfield ("writemode").string_value (); 1447 const std::string writemode = options.getfield ("writemode").string_value ();
1401 if (writemode == "append" && file_stat (filename).exists ()) 1448 if (writemode == "append" && file_stat (filename).exists ())
1409 ini_imvec.insert (ini_imvec.end (), imvec.begin (), imvec.end ()); 1456 ini_imvec.insert (ini_imvec.end (), imvec.begin (), imvec.end ());
1410 ini_imvec.swap (imvec); 1457 ini_imvec.swap (imvec);
1411 } 1458 }
1412 } 1459 }
1413 1460
1414 // FIXME - LoopCount or animationIterations 1461 // FIXME - LoopCount or animationIterations
1415 // How it should work: 1462 // How it should work:
1416 // 1463 //
1417 // This value is only set for the first image in the sequence. Trying 1464 // This value is only set for the first image in the sequence. Trying
1418 // to set this value with the append mode should have no effect, the 1465 // to set this value with the append mode should have no effect, the
1419 // value used with the first image is the one that counts (that would 1466 // value used with the first image is the one that counts (that would
1420 // also be Matlab compatible). Thus, the right way to do this would be 1467 // also be Matlab compatible). Thus, the right way to do this would be
1421 // to have an else block on the condition above, and set this only 1468 // to have an else block on the condition above, and set this only
1422 // when creating a new file. Since Matlab does not interpret a 4D 1469 // when creating a new file. Since Matlab does not interpret a 4D
1423 // matrix as sequence of images to write, its users need to use a for 1470 // matrix as sequence of images to write, its users need to use a for
1424 // loop and set LoopCount only on the first iteration (it actually 1471 // loop and set LoopCount only on the first iteration (it actually
1425 // throws warnings otherwise) 1472 // throws warnings otherwise)
1426 // 1473 //
1427 // Why is this not done the right way: 1474 // Why is this not done the right way:
1428 // 1475 //
1429 // When GM saves a single image, it discards the value if there is only 1476 // When GM saves a single image, it discards the value if there is only
1430 // a single image and sets it to "no loop". Since our default is an 1477 // a single image and sets it to "no loop". Since our default is an
1431 // infinite loop, if the user tries to do it the Matlab way (setting 1478 // infinite loop, if the user tries to do it the Matlab way (setting
1432 // LoopCount only on the first image) that value will go nowhere. 1479 // LoopCount only on the first image) that value will go nowhere.
1433 // See https://sourceforge.net/p/graphicsmagick/bugs/248/ 1480 // See https://sourceforge.net/p/graphicsmagick/bugs/248/
1434 // Because of this, we document to set LoopCount on every iteration 1481 // Because of this, we document to set LoopCount on every iteration
1435 // (in Matlab will cause a lot of warnings), or pass a 4D matrix with 1482 // (in Matlab will cause a lot of warnings), or pass a 4D matrix with
1436 // all frames (won't work in Matlab at all). 1483 // all frames (won't work in Matlab at all).
1437 // Note that this only needs to be set on the first frame 1484 // Note that this only needs to be set on the first frame
1438 imvec[0].animationIterations (options.getfield ("loopcount").uint_value ()); 1485 imvec[0].animationIterations (options.getfield ("loopcount").uint_value ());
1439 1486
1440 write_file (filename, ext, imvec); 1487 write_file (filename, ext, imvec);
1441 if (error_state) 1488 if (error_state)
1442 return retval; 1489 return retval;
1443 1490
1604 case Magick::PixelsPerCentimeterResolution: 1651 case Magick::PixelsPerCentimeterResolution:
1605 return octave_value ("Centimeter"); 1652 return octave_value ("Centimeter");
1606 default: 1653 default:
1607 return octave_value ("undefined"); 1654 return octave_value ("undefined");
1608 } 1655 }
1609 }
1610
1611 // Meant to be shared with both imfinfo and imwrite.
1612 static std::map<octave_idx_type, std::string>
1613 init_disposal_methods ()
1614 {
1615 // GIF Specifications:
1616 //
1617 // Disposal Method - Indicates the way in which the graphic is to
1618 // be treated after being displayed.
1619 //
1620 // 0 - No disposal specified. The decoder is
1621 // not required to take any action.
1622 // 1 - Do not dispose. The graphic is to be left
1623 // in place.
1624 // 2 - Restore to background color. The area used by the
1625 // graphic must be restored to the background color.
1626 // 3 - Restore to previous. The decoder is required to
1627 // restore the area overwritten by the graphic with
1628 // what was there prior to rendering the graphic.
1629 // 4-7 - To be defined.
1630 static std::map<octave_idx_type, std::string> methods;
1631 if (methods.empty ())
1632 {
1633 methods[0] = "doNotSpecify";
1634 methods[1] = "leaveInPlace";
1635 methods[2] = "restoreBG";
1636 methods[3] = "restorePrevious";
1637 }
1638 return methods;
1639 } 1656 }
1640 1657
1641 static bool 1658 static bool
1642 is_valid_exif (const std::string& val) 1659 is_valid_exif (const std::string& val)
1643 { 1660 {