| 407 | |
| 408 | |
| 409 | bool |
| 410 | ImageOutput::write_image (TypeDesc format, const void *data, |
| 411 | stride_t xstride, stride_t ystride, stride_t zstride, |
| 412 | ProgressCallback progress_callback, |
| 413 | void *progress_callback_data) |
| 414 | { |
| 415 | bool native = (format == TypeDesc::UNKNOWN); |
| 416 | stride_t pixel_bytes = native ? (stride_t) m_spec.pixel_bytes (native) |
| 417 | : format.size() * m_spec.nchannels; |
| 418 | if (xstride == AutoStride) |
| 419 | xstride = pixel_bytes; |
| 420 | m_spec.auto_stride (xstride, ystride, zstride, format, |
| 421 | m_spec.nchannels, m_spec.width, m_spec.height); |
| 422 | |
| 423 | if (supports ("rectangles")) { |
| 424 | // Use a rectangle if we can |
| 425 | return write_rectangle (0, m_spec.width, 0, m_spec.height, 0, m_spec.depth, |
| 426 | format, data, xstride, ystride, zstride); |
| 427 | } |
| 428 | |
| 429 | bool ok = true; |
| 430 | if (progress_callback && progress_callback (progress_callback_data, 0.0f)) |
| 431 | return ok; |
| 432 | if (m_spec.tile_width && supports ("tiles")) { |
| 433 | // Tiled image |
| 434 | for (int z = 0; z < m_spec.depth; z += m_spec.tile_depth) { |
| 435 | int zend = std::min (z+m_spec.z+m_spec.tile_depth, |
| 436 | m_spec.z+m_spec.depth); |
| 437 | for (int y = 0; y < m_spec.height; y += m_spec.tile_height) { |
| 438 | int yend = std::min (y+m_spec.y+m_spec.tile_height, |
| 439 | m_spec.y+m_spec.height); |
| 440 | const char *d = (const char *)data + z*zstride + y*ystride; |
| 441 | ok &= write_tiles (m_spec.x, m_spec.x+m_spec.width, |
| 442 | y+m_spec.y, yend, z+m_spec.z, zend, |
| 443 | format, d, xstride, ystride, zstride); |
| 444 | if (progress_callback && |
| 445 | progress_callback (progress_callback_data, |
| 446 | (float)(z*m_spec.height+y)/(m_spec.height*m_spec.depth))) |
| 447 | return ok; |
| 448 | } |
| 449 | } |
| 450 | } else { |
| 451 | // Scanline image |
| 452 | const int chunk = 256; |
| 453 | for (int z = 0; z < m_spec.depth; ++z) |
| 454 | for (int y = 0; y < m_spec.height && ok; y += chunk) { |
| 455 | int yend = std::min (y+m_spec.y+chunk, m_spec.y+m_spec.height); |
| 456 | const char *d = (const char *)data + z*zstride + y*ystride; |
| 457 | ok &= write_scanlines (y+m_spec.y, yend, z+m_spec.z, |
| 458 | format, d, xstride, ystride); |
| 459 | if (progress_callback && |
| 460 | progress_callback (progress_callback_data, |
| 461 | (float)(z*m_spec.height+y)/(m_spec.height*m_spec.depth))) |
| 462 | return ok; |
| 463 | } |
| 464 | } |
| 465 | if (progress_callback) |
| 466 | progress_callback (progress_callback_data, 1.0f); |