Mercurial > octave-libtiff
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") |