static void raster_special(int key, int x, int y) { (void) x; (void) y; switch (key) { case GLUT_KEY_PAGE_UP: /* previous logical image */ if (TIFFCurrentDirectory(tif) > 0) { if (TIFFSetDirectory(tif, TIFFCurrentDirectory(tif)-1)) { initImage(); setWindowSize(); } } else { TIFFRGBAImageEnd(&img); prevImage(); initImage(); setWindowSize(); } break; case GLUT_KEY_PAGE_DOWN: /* next logical image */ if (!TIFFLastDirectory(tif)) { if (TIFFReadDirectory(tif)) { initImage(); setWindowSize(); } } else { TIFFRGBAImageEnd(&img); nextImage(); initImage(); setWindowSize(); } break; case GLUT_KEY_HOME: /* 1st image in current file */ if (TIFFSetDirectory(tif, 0)) { TIFFRGBAImageEnd(&img); initImage(); setWindowSize(); } break; case GLUT_KEY_END: /* last image in current file */ TIFFRGBAImageEnd(&img); while (!TIFFLastDirectory(tif)) TIFFReadDirectory(tif); initImage(); setWindowSize(); break; } glutPostRedisplay(); }
tdir_t tif_DirCount(TIFF* tif) { tdir_t dirCurrent = TIFFCurrentDirectory(tif); int dirCount = 0; TIFFSetDirectory(tif, 0); do{ dirCount++; } while(TIFFReadDirectory(tif)); TIFFSetDirectory(tif, dirCurrent); return dirCount; }
static void raster_reshape(int win_w, int win_h) { GLfloat xratio = (GLfloat)win_w/img.width; GLfloat yratio = (GLfloat)win_h/img.height; int ratio = (int)(((xratio > yratio)?xratio:yratio) * 100); glPixelZoom(xratio, yratio); glViewport(0, 0, win_w, win_h); snprintf(title, 1024, "%s [%u] %d%%", filelist[fileindex], (unsigned int) TIFFCurrentDirectory(tif), ratio); glutSetWindowTitle(title); }
int main(int argc, char* argv[]) { int c; int dirnum = -1; uint32 diroff = 0; oerror = TIFFSetErrorHandler(NULL); owarning = TIFFSetWarningHandler(NULL); while ((c = getopt(argc, argv, "d:o:p:eflmsvw?")) != -1) switch (c) { case 'd': dirnum = atoi(optarg); break; case 'e': oerror = TIFFSetErrorHandler(oerror); break; case 'l': order0 = FILLORDER_LSB2MSB; break; case 'm': order0 = FILLORDER_MSB2LSB; break; case 'o': diroff = strtoul(optarg, NULL, 0); break; case 'p': photo0 = photoArg(optarg); break; case 's': stoponerr = 1; break; case 'w': owarning = TIFFSetWarningHandler(owarning); break; case 'v': verbose = 1; break; case '?': usage(); /*NOTREACHED*/ } filenum = argc - optind; if ( filenum < 1) usage(); glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); /* * Get the screen size */ xmax = glutGet(GLUT_SCREEN_WIDTH); ymax = glutGet(GLUT_SCREEN_HEIGHT); /* * Use 90% of the screen size */ xmax = xmax - xmax / 10.0; ymax = ymax - ymax / 10.0; filelist = (char **) _TIFFmalloc(filenum * sizeof(char*)); if (!filelist) { TIFFError(argv[0], "Can not allocate space for the file list."); return 1; } _TIFFmemcpy(filelist, argv + optind, filenum * sizeof(char*)); fileindex = -1; if (nextImage() < 0) { _TIFFfree(filelist); return 2; } /* * Set initial directory if user-specified * file was opened successfully. */ if (dirnum != -1 && !TIFFSetDirectory(tif, dirnum)) TIFFError(argv[0], "Error, seeking to directory %d", dirnum); if (diroff != 0 && !TIFFSetSubDirectory(tif, diroff)) TIFFError(argv[0], "Error, setting subdirectory at %#x", diroff); order = order0; photo = photo0; initImage(); /* * Create a new window or reconfigure an existing * one to suit the image to be displayed. */ glutInitWindowSize(width, height); snprintf(title, 1024, "%s [%u]", filelist[fileindex], (unsigned int) TIFFCurrentDirectory(tif)); glutCreateWindow(title); glutDisplayFunc(raster_draw); glutReshapeFunc(raster_reshape); glutKeyboardFunc(raster_keys); glutSpecialFunc(raster_special); glutMainLoop(); cleanup_and_exit(); return 0; }
bool _openslide_try_ventana(openslide_t *osr, struct _openslide_tiffcache *tc, TIFF *tiff, struct _openslide_hash *quickhash1, GError **err) { GPtrArray *level_array = g_ptr_array_new(); // parse iScan XML char *xml = read_xml_packet(tiff); if (!xml) { g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_FORMAT_NOT_SUPPORTED, "Not a Ventana slide"); goto FAIL; } if (!parse_initial_xml(osr, xml, err)) { g_free(xml); goto FAIL; } g_free(xml); // okay, assume Ventana slide // walk directories do { tdir_t dir = TIFFCurrentDirectory(tiff); // read ImageDescription char *image_desc; if (!TIFFGetField(tiff, TIFFTAG_IMAGEDESCRIPTION, &image_desc)) { continue; } if (strstr(image_desc, LEVEL_DESCRIPTION_TOKEN)) { // is a level // confirm that this directory is tiled if (!TIFFIsTiled(tiff)) { g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_BAD_DATA, "Directory %d is not tiled", dir); goto FAIL; } // verify that we can read this compression (hard fail if not) uint16_t compression; if (!TIFFGetField(tiff, TIFFTAG_COMPRESSION, &compression)) { g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_BAD_DATA, "Can't read compression scheme"); goto FAIL; }; if (!TIFFIsCODECConfigured(compression)) { g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_BAD_DATA, "Unsupported TIFF compression: %u", compression); goto FAIL; } // create level struct level *l = g_slice_new0(struct level); struct _openslide_tiff_level *tiffl = &l->tiffl; if (!_openslide_tiff_level_init(tiff, dir, (struct _openslide_level *) l, tiffl, err)) { g_slice_free(struct level, l); goto FAIL; } l->grid = _openslide_grid_create_simple(osr, tiffl->tiles_across, tiffl->tiles_down, tiffl->tile_w, tiffl->tile_h, read_tile); // add to array g_ptr_array_add(level_array, l); } else if (!strcmp(image_desc, MACRO_DESCRIPTION)) { // macro image if (!_openslide_tiff_add_associated_image(osr, "macro", tc, dir, err)) { g_prefix_error(err, "Can't read macro image: "); goto FAIL; } } else if (!strcmp(image_desc, THUMBNAIL_DESCRIPTION)) { // thumbnail image if (!_openslide_tiff_add_associated_image(osr, "thumbnail", tc, dir, err)) { g_prefix_error(err, "Can't read thumbnail image: "); goto FAIL; } } } while (TIFFReadDirectory(tiff));
bool _openslide_try_aperio(openslide_t *osr, TIFF *tiff, struct _openslide_hash *quickhash1, GError **err) { int32_t level_count = 0; int32_t *levels = NULL; int32_t i = 0; if (!TIFFIsTiled(tiff)) { g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_FORMAT_NOT_SUPPORTED, "TIFF is not tiled"); goto FAIL; } char *tagval; int tiff_result; tiff_result = TIFFGetField(tiff, TIFFTAG_IMAGEDESCRIPTION, &tagval); if (!tiff_result || (strncmp(APERIO_DESCRIPTION, tagval, strlen(APERIO_DESCRIPTION)) != 0)) { g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_FORMAT_NOT_SUPPORTED, "Not an Aperio slide"); goto FAIL; } /* * http://www.aperio.com/documents/api/Aperio_Digital_Slides_and_Third-party_data_interchange.pdf * page 14: * * The first image in an SVS file is always the baseline image (full * resolution). This image is always tiled, usually with a tile size * of 240 x 240 pixels. The second image is always a thumbnail, * typically with dimensions of about 1024 x 768 pixels. Unlike the * other slide images, the thumbnail image is always * stripped. Following the thumbnail there may be one or more * intermediate "pyramid" images. These are always compressed with * the same type of compression as the baseline image, and have a * tiled organization with the same tile size. * * Optionally at the end of an SVS file there may be a slide label * image, which is a low resolution picture taken of the slide’s * label, and/or a macro camera image, which is a low resolution * picture taken of the entire slide. The label and macro images are * always stripped. */ // for aperio, the tiled directories are the ones we want do { if (TIFFIsTiled(tiff)) { level_count++; } } while (TIFFReadDirectory(tiff)); levels = g_new(int32_t, level_count); TIFFSetDirectory(tiff, 0); i = 0; do { tdir_t dir = TIFFCurrentDirectory(tiff); if (TIFFIsTiled(tiff)) { levels[i++] = dir; //g_debug("tiled directory: %d", dir); } else { // associated image const char *name = (dir == 1) ? "thumbnail" : NULL; if (!add_associated_image(osr ? osr->associated_images : NULL, name, tiff, err)) { g_prefix_error(err, "Can't read associated image: "); goto FAIL; } //g_debug("associated image: %d", dir); } // check depth uint32_t depth; tiff_result = TIFFGetField(tiff, TIFFTAG_IMAGEDEPTH, &depth); if (tiff_result && depth != 1) { // we can't handle depth != 1 g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_BAD_DATA, "Cannot handle ImageDepth=%d", depth); goto FAIL; } // check compression uint16_t compression; if (!TIFFGetField(tiff, TIFFTAG_COMPRESSION, &compression)) { g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_BAD_DATA, "Can't read compression scheme"); goto FAIL; } if ((compression != APERIO_COMPRESSION_JP2K_YCBCR) && (compression != APERIO_COMPRESSION_JP2K_RGB) && !TIFFIsCODECConfigured(compression)) { g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_BAD_DATA, "Unsupported TIFF compression: %u", compression); goto FAIL; } } while (TIFFReadDirectory(tiff)); // read properties if (osr) { TIFFSetDirectory(tiff, 0); TIFFGetField(tiff, TIFFTAG_IMAGEDESCRIPTION, &tagval); // XXX? should be safe, we just did it char **props = g_strsplit(tagval, "|", -1); add_properties(osr->properties, props); g_strfreev(props); } // special jpeg 2000 aperio thing (with fallback) _openslide_add_tiff_ops(osr, tiff, 0, 0, NULL, level_count, levels, aperio_tiff_tilereader, quickhash1); return true; FAIL: g_free(levels); return false; }
GthImage * _cairo_image_surface_create_from_tiff (GInputStream *istream, GthFileData *file_data, int requested_size, int *original_width_p, int *original_height_p, gboolean *loaded_original_p, gpointer user_data, GCancellable *cancellable, GError **error) { GthImage *image; Handle handle; TIFF *tif; gboolean first_directory; int best_directory; int max_width, max_height, min_diff; uint32 image_width; uint32 image_height; uint32 spp; uint16 extrasamples; uint16 *sampleinfo; uint16 orientation; char emsg[1024]; cairo_surface_t *surface; cairo_surface_metadata_t*metadata; uint32 *raster; image = gth_image_new (); handle.cancellable = cancellable; handle.size = 0; if ((file_data != NULL) && (file_data->info != NULL)) { handle.istream = g_buffered_input_stream_new (istream); handle.size = g_file_info_get_size (file_data->info); } else { void *data; gsize size; /* read the whole stream to get the file size */ if (! _g_input_stream_read_all (istream, &data, &size, cancellable, error)) return image; handle.istream = g_memory_input_stream_new_from_data (data, size, g_free); handle.size = size; } TIFFSetErrorHandler (tiff_error_handler); TIFFSetWarningHandler (tiff_error_handler); tif = TIFFClientOpen ("gth-tiff-reader", "r", &handle, tiff_read, tiff_write, tiff_seek, tiff_close, tiff_size, NULL, NULL); if (tif == NULL) { g_object_unref (handle.istream); g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "Couldn't allocate memory for writing TIFF file"); return image; } /* find the best image to load */ first_directory = TRUE; best_directory = -1; max_width = -1; max_height = -1; min_diff = 0; do { int width; int height; if (TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &width) != 1) continue; if (TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &height) != 1) continue; if (! TIFFRGBAImageOK (tif, emsg)) continue; if (width > max_width) { max_width = width; max_height = height; if (requested_size <= 0) best_directory = TIFFCurrentDirectory (tif); } if (requested_size > 0) { int diff = abs (requested_size - width); if (first_directory) { min_diff = diff; best_directory = TIFFCurrentDirectory (tif); } else if (diff < min_diff) { min_diff = diff; best_directory = TIFFCurrentDirectory (tif); } } first_directory = FALSE; } while (TIFFReadDirectory (tif)); if (best_directory == -1) { TIFFClose (tif); g_object_unref (handle.istream); g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Invalid TIFF format"); return image; } /* read the image */ TIFFSetDirectory (tif, best_directory); TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &image_width); TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &image_height); TIFFGetField (tif, TIFFTAG_SAMPLESPERPIXEL, &spp); TIFFGetFieldDefaulted (tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); if (TIFFGetFieldDefaulted (tif, TIFFTAG_ORIENTATION, &orientation) != 1) orientation = ORIENTATION_TOPLEFT; if (original_width_p) *original_width_p = max_width; if (original_height_p) *original_height_p = max_height; if (loaded_original_p) *loaded_original_p = (max_width == image_width); surface = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32, image_width, image_height); if (surface == NULL) { TIFFClose (tif); g_object_unref (handle.istream); g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "Couldn't allocate memory for writing TIFF file"); return image; } metadata = _cairo_image_surface_get_metadata (surface); _cairo_metadata_set_has_alpha (metadata, (extrasamples == 1) || (spp == 4)); _cairo_metadata_set_original_size (metadata, max_width, max_height); raster = (uint32*) _TIFFmalloc (image_width * image_height * sizeof (uint32)); if (raster == NULL) { cairo_surface_destroy (surface); TIFFClose (tif); g_object_unref (handle.istream); g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "Couldn't allocate memory for writing TIFF file"); return image; } if (TIFFReadRGBAImageOriented (tif, image_width, image_height, raster, orientation, 0)) { guchar *surface_row; int line_step; int x, y, temp; guchar r, g, b, a; uint32 *src_pixel; surface_row = _cairo_image_surface_flush_and_get_data (surface); line_step = cairo_image_surface_get_stride (surface); src_pixel = raster; for (y = 0; y < image_height; y++) { guchar *dest_pixel = surface_row; if (g_cancellable_is_cancelled (cancellable)) goto stop_loading; for (x = 0; x < image_width; x++) { r = TIFFGetR (*src_pixel); g = TIFFGetG (*src_pixel); b = TIFFGetB (*src_pixel); a = TIFFGetA (*src_pixel); CAIRO_SET_RGBA (dest_pixel, r, g, b, a); dest_pixel += 4; src_pixel += 1; } surface_row += line_step; } } stop_loading: cairo_surface_mark_dirty (surface); if (! g_cancellable_is_cancelled (cancellable)) gth_image_set_cairo_surface (image, surface); _TIFFfree (raster); cairo_surface_destroy (surface); TIFFClose (tif); g_object_unref (handle.istream); return image; }