milena r1109: improving PNM format support

URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena ChangeLog: 2007-09-14 Matthieu Garrigues <garrigues@lrde.epita.fr> improving PNM format support * img/test.fits: a fits image * mln/io/internal: The functions to save and load ppm, pbm and pgm format looked quite similar. I add this directory to factorise all these similarities * mln/io/internal/abort.hh: the abort function used in loading functions * mln/io/internal/pnm/load.hh: functions to load pnm files, 8 or 16 bits. * mln/io/internal/pnm/load_header.hh: function to read a pnm header. * mln/io/internal/pnm/macros.hh: Some macros to identify the magic numbers of the formats * mln/io/internal/pnm/save.hh: functions to load pnm files, 8 or 16 bits. * mln/io/internal/pnm/save_header.hh: function to save a pnm header. * mln/io/internal/pnm: all internal treatments of pnm format, used by concrete formats (pbm, pgm, ppm) * mln/io/pbm/load.hh: loading of pbm format done * mln/io/pbm/save.hh: saving of pbm format done * mln/io/pfm/load.hh: loading of pfm format done * mln/io/pgm/load.hh: loading of pgm format done * mln/io/pgm/save.hh: saving of pgm 8/16 bits format done * mln/io/ppm/load.hh: loading of ppm 8/16 bits format done * mln/io/ppm/save.hh: loading of ppm 8/16 bits format done * mln/value/rgb.hh: To fix : we can't apply level:transform on rgb images convert_< rgb8 > could be one part of the problem. * mln/value/rgb16.hh: add rgb16 type to test ppm 16bits * tests/io_pbm.cc: some tests * tests/io_pgm.cc: some tests * tests/io_ppm16.cc: some tests --- 1109) |binary trunk/milena/mln/io/internal/abort.hh | 53 +++++++ trunk/milena/mln/io/internal/pnm/load.hh | 179 ++++++++++++++++++++++++ trunk/milena/mln/io/internal/pnm/load_header.hh | 120 ++++++++++++++++ trunk/milena/mln/io/internal/pnm/macros.hh | 49 ++++++ trunk/milena/mln/io/internal/pnm/save.hh | 162 +++++++++++++++++++++ trunk/milena/mln/io/internal/pnm/save_header.hh | 86 +++++++++++ trunk/milena/mln/io/pbm/load.hh | 74 --------- trunk/milena/mln/io/pbm/save.hh | 55 ------- trunk/milena/mln/io/pfm/load.hh | 1 trunk/milena/mln/io/pgm/load.hh | 142 ------------------- trunk/milena/mln/io/pgm/save.hh | 57 ------- trunk/milena/mln/io/ppm/load.hh | 148 ------------------- trunk/milena/mln/io/ppm/save.hh | 83 ----------- trunk/milena/mln/value/rgb.hh | 40 ++++- trunk/milena/mln/value/rgb16.hh | 55 +++++++ trunk/milena/tests/io_pbm.cc | 30 ---- trunk/milena/tests/io_pgm.cc | 10 - trunk/milena/tests/io_ppm16.cc | 110 ++++++++++++++ 19 files changed, 872 insertions(+), 582 deletions(-) Index: trunk/milena/tests/io_pbm.cc =================================================================== --- trunk/milena/tests/io_pbm.cc (revision 1108) +++ trunk/milena/tests/io_pbm.cc (revision 1109) @@ -31,43 +31,13 @@ */ #include <mln/core/image2d_b.hh> -#include <mln/core/win/rectangle2d.hh> - -#include <mln/value/int_u8.hh> -#include <mln/value/int_u16.hh> -#include <mln/value/rgb8.hh> - -#include <mln/io/pgm/load.hh> -#include <mln/io/pgm/save.hh> #include <mln/io/pbm/load.hh> #include <mln/io/pbm/save.hh> -#include <mln/io/ppm/save.hh> - -#include <mln/level/transform.hh> - - - -struct binarise : mln::Function_v2v<binarise> -{ - typedef bool result; - result operator()(unsigned int v) const - { - if (v > 127) - return false; - else - return true; - } -}; int main() { using namespace mln; - using value::int_u8; - using value::rgb8; - - win::rectangle2d rect(51, 51); - border::thickness = 52; image2d_b< bool > lena = io::pbm::load("../img/lena.pbm"); Index: trunk/milena/tests/io_pgm.cc =================================================================== --- trunk/milena/tests/io_pgm.cc (revision 1108) +++ trunk/milena/tests/io_pgm.cc (revision 1109) @@ -37,7 +37,6 @@ #include <mln/io/pgm/load.hh> #include <mln/io/pgm/save.hh> -#include <mln/io/ppm/save.hh> int main() { @@ -45,12 +44,11 @@ using value::int_u8; using value::rgb8; - { - image2d_b<rgb8> - lena = io::pgm::load<rgb8>("../img/lena.pgm"); + // { + // // image2d_b<rgb8> + // // lena = io::pgm::load<rgb8>("../img/lena.pgm"); + // } - //io::pgm::save(lena, "out.pgm"); - } { image2d_b<int_u8> lena = io::pgm::load<int_u8>("../img/lena.pgm"); Index: trunk/milena/tests/io_ppm16.cc =================================================================== --- trunk/milena/tests/io_ppm16.cc (revision 0) +++ trunk/milena/tests/io_ppm16.cc (revision 1109) @@ -0,0 +1,110 @@ +// Copyright (C) 2007 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +/*! \file tests/pbm_load.cc + * + * \brief Test on mln::io::pbm::load for 16bits ppm + */ + +#include <mln/core/image2d_b.hh> +#include <mln/core/win/rectangle2d.hh> + +#include <mln/value/rgb8.hh> +#include <mln/value/rgb16.hh> + +#include <mln/io/ppm/load.hh> +#include <mln/io/ppm/save.hh> + +#include <mln/level/compare.hh> + + +using namespace mln; + +struct to16bits : mln::Function_v2v<to16bits> +{ + + typedef value::rgb16 result; + result operator()(value::rgb8 v) const + { + result ret(v.red().to_enc() * 256, + v.green().to_enc() * 256, + v.blue().to_enc() * 256); + return ret; + } +}; + +struct to8bits : mln::Function_v2v<to8bits> +{ + + typedef value::rgb8 result; + result operator()(value::rgb16 v) const + { + result ret(v.red().to_enc() / 256, + v.green().to_enc() / 256, + v.blue().to_enc() / 256); + return ret; + } +}; + +int main() +{ + using namespace mln; + using value::rgb8; + using value::rgb16; + + typedef image2d_b<rgb8> I; + + + // load a 8bits image A + image2d_b<rgb8> + a = io::ppm::load<rgb8>("../img/lena.ppm"); + image2d_b<rgb16> b(a.domain()); + + image2d_b<rgb8>::fwd_piter p(b.domain()); + + // save it as a 16bits ppm image B + to16bits f; + for_all(p) + b(p) = f(a(p)); + io::ppm::save(b, "out16.ppm"); + + // reload B into C + image2d_b<rgb16> + c = io::ppm::load<rgb16>("out16.ppm"); + image2d_b<rgb8> d(a.domain()); + + + // save C as a 8bits ppm image D + to8bits g; + for_all(p) + d(p) = g(c(p)); + io::ppm::save(d, "out8.ppm"); + + // D should equals A + mln_assertion(d == a); + +} Index: trunk/milena/mln/io/pfm/load.hh =================================================================== --- trunk/milena/mln/io/pfm/load.hh (revision 1108) +++ trunk/milena/mln/io/pfm/load.hh (revision 1109) @@ -120,7 +120,6 @@ << "' not found!"; abort(); } - char type; int nrows, ncols; internal::read_pfm_header(file, nrows, ncols); Index: trunk/milena/mln/io/pgm/save.hh =================================================================== --- trunk/milena/mln/io/pgm/save.hh (revision 1108) +++ trunk/milena/mln/io/pgm/save.hh (revision 1109) @@ -32,6 +32,8 @@ # include <iostream> # include <fstream> +# include <mln/io/internal/pnm/save.hh> + # include <mln/geom/size2d.hh> # include <mln/metal/equal.hh> # include <mln/metal/bexpr.hh> @@ -63,64 +65,13 @@ { template <typename I> - void save_header_(const I& ima, const std::string& filename, - std::ofstream& file) - { - if (! file) - { - std::cerr << "error: cannot open file '" << filename - << "'!"; - abort(); - } - file << "P5" << std::endl; - file << "# milena" << std::endl; - file << geom::ncols(ima) << ' ' << geom::nrows(ima) << std::endl; - file << mln_max(mln_value(I)) << std::endl; - } - - template <typename I> - void save_(const Fast_Image<I>& ima_, const std::string& filename) - { - std::cout << "testestse" ; - const I& ima = exact(ima_); - std::ofstream file(filename.c_str()); - save_header_(ima, filename, file); - const int - min_row = geom::min_row(ima), - max_row = geom::max_row(ima); - point2d p; - -// FIXME : ask theo if I can remove this else -// if (sizeof(mln_value(I)) <= 2) -// { - p.col() = geom::min_col(ima); - size_t len = geom::ncols(ima) * sizeof(mln_value(I)); - for (p.row() = min_row; p.row() <= max_row; ++p.row()) - file.write((char*)(& ima(p)), len); -// } -// else -// { -// // FIXME: code for g++-2.95 when sizeof(int_u8) == 2!!! -// const int -// min_col = geom::min_col(ima), -// max_col = geom::max_col(ima); -// for (p.row() = min_row; p.row() <= max_row; ++p.row()) -// for (p.col() = min_col; p.col() <= max_col; ++p.col()) -// { -// unsigned char c = ima(p); -// file.write((char*)(&c), 1); -// } -// } - } - - template <typename I> void save_(const Image<I>& ima_, const std::string& filename) { typedef typename I::value::enc T; const I& ima = exact(ima_); std::ofstream file(filename.c_str()); - save_header_(ima, filename, file); + io::internal::pnm::save_header(5, ima, filename, file); const int min_row = geom::min_row(ima), max_row = geom::max_row(ima), @@ -153,7 +104,7 @@ > > >::check(); - impl::save_(exact(ima), filename); + io::internal::pnm::save(PGM, exact(ima), filename); } # endif // ! MLN_INCLUDE_ONLY Index: trunk/milena/mln/io/pgm/load.hh =================================================================== --- trunk/milena/mln/io/pgm/load.hh (revision 1108) +++ trunk/milena/mln/io/pgm/load.hh (revision 1109) @@ -36,6 +36,8 @@ # include <mln/core/image2d_b.hh> # include <mln/value/int_u8.hh> +# include <mln/io/internal/pnm/load.hh> + namespace mln { @@ -46,148 +48,10 @@ namespace pgm { - namespace internal - { - - void abort() - { - std::cerr << " aborting." << std::endl; - exit(0); - } - - bool read_pnm_header(std::istream& istr, - char& type, - int& nrows, int& ncols, - bool test = false) - { - // check magic - if (istr.get() != 'P' ) - goto err; - type = istr.get(); - if (type < '1' || type > '6') - goto err; - if (istr.get() != '\n') - goto err; - - // skip comments - while (istr.peek() == '#') - { - std::string line; - std::getline(istr, line); - } - - // get size - istr >> ncols >> nrows; - if (nrows <= 0 || ncols <= 0) - goto err; - - // skip maxvalue - if (istr.get() != '\n') - goto err; - if (type != '1' && type != '4') - { - std::string line; - std::getline(istr, line); - } - return true; - - err: - if (! test) - { - std::cerr << "error: badly formed header!"; - abort(); - } - return false; - } - - void read_pnm_header(char ascii, char raw, - std::istream& istr, - char& type, - int& nrows, int& ncols) - { - read_pnm_header(istr, type, nrows, ncols); - if (! (type == ascii || type == raw)) - { - std::cerr << "error: bad pnm type; " - << "expected P" << ascii - << " or P" << raw - << ", get P" << type << "!"; - abort(); - } - } - - - /// load_ascii. - template <typename I> - void load_ascii(std::ifstream& file, I& ima) - { - mln_fwd_piter(I) p(ima.domain()); - for_all(p) - { - unsigned value; - file >> value; - ima(p) = value; - // FIXME: Test alt code below. - // file >> ima(p); - } - } - - - /// load_raw_2d. - template <typename I> - void load_raw_2d(std::ifstream& file, I& ima) - { - point2d p = make::point2d(0, ima.domain().pmin().col()); - typedef mln_value(I) V; - const mln_coord(I) - min_row = geom::min_row(ima), - max_row = geom::max_row(ima); - if (sizeof(V) <= 2) - { - size_t len = geom::ncols(ima) * sizeof(mln_enc(V)); - for (p.row() = min_row; p.row() <= max_row; ++p.row()) - file.read((char*)(& ima(p)), len); - } - else - { - // FIXME: code for g++-2.95 when sizeof(int_u8) == 2!!! - const mln_coord(I) - min_col = geom::min_col(ima), - max_col = geom::max_col(ima); - for (p.row() = min_row; p.row() <= max_row; ++p.row()) - for (p.col() = min_col; p.col() <= max_col; ++p.col()) - { - unsigned char c; - file.read((char*)(&c), 1); - ima(p) = c; - } - } - } - - - } // end of namespace mln::io::internal - template <typename V> image2d_b<V> load(const std::string& filename) { - std::ifstream file(filename.c_str()); - if (! file) - { - std::cerr << "error: file '" << filename - << "' not found!"; - abort(); - } - char type; - int nrows, ncols; - internal::read_pnm_header('2', '5', file, type, nrows, ncols); - - image2d_b<V> ima(nrows, ncols); - if (type == '5') - internal::load_raw_2d(file, ima); - else - if (type == '2') - internal::load_ascii(file, ima); - return ima; + return io::internal::pnm::load<V>(PGM, filename); } image2d_b<value::int_u8> load(const std::string& filename) Index: trunk/milena/mln/io/internal/abort.hh =================================================================== --- trunk/milena/mln/io/internal/abort.hh (revision 0) +++ trunk/milena/mln/io/internal/abort.hh (revision 1109) @@ -0,0 +1,53 @@ +// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 EPITA +// Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_IO_ABORT_HH +# define MLN_IO_ABORT_HH + +namespace mln +{ + + namespace io + { + + namespace internal + { + + void abort() + { + std::cerr << " aborting." << std::endl; + exit(0); + } + + } // end of namespace mln::io::internal + + } // end of namespace mln::io + +} // end of namespace mln + +#endif // ! MLN_IO_ABORT_HH Index: trunk/milena/mln/io/internal/pnm/macros.hh =================================================================== --- trunk/milena/mln/io/internal/pnm/macros.hh (revision 0) +++ trunk/milena/mln/io/internal/pnm/macros.hh (revision 1109) @@ -0,0 +1,49 @@ +// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 EPITA +// Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_IO_PNM_MACROS_HH +# define MLN_IO_PNM_MACROS_HH + +/*! \file mln/io/internal/pnm/macros.hh + * + * \brief Definition of pnm formats macros. + */ + +/// Portable Pixel Map Format +# define PPM '6' +# define PPM_ASCII '3' + +/// Portable Gray Map Format +# define PGM '5' +# define PGM_ASCII '2' + +/// Portable Bit Map Format +# define PBM '4' +# define PBM_ASCII '1' + +#endif // ! MLN_IO_PNM_LOAD_HH Index: trunk/milena/mln/io/internal/pnm/save_header.hh =================================================================== --- trunk/milena/mln/io/internal/pnm/save_header.hh (revision 0) +++ trunk/milena/mln/io/internal/pnm/save_header.hh (revision 1109) @@ -0,0 +1,86 @@ +// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 EPITA +// Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_IO_PNM_SAVE_HEADER_HH +# define MLN_IO_PNM_SAVE_HEADER_HH + +# include <iostream> +# include <fstream> + +namespace mln +{ + + namespace io + { + + namespace internal + { + +# ifndef MLN_INCLUDE_ONLY + + namespace pnm + { + + template <typename I> + void save_header(const char type, + const I& ima, const std::string& filename, + std::ofstream& file) + { + if (! file) + { + std::cerr << "error: cannot open file '" << filename + << "'!"; + abort(); + } + file << "P" << type << std::endl; + file << "# milena" << std::endl; + file << geom::ncols(ima) << ' ' << geom::nrows(ima) << std::endl; + } + + template <typename I> + void save_header(const char type, const int maxval, + const I& ima, const std::string& filename, + std::ofstream& file) + { + save_header(type, ima, filename, file); + file << maxval << std::endl; + } + + } // end of namespace mln::io::internal::pnm + + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::internal + + } // end of namespace mln::io + +} // end of namespace mln + + +#endif // ! MLN_IO_PNM_SAVE_HEADER_HH Index: trunk/milena/mln/io/internal/pnm/load_header.hh =================================================================== --- trunk/milena/mln/io/internal/pnm/load_header.hh (revision 0) +++ trunk/milena/mln/io/internal/pnm/load_header.hh (revision 1109) @@ -0,0 +1,120 @@ +// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 EPITA +// Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_IO_PNM_LOAD_HEADER_HH +# define MLN_IO_PNM_LOAD_HEADER_HH + +# include <iostream> +# include <fstream> +# include <string> + +namespace mln +{ + + namespace io + { + + namespace internal + { + + namespace pnm + { + + + bool read_header(std::istream& istr, + char& type, + int& nrows, int& ncols, + bool test = false) + { + // check magic + if (istr.get() != 'P' ) + goto err; + type = istr.get(); + + if (type < '1' || type > '6') + goto err; + if (istr.get() != '\n') + goto err; + + // skip comments + while (istr.peek() == '#') + { + std::string line; + std::getline(istr, line); + } + + // get size + istr >> ncols >> nrows; + if (nrows <= 0 || ncols <= 0) + goto err; + + // skip maxvalue + if (istr.get() != '\n') + goto err; + if (type != '1' && type != '4') + { + std::string line; + std::getline(istr, line); + } + return true; + + err: + if (! test) + { + std::cerr << "error: badly formed header!"; + abort(); + } + return false; + } + + void read_header(char ascii, char raw, + std::istream& istr, + char& type, + int& nrows, int& ncols) + { + read_header(istr, type, nrows, ncols); + if (! (type == ascii || type == raw)) + { + std::cerr << "error: bad pnm type; " + << "expected P" << ascii + << " or P" << raw + << ", get P" << type << "!"; + abort(); + } + } + + } // end of namespace mln::io::internal::pnm + + } // end of namespace mln::io::internal + + } // end of namespace mln::io + +} // end of namespace mln + + +#endif // ! MLN_IO_PNM_LOAD_HEADER_HH Index: trunk/milena/mln/io/internal/pnm/save.hh =================================================================== --- trunk/milena/mln/io/internal/pnm/save.hh (revision 0) +++ trunk/milena/mln/io/internal/pnm/save.hh (revision 1109) @@ -0,0 +1,162 @@ +// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 EPITA +// Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_IO_PNM_SAVE_HH +# define MLN_IO_PNM_SAVE_HH + +# include <iostream> +# include <fstream> + +# include <mln/core/concept/image.hh> + +# include <mln/value/rgb.hh> +# include <mln/value/int_u8.hh> + +# include <mln/io/internal/pnm/save_header.hh> +# include <mln/io/internal/pnm/macros.hh> + +# include <mln/metal/instance_of.hh> + +# include <mln/geom/size2d.hh> + +/*! \file mln/level/transform.hh + * + * \brief save pgm, + * + */ + +namespace mln +{ + + namespace io + { + + namespace internal + { + + +# ifndef MLN_INCLUDE_ONLY + + namespace pnm + { + + // for 3dimensionals values (rgb) + template <unsigned int n> + void save_data_uncontiguous(std::ofstream& file, + const image2d_b< value::rgb<n> >& ima) + { + typedef typename value::rgb<n>::enc V; + typedef typename value::rgb<n>::enc::enc E; + + const int + min_row = geom::min_row(ima), + max_row = geom::max_row(ima), + min_col = geom::min_col(ima), + max_col = geom::max_col(ima); + + point2d p; + + for (p.row() = min_row; p.row() <= max_row; ++p.row()) + for (p.col() = min_col; p.col() <= max_col; ++p.col()) + { + const V* buf = ima(p).buffer(); + + E v = buf[0].to_enc(); + file.write((char*)&v, sizeof(E)); + v = ima(p).green().to_enc(); + file.write((char*)&v, sizeof(E)); + v = ima(p).blue().to_enc(); + file.write((char*)&v, sizeof(E)); + } + + } + + // for scalar value + template <typename V> + void save_data_uncontiguous(std::ofstream& file, + const image2d_b<V>& ima) + { + typedef typename V::enc E; + + const int + min_row = geom::min_row(ima), + max_row = geom::max_row(ima), + min_col = geom::min_col(ima), + max_col = geom::max_col(ima); + + point2d p; + for (p.row() = min_row; p.row() <= max_row; ++p.row()) + for (p.col() = min_col; p.col() <= max_col; ++p.col()) + { + E c = ima(p).to_enc(); + file.write((char*)(&c), sizeof(E)); + } + + } + + template <typename I> + void save_data(std::ofstream& file, + const I& ima) + { + const int + min_row = geom::min_row(ima), + max_row = geom::max_row(ima); + point2d p; + p.col() = geom::min_col(ima); + size_t len = geom::ncols(ima) * sizeof(mln_value(I)); + for (p.row() = min_row; p.row() <= max_row; ++p.row()) + file.write((char*)(& ima(p)), len); + } + + template <typename I> + void save(const int type, const Fast_Image<I>& ima_, const std::string& filename) + { + const I& ima = exact(ima_); + std::ofstream file(filename.c_str()); + io::internal::pnm::save_header(type, mln_max(mln_value(I)::enc), + ima, filename, file); + + if (sizeof(value::int_u8) == 1) + save_data(file, ima); + else + save_data_uncontiguous(file, ima); + } + + } // end of namespace mln::io::internal::pnm + + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::internal + + } // end of namespace mln::io + +} // end of namespace mln + + +#endif // ! MLN_IO_PNM_SAVE_HH Index: trunk/milena/mln/io/internal/pnm/load.hh =================================================================== --- trunk/milena/mln/io/internal/pnm/load.hh (revision 0) +++ trunk/milena/mln/io/internal/pnm/load.hh (revision 1109) @@ -0,0 +1,179 @@ +// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 EPITA +// Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_IO_PNM_LOAD_HH +# define MLN_IO_PNM_LOAD_HH + +# include <iostream> +# include <fstream> +# include <string> + +# include <mln/core/image2d_b.hh> + +# include <mln/value/int_u8.hh> +# include <mln/value/rgb.hh> + +# include <mln/io/internal/pnm/load_header.hh> +# include <mln/io/internal/pnm/macros.hh> + +namespace mln +{ + + namespace io + { + + namespace internal + { + + namespace pnm + { + template <unsigned int n> + void load_raw_2d_uncontiguous(std::ifstream& file, + image2d_b< value::rgb<n> >& ima) + { + typedef typename value::rgb<n>::enc E; + + const int + min_row = geom::min_row(ima), + max_row = geom::max_row(ima), + min_col = geom::min_col(ima), + max_col = geom::max_col(ima); + + point2d p; + std::cout << "g++ == 2.95 load as rgb\n"; + for (p.row() = min_row; p.row() <= max_row; ++p.row()) + for (p.col() = min_col; p.col() <= max_col; ++p.col()) + { + E c; + file.read((char*)(&c), sizeof(E)); + ima(p).red() = c; + file.read((char*)(&c), sizeof(E)); + ima(p).green() = c; + file.read((char*)(&c), sizeof(E)); + ima(p).blue() = c; + } + } + + template <unsigned int n> + void load_raw_2d_uncontiguous(std::ifstream& file, + image2d_b< value::int_u<n> >& ima) + { + typedef typename value::int_u<n>::enc E; + + const int + min_row = geom::min_row(ima), + max_row = geom::max_row(ima), + min_col = geom::min_col(ima), + max_col = geom::max_col(ima); + + point2d p; + for (p.row() = min_row; p.row() <= max_row; ++p.row()) + for (p.col() = min_col; p.col() <= max_col; ++p.col()) + { + E c; + file.read((char*)(&c), sizeof(E)); + ima(p) = c; + } + + } + + template <typename I> + void load_raw_2d_contiguous(std::ifstream& file, I& ima) + { + point2d p = make::point2d(0, ima.domain().pmin().col()); + typedef mln_value(I) V; + const mln_coord(I) + min_row = geom::min_row(ima), + max_row = geom::max_row(ima); + + size_t len = geom::ncols(ima) * sizeof(V); + for (p.row() = min_row; p.row() <= max_row; ++p.row()) + file.read((char*)(&ima(p)), len); + } + + /// load_ascii. + template <typename I> + void load_ascii(std::ifstream& file, I& ima) + { + mln_fwd_piter(I) p(ima.domain()); + for_all(p) + { + unsigned value; + file >> value; + ima(p) = value; + // FIXME: Test alt code below. + // file >> ima(p); + } + } + + /// load_raw_2d. + /// for all pnm 8/16 bits formats + template <typename I> + void load_raw_2d(std::ifstream& file, I& ima) + { + if (sizeof(value::int_u8) == 1) + load_raw_2d_contiguous(file, ima); + else + load_raw_2d_uncontiguous(file, ima); + } + + /// load pnm format + template <typename V> + image2d_b<V> load(char type_, const std::string& filename) + { + std::ifstream file(filename.c_str()); + if (! file) + { + std::cerr << "error: file '" << filename + << "' not found!"; + abort(); + } + char type = 0; + int nrows, ncols; + io::internal::pnm::read_header(type_ - 3, type_, file, type, nrows, ncols); + + image2d_b<V> ima(nrows, ncols); + if (type == type_) + io::internal::pnm::load_raw_2d(file, ima); + else + if (type == (type_ - 3)) + io::internal::pnm::load_ascii(file, ima); + return ima; + + } + + } // end of namespace mln::io::internal::pnm + + } // end of namespace mln::io::internal + + } // end of namespace mln::io + +} // end of namespace mln + + +#endif // ! MLN_IO_PNM_LOAD_HH Index: trunk/milena/mln/io/ppm/save.hh =================================================================== --- trunk/milena/mln/io/ppm/save.hh (revision 1108) +++ trunk/milena/mln/io/ppm/save.hh (revision 1109) @@ -39,6 +39,7 @@ # include <mln/metal/bexpr.hh> # include <mln/convert/to_rgb.hh> +# include <mln/io/internal/pnm/save.hh> namespace mln { @@ -62,89 +63,11 @@ # ifndef MLN_INCLUDE_ONLY - namespace impl - { - - template <typename I> - void save_header_(const I& ima, const std::string& filename, - std::ofstream& file) - { - if (! file) - { - std::cerr << "error: cannot open file '" << filename - << "'!"; - abort(); - } - file << "P6" << std::endl; - file << "# milena" << std::endl; - file << geom::ncols(ima) << ' ' << geom::nrows(ima) << std::endl; - file << "255" << std::endl; - } - -// template <typename I> -// void save_(const Fast_Image<I>& ima_, const std::string& filename) -// { -// const I& ima = exact(ima_); -// std::ofstream file(filename.c_str()); -// save_header_(ima, filename, file); -// const int -// min_row = geom::min_row(ima), -// max_row = geom::max_row(ima); -// point2d p; -// if (sizeof(mln_value(I)) == 1) -// { -// p.col() = geom::min_col(ima); -// size_t len = geom::ncols(ima); -// for (p.row() = min_row; p.row() <= max_row; ++p.row()) -// file.write((char*)(& ima(p)), len); -// } -// else -// { -// // FIXME: code for g++-2.95 when sizeof(int_u8) == 2!!! -// const int -// min_col = geom::min_col(ima), -// max_col = geom::max_col(ima); -// for (p.row() = min_row; p.row() <= max_row; ++p.row()) -// for (p.col() = min_col; p.col() <= max_col; ++p.col()) -// { -// unsigned char c = ima(p); -// file.write((char*)(&c), 1); -// } -// } -// } - - template <typename I> - void save_(const Image<I>& ima_, const std::string& filename) - { - const I& ima = exact(ima_); - std::ofstream file(filename.c_str()); - save_header_(ima, filename, file); - const int - min_row = geom::min_row(ima), - max_row = geom::max_row(ima), - min_col = geom::min_col(ima), - max_col = geom::max_col(ima); - point2d p; - - for (p.row() = min_row; p.row() <= max_row; ++p.row()) - for (p.col() = min_col; p.col() <= max_col; ++p.col()) - { - const value::int_u8* c = convert::to_rgb(ima(p)).buffer(); - file.write((char*)(c), 3); - } - } - - } // end of namespace mln::io::impl - - template <typename I> void save(const Image<I>& ima, const std::string& filename) { -// mln::metal::or_< -// mln::metal::equal<mln_value(I), value::int_u<8> >, -// mln::metal::equal<mln_value(I), value::int_u_sat<8> > -// >::check(); - impl::save_(exact(ima), filename); + mln::metal::instance_of<mln_value(I), value::rgb >::check(); + io::internal::pnm::save(PPM, exact(ima), filename); } # endif // ! MLN_INCLUDE_ONLY Index: trunk/milena/mln/io/ppm/load.hh =================================================================== --- trunk/milena/mln/io/ppm/load.hh (revision 1108) +++ trunk/milena/mln/io/ppm/load.hh (revision 1109) @@ -36,6 +36,7 @@ # include <mln/core/image2d_b.hh> # include <mln/value/rgb8.hh> +# include <mln/io/internal/pnm/load.hh> namespace mln { @@ -45,153 +46,15 @@ namespace ppm { - - namespace internal - { - - void abort() - { - std::cerr << " aborting." << std::endl; - exit(0); - } - - bool read_pnm_header(std::istream& istr, - char& type, - int& nrows, int& ncols, - bool test = false) - { - // check magic - if (istr.get() != 'P' ) - goto err; - type = istr.get(); - if (type < '1' || type > '6') - goto err; - if (istr.get() != '\n') - goto err; - - // skip comments - while (istr.peek() == '#') - { - std::string line; - std::getline(istr, line); - } - - // get size - istr >> ncols >> nrows; - if (nrows <= 0 || ncols <= 0) - goto err; - - // skip maxvalue - if (istr.get() != '\n') - goto err; - if (type != '1' && type != '4') - { - std::string line; - std::getline(istr, line); - } - return true; - - err: - if (! test) - { - std::cerr << "error: badly formed header!"; - abort(); - } - return false; - } - - void read_pnm_header(char ascii, char raw, - std::istream& istr, - char& type, - int& nrows, int& ncols) - { - read_pnm_header(istr, type, nrows, ncols); - if (! (type == ascii || type == raw)) - { - std::cerr << "error: bad pnm type; " - << "expected P" << ascii - << " or P" << raw - << ", get P" << type << "!"; - abort(); - } - } - - - /// load_ascii. - template <typename I> - void load_ascii(std::ifstream& file, I& ima) + template <typename V> + image2d_b<V> load(const std::string& filename) { - mln_fwd_piter(I) p(ima.domain()); - for_all(p) - { - unsigned value; - file >> value; - ima(p) = value; - // FIXME: Test alt code below. - // file >> ima(p); - } + return io::internal::pnm::load<V>(PPM, filename); } - - /// load_raw_2d. - template <typename I> - void load_raw_2d(std::ifstream& file, I& ima) - { - point2d p = make::point2d(0, ima.domain().pmin().col()); - typedef mln_value(I) V; - const mln_coord(I) - min_row = geom::min_row(ima), - max_row = geom::max_row(ima); - if (sizeof(V) == 1) - { - size_t len = geom::ncols(ima) * sizeof(mln_enc(V)) * 3; - for (p.row() = min_row; p.row() <= max_row; ++p.row()) - file.read((char*)(& ima(p)), len); - } - else - { - // FIXME: code for g++-2.95 when sizeof(int_u8) == 2!!! - const mln_coord(I) - min_col = geom::min_col(ima), - max_col = geom::max_col(ima); - for (p.row() = min_row; p.row() <= max_row; ++p.row()) - for (p.col() = min_col; p.col() <= max_col; ++p.col()) - { - unsigned char c; - file.read((char*)(&c), 1); - ima(p).red() = c; - file.read((char*)(&c), 1); - ima(p).green() = c; - file.read((char*)(&c), 1); - ima(p).blue() = c; - } - } - } - - - } // end of namespace mln::io::internal - - image2d_b<value::rgb8> load(const std::string& filename) { - std::ifstream file(filename.c_str()); - if (! file) - { - std::cerr << "error: file '" << filename - << "' not found!"; - abort(); - } - char type; - int nrows, ncols; - internal::read_pnm_header('3', '6', file, type, nrows, ncols); - - image2d_b<value::rgb8> ima(nrows, ncols); - if (type == '6') - internal::load_raw_2d(file, ima); - else - if (type == '3') - internal::load_ascii(file, ima); - return ima; + return load< value::rgb8 >(filename); } } // end of namespace mln::io::ppm @@ -202,3 +65,4 @@ #endif // ! MLN_IO_PPM_LOAD_HH + Index: trunk/milena/mln/io/pbm/save.hh =================================================================== --- trunk/milena/mln/io/pbm/save.hh (revision 1108) +++ trunk/milena/mln/io/pbm/save.hh (revision 1109) @@ -36,6 +36,8 @@ # include <mln/metal/equal.hh> # include <mln/metal/bexpr.hh> +# include <mln/io/internal/pnm/save.hh> + namespace mln { @@ -63,59 +65,14 @@ { template <typename I> - void save_header_(const I& ima, const std::string& filename, - std::ofstream& file) - { - if (! file) - { - std::cerr << "error: cannot open file '" << filename - << "'!"; - abort(); - } - file << "P4" << std::endl; - file << "# milena" << std::endl; - file << geom::ncols(ima) << ' ' << geom::nrows(ima) << std::endl; - file << "255" << std::endl; - } - -// template <typename I> -// void save_(const Fast_Image<I>& ima_, const std::string& filename) -// { -// const I& ima = exact(ima_); -// std::ofstream file(filename.c_str()); -// save_header_(ima, filename, file); -// const int -// min_row = geom::min_row(ima), -// max_row = geom::max_row(ima); -// point2d p; -// if (sizeof(mln_value(I)) == 1) -// { -// p.col() = geom::min_col(ima); -// size_t len = geom::ncols(ima); -// for (p.row() = min_row; p.row() <= max_row; ++p.row()) -// file.write((char*)(& ima(p)), len); -// } -// else -// { -// // FIXME: code for g++-2.95 when sizeof(int_u8) == 2!!! -// const int -// min_col = geom::min_col(ima), -// max_col = geom::max_col(ima); -// for (p.row() = min_row; p.row() <= max_row; ++p.row()) -// for (p.col() = min_col; p.col() <= max_col; ++p.col()) -// { -// unsigned char c = ima(p); -// file.write((char*)(&c), 1); -// } -// } -// } - - template <typename I> void save_(const Image<I>& ima_, const std::string& filename) { const I& ima = exact(ima_); std::ofstream file(filename.c_str()); - save_header_(ima, filename, file); + + //FIXME : why do we need a max val??? + io::internal::pnm::save_header(PBM, 255, ima, filename, file); + const int min_row = geom::min_row(ima), max_row = geom::max_row(ima), Index: trunk/milena/mln/io/pbm/load.hh =================================================================== --- trunk/milena/mln/io/pbm/load.hh (revision 1108) +++ trunk/milena/mln/io/pbm/load.hh (revision 1109) @@ -34,7 +34,7 @@ # include <string> # include <mln/core/image2d_b.hh> - +# include <mln/io/internal/pnm/load_header.hh> namespace mln { @@ -48,74 +48,6 @@ namespace internal { - void abort() - { - std::cerr << " aborting." << std::endl; - exit(0); - } - - bool read_pnm_header(std::istream& istr, - char& type, - int& nrows, int& ncols, - bool test = false) - { - // check magic - if (istr.get() != 'P' ) - goto err; - type = istr.get(); - if (type < '1' || type > '6') - goto err; - if (istr.get() != '\n') - goto err; - - // skip comments - while (istr.peek() == '#') - { - std::string line; - std::getline(istr, line); - } - - // get size - istr >> ncols >> nrows; - if (nrows <= 0 || ncols <= 0) - goto err; - - // skip maxvalue - if (istr.get() != '\n') - goto err; - if (type != '1' && type != '4') - { - std::string line; - std::getline(istr, line); - } - return true; - - err: - if (! test) - { - std::cerr << "error: badly formed header!"; - abort(); - } - return false; - } - - void read_pnm_header(char ascii, char raw, - std::istream& istr, - char& type, - int& nrows, int& ncols) - { - read_pnm_header(istr, type, nrows, ncols); - if (! (type == ascii || type == raw)) - { - std::cerr << "error: bad pnm type; " - << "expected P" << ascii - << " or P" << raw - << ", get P" << type << "!"; - abort(); - } - } - - /// load_ascii. template <typename I> void load_ascii(std::ifstream& file, I& ima) @@ -136,8 +68,6 @@ template <typename I> void load_raw_2d(std::ifstream& file, I& ima) { - std::cout << "test"<< std::endl; - point2d p = make::point2d(0, ima.domain().pmin().col()); typedef mln_value(I) V; const mln_coord(I) @@ -174,7 +104,7 @@ } char type; int nrows, ncols; - internal::read_pnm_header('1', '4', file, type, nrows, ncols); + io::internal::pnm::read_header('1', '4', file, type, nrows, ncols); image2d_b<bool> ima(nrows, ncols); if (type == '4') Index: trunk/milena/mln/value/rgb16.hh =================================================================== --- trunk/milena/mln/value/rgb16.hh (revision 0) +++ trunk/milena/mln/value/rgb16.hh (revision 1109) @@ -0,0 +1,55 @@ +// Copyright (C) 2007 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_VALUE_RGB16_HH +# define MLN_VALUE_RGB16_HH + +/*! \file mln/value/rgb16.hh + * + * \brief Color class for red-green-blue where every component is + * 16-bit encoded. + */ + +# include <mln/value/rgb.hh> + + +namespace mln +{ + + namespace value + { + + /*! \brief Color class for red-green-blue where every component is + * 16-bit encoded. + */ + typedef rgb<16> rgb16; + } // end of namespace mln::value + +} // end of namespace mln + + +#endif // ! MLN_VALUE_RGB16_HH Index: trunk/milena/mln/value/rgb.hh =================================================================== --- trunk/milena/mln/value/rgb.hh (revision 1108) +++ trunk/milena/mln/value/rgb.hh (revision 1109) @@ -101,6 +101,12 @@ rgb<n> operator-(const enc& i) const ; rgb<n> operator-(const size_t& i) const; + /// multiplication + rgb<n> operator*(const enc& i) const; + + /// division + rgb<n> operator/(const enc& i) const; + /// Self addition rgb<n>& operator+=(const rgb<n>& v); @@ -125,20 +131,13 @@ static const unsigned nbits = 24; static const std::size_t card_ = metal::pow<2, nbits>::value; static const rgb<n> max() { rgb<n> c(props< int_u<n> >::max); return c; } - static const rgb<n> - min() - { - const rgb<n> c(props< int_u<n> >::min()); - return c; - } - + static const rgb<n> min() { const rgb<n> c(props< int_u<n> >::min()); return c; } typedef color_kind kind; typedef float_x3_t sum; typedef uchar_x3_t interop; }; - /*! \brief Print an rgb \p c into the output stream \p ostr. * * \param[in,out] ostr An output stream. @@ -160,7 +159,7 @@ template <unsigned n> rgb<n>::rgb(equiv a) { - std::memcpy(this->c_, a, 3); + std::memcpy(this->c_, a, 3 * sizeof(enc)); } template <unsigned n> @@ -183,7 +182,7 @@ rgb<n>& rgb<n>::operator=(const rgb<n>& v) { - std::memcpy(this->c_, v.c_, 3); + std::memcpy(this->c_, v.c_, 3 * sizeof(enc)); return *this; } @@ -290,6 +289,27 @@ } template <unsigned n> + rgb<n> + rgb<n>::operator*(const enc& i) const + { + rgb<n> res; + for (int j = 0; j < 3; j++) + res.c_[j] = this->c_[j] * i; + return res; + } + + template <unsigned n> + rgb<n> + rgb<n>::operator/(const enc& i) const + { + rgb<n> res; + for (int j = 0; j < 3; j++) + res.c_[j] = this->c_[j] * i; + return res; + } + + + template <unsigned n> std::ostream& operator<<(std::ostream& ostr, const rgb<n>& v) { return ostr << "(R:" << debug::format(v.red()) Index: trunk/milena/img/test.fits =================================================================== Binary files trunk/milena/img/test.fits (revision 0) and trunk/milena/img/test.fits (revision 1109) differ
participants (1)
-
Matthieu Garrigues