// // ReadImage() // read a PNG format image into memory, returning the image itself // This version reads a subpart of an image // CImage* CImageIOPng::ReadImage(CNcbiIstream& istr, size_t x, size_t y, size_t w, size_t h) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_infop end_ptr = NULL; CRef<CImage> image; try { // create our PNG structures s_PngReadInit(png_ptr, info_ptr, end_ptr); // begin reading our image png_set_read_fn(png_ptr, &istr, s_PngRead); png_read_info(png_ptr, info_ptr); // store and validate our image's parameters size_t width = 0; size_t height = 0; size_t depth = 0; s_PngReadValidate(png_ptr, info_ptr, width, height, depth, x, y, w, h); // allocate our image image.Reset(new CImage(w, h, depth)); unsigned char* to_data = image->SetData(); size_t to_stride = image->GetWidth() * image->GetDepth(); size_t to_offs = x * image->GetDepth(); // allocate a scanline for this image vector<unsigned char> row(width * depth); unsigned char* row_ptr = &row[0]; size_t i; // read up to our starting scan line for (i = 0; i < y; ++i) { png_read_row(png_ptr, row_ptr, NULL); } // read and convert the scanlines of interest for ( ; i < y + h; ++i) { png_read_row(png_ptr, row_ptr, NULL); memcpy(to_data, row_ptr + to_offs, to_stride); to_data += to_stride; } /** // read the rest of the image (do we need this?) for ( ; i < height; ++i) { png_read_row(png_ptr, row_ptr, NULL); } // read the end pointer png_read_end(png_ptr, end_ptr); **/ // close and return s_PngReadFinalize(png_ptr, info_ptr, end_ptr); } catch (...) { // destroy everything s_PngReadFinalize(png_ptr, info_ptr, end_ptr); // rethrow throw; } return image.Release(); }