Example #1
0
bool Channel::read_tile_or_closest_ancestor(TileIndex ti, TileIndex &ret_index, Tile &ret) const {
  Locker lock(*this);  // Lock self and hold lock until exiting this method
  ChannelInfo info;
  bool success = read_info(info);
  if (!success) {
    if (verbosity) log_f("read_tile_or_closest_ancestor: can't read info");
    return false;
  }
  TileIndex root = info.nonnegative_root_tile_index;

  if (ti.is_ancestor_of(root)) {
    ret_index = root;
  } else {
    if (ti != root && !root.is_ancestor_of(ti)) {
      // Tile isn't under root
      return false;
    }
    
    assert(tile_exists(root));
    ret_index = root;
    while (ret_index != ti) {
      TileIndex child = ti.start_time() < ret_index.left_child().end_time() ? ret_index.left_child() : ret_index.right_child();
      if (!tile_exists(child)) break;
      ret_index = child;
    }
  }
  // ret_index now holds closest ancestor to ti (or ti itself if it exists)  
    
  assert(read_tile(ret_index, ret));
  return true;
}
Example #2
0
void Channel::move_root_upwards(TileIndex new_root_index, TileIndex old_root_index) {
  Tile old_root_tile;
  Tile empty_tile;
  assert(read_tile(old_root_index, old_root_tile));
  TileIndex ti = old_root_index;
  while (ti != new_root_index) {
    write_tile(ti.sibling(), empty_tile);
    write_tile(ti.parent(), old_root_tile);
    ti = ti.parent();
  }
}
void _openslide_read_tiles(cairo_t *cr,
			   int32_t level,
			   int64_t start_tile_x, int64_t start_tile_y,
			   int64_t end_tile_x, int64_t end_tile_y,
			   double offset_x, double offset_y,
			   double advance_x, double advance_y,
			   openslide_t *osr,
			   struct _openslide_cache *cache,
			   void *arg,
			   void (*read_tile)(openslide_t *osr,
					     cairo_t *cr,
					     int32_t level,
					     int64_t tile_x, int64_t tile_y,
					     double translate_x, double translate_y,
					     struct _openslide_cache *cache,
					     void *arg)) {
  //g_debug("offset: %g %g, advance: %g %g", offset_x, offset_y, advance_x, advance_y);
  if (fabs(offset_x) >= advance_x) {
    _openslide_set_error(osr, "internal error: fabs(offset_x) >= advance_x");
    return;
  }
  if (fabs(offset_y) >= advance_y) {
    _openslide_set_error(osr, "internal error: fabs(offset_y) >= advance_y");
    return;
  }

  //  cairo_set_source_rgb(cr, 0, 1, 0);
  //  cairo_paint(cr);
  //g_debug("offset: %d %d", offset_x, offset_y);

  //g_debug("start: %" G_GINT64_FORMAT " %" G_GINT64_FORMAT, start_tile_x, start_tile_y);
  //g_debug("end: %" G_GINT64_FORMAT " %" G_GINT64_FORMAT, end_tile_x, end_tile_y);

  int64_t tile_y = end_tile_y - 1;

  while (tile_y >= start_tile_y) {
    double translate_y = ((tile_y - start_tile_y) * advance_y) - offset_y;
    int64_t tile_x = end_tile_x - 1;

    while (tile_x >= start_tile_x) {
      double translate_x = ((tile_x - start_tile_x) * advance_x) - offset_x;
      //      g_debug("read_tiles %" G_GINT64_FORMAT " %" G_GINT64_FORMAT, tile_x, tile_y);
      read_tile(osr, cr, level, tile_x, tile_y, translate_x, translate_y, cache, arg);
      tile_x--;
    }

    tile_y--;
  }
}
Example #4
0
static void draw_hudline(const int x, const int y) 
{
	if ((vga_line-y)>=0 && (vga_line-y)<8) {
		for (int i=0;i<20;i++) {
			int chr=hud[i];
			if (chr!=' ') {
				chr = chr>='A' ? chr+256-'A' : chr-'0';

				for (int dx=0;dx<8;dx++) {
					uint8_t c=read_tile(0xF5, dx+chr*8, vga_line-y);
					if (c!=TRANSPARENT)
						draw_buffer[x+dx+i*8]=c;
				}
			}
		}
	}
}
Example #5
0
void Channel::read_bottommost_tiles_in_range(Range times,
                                             bool (*callback)(const Tile &t, Range times)) const {
  ChannelInfo info;
  bool success = read_info(info);
  if (!success) return;
  if (!info.times.intersects(times)) return;

  double time = times.min;
  TileIndex ti = TileIndex::null();
  while (time < times.max) {
    if (ti.is_null()) {
      ti = find_lowest_child_overlapping_time(info.nonnegative_root_tile_index, times.min);
    } else {
      ti = find_lowest_successive_tile(info.nonnegative_root_tile_index, ti);
    }
    if (ti.is_null() || ti.start_time() >= times.max) break;

    Tile t;
    assert(read_tile(ti, t));
    if (!(*callback)(t, times)) break;
  }
}
Example #6
0
void Channel::read_data(std::vector<DataSample<double> > &data, double begin, double end) const {
  double time = begin;
  data.clear();

  Locker lock(*this);  // Lock self and hold lock until exiting this method

  ChannelInfo info;
  bool success = read_info(info);
  if (!success) {
    // Channel doesn't yet exist;  no data
    if (verbosity) log_f("read_data: can't read info");
    return;
  }
  bool first_tile = true;

  while (time < end) {
    TileIndex ti = find_lowest_child_overlapping_time(info.nonnegative_root_tile_index, time);
    if (ti.is_null()) {
      // No tiles; no more data
      if (verbosity) log_f("read_data: can't read tile");
      return;
    }

    Tile tile;
    assert(read_tile(ti, tile));
    unsigned i = 0;
    if (first_tile) {
      // Skip any samples before requested time
      for (; i < tile.double_samples.size() && tile.double_samples[i].time < begin; i++);
    }

    for (; i < tile.double_samples.size() && tile.double_samples[i].time < end; i++) {
      data.push_back(tile.double_samples[i]);
    }
    time = ti.end_time();
  }
}
Example #7
0
std::string Channel::dump_tile_summaries_internal(TileIndex ti, int level) const {
  Tile tile;
  if (!read_tile(ti, tile)) return "";
  std::string ret = string_printf("%*s%d.%d: %zd samples\n", level, "", ti.level, ti.offset, tile.double_samples.size());
  return ret + dump_tile_summaries_internal(ti.left_child(), level+1) + dump_tile_summaries_internal(ti.right_child(), level+1);
}
Example #8
0
void Channel::add_data_internal(const std::vector<DataSample<T> > &data, DataRanges *channel_ranges) {
  if (!data.size()) return;
  // Sanity check
  if (data[0].time < 0) throw std::runtime_error("Unimplemented feature: adding data with negative time");
  for (unsigned i = 0; i < data.size()-1; i++) {
    if (data[i].time > data[i+1].time) throw std::runtime_error("Attempt to add data that is not sorted by ascending time");
  }

  //	regenerate = empty set
  Locker lock(*this);  // Lock self and hold lock until exiting this method
  std::set<TileIndex> to_regenerate;

  ChannelInfo info;
  bool success = read_info(info);
  if (!success) {
    // New channel
    info.magic = ChannelInfo::MAGIC;
    info.version = 0x00010000;
    info.times = Range(data[0].time, data.back().time);
    info.nonnegative_root_tile_index = TileIndex::nonnegative_all();
    create_tile(TileIndex::nonnegative_all());
    info.negative_root_tile_index = TileIndex::null();
  } else {
    info.times.add(Range(data[0].time, data.back().time));
    // If we're not the all-tile, see if we need to move the root upwards
    if (info.nonnegative_root_tile_index != TileIndex::nonnegative_all()) {
      TileIndex new_nonnegative_root_tile_index = TileIndex::index_containing(info.times);
      if (new_nonnegative_root_tile_index.level > info.nonnegative_root_tile_index.level) {
	// Root index changed.  Confirm new root is parent or more distant ancestor of old root
	assert(new_nonnegative_root_tile_index.is_ancestor_of(info.nonnegative_root_tile_index));
	// Trigger regeneration from old root's parent, up through new root
	to_regenerate.insert(info.nonnegative_root_tile_index.parent());
	move_root_upwards(new_nonnegative_root_tile_index, info.nonnegative_root_tile_index);
	info.nonnegative_root_tile_index = new_nonnegative_root_tile_index;
      }
    }
  }

  unsigned i=0;

  while (i < data.size()) {
    TileIndex ti= find_lowest_child_overlapping_time(info.nonnegative_root_tile_index, data[i].time);
    assert(!ti.is_null());

    Tile tile;
    assert(read_tile(ti, tile));
    const DataSample<T> *begin = &data[i];
    while (i < data.size() && ti.contains_time(data[i].time)) i++;
    const DataSample<T> *end = &data[i];
    tile.insert_samples(begin, end);
    
    TileIndex new_root = split_tile_if_needed(ti, tile);
    if (new_root != TileIndex::null()) {
      assert(ti == TileIndex::nonnegative_all());
      if (verbosity) log_f("Channel: %s changing root from %s to %s",
                           descriptor().c_str(), ti.to_string().c_str(),
                           new_root.to_string().c_str());
      info.nonnegative_root_tile_index = new_root;
      delete_tile(ti); // Delete old root
      ti = new_root;
    }
    write_tile(ti, tile);
    if (ti == info.nonnegative_root_tile_index && channel_ranges) { *channel_ranges = tile.ranges; }
    if (ti != info.nonnegative_root_tile_index) to_regenerate.insert(ti.parent());
  }
  
  // Regenerate from lowest level to highest
  while (!to_regenerate.empty()) {
    TileIndex ti = *to_regenerate.begin();
    to_regenerate.erase(to_regenerate.begin());
    Tile regenerated, children[2];
    assert(read_tile(ti.left_child(), children[0]));
    assert(read_tile(ti.right_child(), children[1]));
    create_parent_tile_from_children(ti, regenerated, children);
    write_tile(ti, regenerated);
    if (ti == info.nonnegative_root_tile_index && channel_ranges) { *channel_ranges = regenerated.ranges; }
    if (ti != info.nonnegative_root_tile_index) to_regenerate.insert(ti.parent());
  }
  write_info(info);
}
Example #9
0
bool
ImageInput::read_image (TypeDesc format, void *data,
                        stride_t xstride, stride_t ystride, stride_t zstride,
                        ProgressCallback progress_callback,
                        void *progress_callback_data)
{
    bool native = (format == TypeDesc::UNKNOWN);
    stride_t pixel_bytes = native ? (stride_t) m_spec.pixel_bytes (native)
                                  : (stride_t) (format.size()*m_spec.nchannels);
    if (native && xstride == AutoStride)
        xstride = pixel_bytes;
    m_spec.auto_stride (xstride, ystride, zstride, format, m_spec.nchannels,
                        m_spec.width, m_spec.height);
    bool ok = true;
    if (progress_callback)
        if (progress_callback (progress_callback_data, 0.0f))
            return ok;
    if (m_spec.tile_width) {
        // Tiled image

        // Locally allocate a single tile to gracefully deal with image
        // dimensions smaller than a tile, or if one of the tiles runs
        // past the right or bottom edge.  Then we copy from our tile to
        // the user data, only copying valid pixel ranges.
        stride_t tilexstride = pixel_bytes;
        stride_t tileystride = tilexstride * m_spec.tile_width;
        stride_t tilezstride = tileystride * m_spec.tile_height;
        imagesize_t tile_pixels = m_spec.tile_pixels();
        std::vector<char> pels (tile_pixels * pixel_bytes);
        for (int z = 0;  z < m_spec.depth;  z += m_spec.tile_depth)
            for (int y = 0;  y < m_spec.height;  y += m_spec.tile_height) {
                for (int x = 0;  x < m_spec.width && ok;  x += m_spec.tile_width) {
                    ok &= read_tile (x+m_spec.x, y+m_spec.y, z+m_spec.z,
                                     format, &pels[0]);
                    // Now copy out the scanlines
                    int ntz = std::min (z+m_spec.tile_depth, m_spec.depth) - z;
                    int nty = std::min (y+m_spec.tile_height, m_spec.height) - y;
                    int ntx = std::min (x+m_spec.tile_width, m_spec.width) - x;
                    for (int tz = 0;  tz < ntz;  ++tz) {
                        for (int ty = 0;  ty < nty;  ++ty) {
                            // FIXME -- doesn't work for non-contiguous scanlines
                            memcpy ((char *)data + x*xstride + (y+ty)*ystride + (z+tz)*zstride,
                                    &pels[ty*tileystride+tz*tilezstride],
                                    ntx*tilexstride);
                        }
                    }
//                    return ok; // DEBUG -- just try very first tile
                }
                if (progress_callback)
                    if (progress_callback (progress_callback_data, (float)y/m_spec.height))
                        return ok;
            }
    } else {
        // Scanline image
        for (int z = 0;  z < m_spec.depth;  ++z)
            for (int y = 0;  y < m_spec.height && ok;  ++y) {
                ok &= read_scanline (y+m_spec.y, z+m_spec.z, format,
                                     (char *)data + z*zstride + y*ystride,
                                     xstride);
                if (progress_callback && !(y & 0x0f))
                    if (progress_callback (progress_callback_data, (float)y/m_spec.height))
                        return ok;
            }
    }
    if (progress_callback)
        progress_callback (progress_callback_data, 1.0f);
    return ok;
}
Example #10
0
bool 
ImageInput::read_tiles (int xbegin, int xend, int ybegin, int yend,
                        int zbegin, int zend, 
                        int firstchan, int nchans,
                        TypeDesc format, void *data,
                        stride_t xstride, stride_t ystride, stride_t zstride)
{
    if (! m_spec.valid_tile_range (xbegin, xend, ybegin, yend, zbegin, zend))
        return false;

    nchans = std::min (nchans, m_spec.nchannels-firstchan);
    // native_pixel_bytes is the size of a pixel in the FILE, including
    // the per-channel format.
    stride_t native_pixel_bytes = (stride_t) m_spec.pixel_bytes (firstchan, nchans, true);
    // perchanfile is true if the file has different per-channel formats
    bool perchanfile = m_spec.channelformats.size();
    // native_data is true if the user asking for data in the native format
    bool native_data = (format == TypeDesc::UNKNOWN ||
                        (format == m_spec.format && !perchanfile));
    if (format == TypeDesc::UNKNOWN && xstride == AutoStride)
        xstride = native_pixel_bytes;
    m_spec.auto_stride (xstride, ystride, zstride, format, nchans,
                        xend-xbegin, yend-ybegin);
    // Do the strides indicate that the data area is contiguous?
    bool contiguous = (native_data && xstride == native_pixel_bytes) ||
        (!native_data && xstride == (stride_t)m_spec.pixel_bytes(false));
    contiguous &= (ystride == xstride*(xend-xbegin) &&
                   (zstride == ystride*(yend-ybegin) || (zend-zbegin) <= 1));

    int nxtiles = (xend - xbegin + m_spec.tile_width - 1) / m_spec.tile_width;
    int nytiles = (yend - ybegin + m_spec.tile_height - 1) / m_spec.tile_height;
    int nztiles = (zend - zbegin + m_spec.tile_depth - 1) / m_spec.tile_depth;

    // If user's format and strides are set up to accept the native data
    // layout, and we're asking for a whole number of tiles (no partial
    // tiles at the edges), then read the tile directly into the user's
    // buffer.
    if (native_data && contiguous &&
        (xend-xbegin) == nxtiles*m_spec.tile_width &&
        (yend-ybegin) == nytiles*m_spec.tile_height &&
        (zend-zbegin) == nztiles*m_spec.tile_depth) {
        if (firstchan == 0 && nchans == m_spec.nchannels)
            return read_native_tiles (xbegin, xend, ybegin, yend, zbegin, zend,
                                      data);  // Simple case
        else
            return read_native_tiles (xbegin, xend, ybegin, yend, zbegin, zend,
                                      firstchan, nchans, data);
    }

    // No such luck.  Just punt and read tiles individually.
    bool ok = true;
    stride_t pixelsize = native_data ? native_pixel_bytes 
                                     : (format.size() * nchans);
    stride_t full_pixelsize = native_data ? m_spec.pixel_bytes(true)
                                          : (format.size() * m_spec.nchannels);
    size_t prefix_bytes = m_spec.pixel_bytes (0,firstchan,true);
    std::vector<char> buf;
    for (int z = zbegin;  z < zend;  z += std::max(1,m_spec.tile_depth)) {
        int zd = std::min (zend-z, m_spec.tile_depth);
        for (int y = ybegin;  y < yend;  y += m_spec.tile_height) {
            char *tilestart = ((char *)data + (z-zbegin)*zstride
                               + (y-ybegin)*ystride);
            int yh = std::min (yend-y, m_spec.tile_height);
            for (int x = xbegin;  ok && x < xend;  x += m_spec.tile_width) {
                int xw = std::min (xend-x, m_spec.tile_width);
                // Full tiles are read directly into the user buffer,
                // but partial tiles (such as at the image edge) or
                // partial channel subsets are read into a buffer and
                // then copied.
                if (xw == m_spec.tile_width && yh == m_spec.tile_height &&
                      zd == m_spec.tile_depth &&
                      firstchan == 0 && nchans == m_spec.nchannels) {
                    ok &= read_tile (x, y, z, format, tilestart,
                                     xstride, ystride, zstride);
                } else {
                    buf.resize (m_spec.tile_bytes());
                    ok &= read_tile (x, y, z, format, &buf[0],
                                     full_pixelsize,
                                     full_pixelsize*m_spec.tile_width,
                                     full_pixelsize*m_spec.tile_pixels());
                    if (ok)
                        copy_image (nchans, xw, yh, zd, &buf[prefix_bytes],
                                    pixelsize, full_pixelsize,
                                    full_pixelsize*m_spec.tile_width,
                                    full_pixelsize*m_spec.tile_pixels(),
                                    tilestart, xstride, ystride, zstride);
                }
                tilestart += m_spec.tile_width * xstride;
            }
        }
    }

    if (! ok)
        error ("ImageInput::read_tiles : no support for format %s",
               m_spec.format.c_str());
    return ok;
}