comparison libinterp/corefcn/__tiff__.cc @ 31171:8bf3fa6b6977

Tiff: added readRGBAStrip and readRGBATile methods * __tiff__.cc: added internal functions for reading strips and tiles using LibTIFF's RGBA interface. * Tiff.m: added readRGBAStrip and readRGBATile methods to the Tiff class and added unit tests for the ne methods.
author magedrifaat <magedrifaat@gmail.com>
date Sun, 14 Aug 2022 02:40:03 +0200
parents 72a159bc5a4c
children 3f5f1404af8a
comparison
equal deleted inserted replaced
31170:72a159bc5a4c 31171:8bf3fa6b6977
2057 error ("Openning files in r+ mode is not yet supported"); 2057 error ("Openning files in r+ mode is not yet supported");
2058 else 2058 else
2059 error ("Invalid mode for openning Tiff file: %s", mode.c_str ()); 2059 error ("Invalid mode for openning Tiff file: %s", mode.c_str ());
2060 } 2060 }
2061 2061
2062 // LibTIFF does Strip chopping by default, which makes the organization of
2063 // data exposed to the user different from the actual file, so we need to
2064 // force disable this behavior by adding 'c' flag to the mode
2065 mode = mode + 'c';
2066
2062 TIFF *tif = TIFFOpen (filename.c_str (), mode.c_str ()); 2067 TIFF *tif = TIFFOpen (filename.c_str (), mode.c_str ());
2063 2068
2064 if (! tif) 2069 if (! tif)
2065 error ("Failed to open Tiff file\n"); 2070 error ("Failed to open Tiff file\n");
2066 2071
2334 err_disabled_feature ("readEncodedTile", "Tiff"); 2339 err_disabled_feature ("readEncodedTile", "Tiff");
2335 #endif 2340 #endif
2336 } 2341 }
2337 2342
2338 DEFUN (__tiff_read_rgba_image__, args, , 2343 DEFUN (__tiff_read_rgba_image__, args, ,
2339 "Read the image data in rgba mode") 2344 "Read the image data in rgba mode")
2340 { 2345 {
2341 #if defined (HAVE_TIFF) 2346 #if defined (HAVE_TIFF)
2342 int nargin = args.length (); 2347 int nargin = args.length ();
2343 2348
2344 if (nargin != 1) 2349 if (nargin != 1)
2346 2351
2347 TIFF *tif = (TIFF *)(args(0).uint64_value ()); 2352 TIFF *tif = (TIFF *)(args(0).uint64_value ());
2348 2353
2349 tiff_image_data image_data (tif); 2354 tiff_image_data image_data (tif);
2350 2355
2356 // Start with reversed dimensions to be aligned with LibTIFF and
2357 // permute to the correct order later
2351 dim_vector img_dims (4, image_data.width, image_data.height); 2358 dim_vector img_dims (4, image_data.width, image_data.height);
2352 uint8NDArray img (img_dims); 2359 uint8NDArray img (img_dims);
2353 uint32_t *img_ptr = reinterpret_cast <uint32_t *> (img.fortran_vec ()); 2360 uint32_t *img_ptr = reinterpret_cast <uint32_t *> (img.fortran_vec ());
2354 // Matlab (R2022a) uses a top-left orientation ignoring the tag if present 2361 // Matlab (R2022a) uses a top-left orientation ignoring the tag if present
2355 if (! TIFFReadRGBAImageOriented (tif, image_data.width, image_data.height, 2362 if (! TIFFReadRGBAImageOriented (tif, image_data.width, image_data.height,
2356 img_ptr, 1)) 2363 img_ptr, 1))
2357 error ("Failed to read image"); 2364 error ("Failed to read image");
2358 2365
2366 // Permute to the correct Octave dimension order
2359 Array<octave_idx_type> perm (dim_vector (3, 1)); 2367 Array<octave_idx_type> perm (dim_vector (3, 1));
2360 perm(0) = 2; 2368 perm(0) = 2;
2361 perm(1) = 1; 2369 perm(1) = 1;
2362 perm(2) = 0; 2370 perm(2) = 0;
2363 img = img.permute (perm); 2371 img = img.permute (perm);
2364 2372
2373 // Slice the data into RGB and alpha
2365 Array<idx_vector> idx (dim_vector (3, 1)); 2374 Array<idx_vector> idx (dim_vector (3, 1));
2366 idx(0) = idx_vector (':'); 2375 idx(0) = idx_vector (':');
2367 idx(1) = idx_vector (':'); 2376 idx(1) = idx_vector (':');
2368 idx(2) = idx_vector (0, 3); 2377 idx(2) = idx_vector (0, 3);
2369 uint8NDArray rgb = uint8NDArray (img.index (idx)); 2378 uint8NDArray rgb = uint8NDArray (img.index (idx));
2373 octave_value_list retval (2); 2382 octave_value_list retval (2);
2374 retval(0) = octave_value (rgb); 2383 retval(0) = octave_value (rgb);
2375 retval(1) = octave_value (alpha); 2384 retval(1) = octave_value (alpha);
2376 return retval; 2385 return retval;
2377 #else 2386 #else
2378 err_disabled_feature ("readEncodedTile", "Tiff"); 2387 err_disabled_feature ("readRGBAImage", "Tiff");
2388 #endif
2389 }
2390
2391 DEFUN (__tiff_read_rgba_strip__, args, ,
2392 "Read the strip data containing the given row in rgba mode")
2393 {
2394 #if defined (HAVE_TIFF)
2395 int nargin = args.length ();
2396
2397 if (nargin != 2)
2398 error ("Wrong number of arguments");
2399
2400 TIFF *tif = (TIFF *)(args(0).uint64_value ());
2401
2402 // TODO(maged): check matlab behavior for missing/ wrong/ out of bounds row
2403 uint32_t row = args (1).uint32_scalar_value ();
2404
2405 tiff_image_data image_data (tif);
2406 if (image_data.is_tiled)
2407 error ("The image is tiled not stripped");
2408
2409 if (row < 1 || row > image_data.height)
2410 error ("Row out of bounds of the image");
2411
2412 // TODO(maged): check if matlab require the first row in strip as well
2413 // Convert from 1-based indexing to zero-based
2414 row--;
2415
2416 uint32_t rows_in_strip;
2417 if (! TIFFGetFieldDefaulted (tif, TIFFTAG_ROWSPERSTRIP, &rows_in_strip))
2418 error ("Failed to obtain a value for RowsPerStrip");
2419
2420 if (rows_in_strip > image_data.height)
2421 rows_in_strip = image_data.height;
2422
2423 // LibTIFF requires the row to be the first row in the strip
2424 // so this removes any offset to reach the first row
2425 row -= row % rows_in_strip;
2426
2427 // The exact number of rows in the strip is needed for boundary strips
2428 uint32_t strip_no = TIFFComputeStrip (tif, row, 0);
2429 rows_in_strip = get_rows_in_strip (strip_no, TIFFNumberOfStrips (tif),
2430 rows_in_strip, &image_data);
2431
2432 // Start with reversed dimensions to be aligned with LibTIFF and
2433 // permute to the correct order later
2434 dim_vector strip_dims (4, image_data.width, rows_in_strip);
2435 uint8NDArray strip_data (strip_dims);
2436 uint32_t *strip_ptr
2437 = reinterpret_cast <uint32_t *> (strip_data.fortran_vec ());
2438
2439 // TODO(maged): check if matlab does anything with orientation tag
2440 if (! TIFFReadRGBAStrip (tif, row, strip_ptr))
2441 error ("Failed to read strip");
2442
2443 // Permute to the correct order of dimensions for Octave
2444 Array<octave_idx_type> perm (dim_vector (3, 1));
2445 perm(0) = 2;
2446 perm(1) = 1;
2447 perm(2) = 0;
2448 strip_data = strip_data.permute (perm);
2449
2450 // Slice the data into RGB and alpha
2451 // The rows are reversed because LibTIFF assumes a bottom-left orientation
2452 Array<idx_vector> idx (dim_vector (3, 1));
2453 idx(0) = idx_vector (rows_in_strip - 1, -1, -1);
2454 idx(1) = idx_vector (':');
2455 idx(2) = idx_vector (0, 3);
2456 uint8NDArray rgb = uint8NDArray (strip_data.index (idx));
2457 idx(2) = idx_vector (3);
2458 uint8NDArray alpha = uint8NDArray (strip_data.index (idx));
2459
2460 octave_value_list retval (2);
2461 retval(0) = octave_value (rgb);
2462 retval(1) = octave_value (alpha);
2463 return retval;
2464 #else
2465 err_disabled_feature ("readRGBAStrip", "Tiff");
2466 #endif
2467 }
2468
2469 DEFUN (__tiff_read_rgba_tile__, args, ,
2470 "Read the stile data containing the given row and column in rgba mode")
2471 {
2472 #if defined (HAVE_TIFF)
2473 int nargin = args.length ();
2474
2475 if (nargin != 3)
2476 error ("Wrong number of arguments");
2477
2478 TIFF *tif = (TIFF *)(args(0).uint64_value ());
2479
2480 // TODO(maged): check matlab behavior for missing/ wrong/ out of bounds vals
2481 uint32_t row = args (1).uint32_scalar_value ();
2482 uint32_t col = args (2).uint32_scalar_value ();
2483
2484 tiff_image_data image_data (tif);
2485 if (! image_data.is_tiled)
2486 error ("The image is stripped not tiled");
2487
2488 if (row < 1 || row > image_data.height)
2489 error ("Row out of bounds of the image");
2490 if (col < 1 || col > image_data.width)
2491 error ("Column out of bounds of the image");
2492
2493 // TODO(maged): check if matlab require the first row,col in tile as well
2494 // Convert from 1-based indexing to zero-based
2495 row--;
2496 col--;
2497
2498 uint32_t tile_width, tile_height;
2499 if (! TIFFGetField (tif, TIFFTAG_TILELENGTH, &tile_height))
2500 error ("Failed to obtain a value for TileLength");
2501 if (! TIFFGetField (tif, TIFFTAG_TILEWIDTH, &tile_width))
2502 error ("Failed to obtain a value for TileWidth");
2503
2504 // LibTIFF requires the row and columns to be the top-left corner of the
2505 // tile, so this removes any offset to reach the top-left row and column
2506 // of the tile
2507 row -= row % tile_height;
2508 col -= col % tile_width;
2509
2510 // Start with reversed dimensions to be aligned with LibTIFF and
2511 // permute to the correct order later
2512 dim_vector tile_dims (4, tile_width, tile_height);
2513 uint8NDArray tile_data (tile_dims);
2514 uint32_t *tile_ptr
2515 = reinterpret_cast <uint32_t *> (tile_data.fortran_vec ());
2516
2517 // TODO(maged): check if matlab does anything with orientation tag
2518 if (! TIFFReadRGBATile (tif, col, row, tile_ptr))
2519 error ("Failed to read tile");
2520
2521 // Permute to the correct order of dimensions for Octave
2522 Array<octave_idx_type> perm (dim_vector (3, 1));
2523 perm(0) = 2;
2524 perm(1) = 1;
2525 perm(2) = 0;
2526 tile_data = tile_data.permute (perm);
2527
2528 // Calculate the correct dimensions for boundary tiles
2529 uint32_t corrected_height = tile_height;
2530 uint32_t corrected_width = tile_width;
2531 if (row + tile_height > image_data.height)
2532 corrected_height = image_data.height - row;
2533 if (col + tile_width > image_data.width)
2534 corrected_width = image_data.width - col;
2535
2536 // Slice the data into RGB and alpha
2537 // LibTIFF assumes the image has bottom-left orientation and returns
2538 // the rows flipped vertically, so we need to reverse them and remove
2539 // the padding which is at the top since the rows are flipped
2540 Array<idx_vector> idx (dim_vector (3, 1));
2541 // Must cast the unsigned values to signed because otherwise the output
2542 // can't be negative (C++ is the best).
2543 idx(0) = idx_vector (tile_height - 1,
2544 int64_t(tile_height - corrected_height) - 1, -1);
2545 idx(1) = idx_vector (0, corrected_width);
2546 idx(2) = idx_vector (0, 3);
2547 uint8NDArray rgb = uint8NDArray (tile_data.index (idx));
2548 idx(2) = idx_vector (3);
2549 uint8NDArray alpha = uint8NDArray (tile_data.index (idx));
2550
2551 octave_value_list retval (2);
2552 retval(0) = octave_value (rgb);
2553 retval(1) = octave_value (alpha);
2554 return retval;
2555 #else
2556 err_disabled_feature ("readRGBATile", "Tiff");
2379 #endif 2557 #endif
2380 } 2558 }
2381 2559
2382 DEFUN (__tiff_write__, args, , 2560 DEFUN (__tiff_write__, args, ,
2383 "Write the image data to the current IFD") 2561 "Write the image data to the current IFD")