void jpeg_reader<T>::init() { jpeg_decompress_struct cinfo; jpeg_info_guard iguard(&cinfo); jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = on_error; jerr.output_message = on_error_message; jpeg_create_decompress(&cinfo); attach_stream(&cinfo, &stream_); int ret = jpeg_read_header(&cinfo, TRUE); if (ret != JPEG_HEADER_OK) throw image_reader_exception("JPEG Reader: failed to read header"); jpeg_start_decompress(&cinfo); width_ = cinfo.output_width; height_ = cinfo.output_height; if (cinfo.out_color_space == JCS_UNKNOWN) { throw image_reader_exception("JPEG Reader: failed to read unknown color space"); } if (cinfo.output_width == 0 || cinfo.output_height == 0) { throw image_reader_exception("JPEG Reader: failed to read image size of"); } }
PremultipliedImage decodeJPEG(const uint8_t* data, size_t size) { util::CharArrayBuffer dataBuffer { reinterpret_cast<const char*>(data), size }; std::istream stream(&dataBuffer); jpeg_decompress_struct cinfo; jpeg_info_guard iguard(&cinfo); jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = on_error; jerr.output_message = on_error_message; jpeg_create_decompress(&cinfo); attach_stream(&cinfo, &stream); int ret = jpeg_read_header(&cinfo, TRUE); if (ret != JPEG_HEADER_OK) throw std::runtime_error("JPEG Reader: failed to read header"); jpeg_start_decompress(&cinfo); if (cinfo.out_color_space == JCS_UNKNOWN) throw std::runtime_error("JPEG Reader: failed to read unknown color space"); if (cinfo.output_width == 0 || cinfo.output_height == 0) throw std::runtime_error("JPEG Reader: failed to read image size"); size_t width = cinfo.output_width; size_t height = cinfo.output_height; size_t components = cinfo.output_components; size_t rowStride = components * width; PremultipliedImage image({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) }); uint8_t* dst = image.data.get(); JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, rowStride, 1); while (cinfo.output_scanline < cinfo.output_height) { jpeg_read_scanlines(&cinfo, buffer, 1); for (size_t i = 0; i < width; ++i) { dst[0] = buffer[0][components * i]; dst[3] = 0xFF; if (components > 2) { dst[1] = buffer[0][components * i + 1]; dst[2] = buffer[0][components * i + 2]; } else { dst[1] = dst[0]; dst[2] = dst[0]; } dst += 4; } } jpeg_finish_decompress(&cinfo); return image; }
void jpeg_reader<T>::read(unsigned x0, unsigned y0, image_data_32& image) { stream_.clear(); stream_.seekg(0, std::ios_base::beg); jpeg_decompress_struct cinfo; jpeg_info_guard iguard(&cinfo); jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = on_error; jerr.output_message = on_error_message; jpeg_create_decompress(&cinfo); attach_stream(&cinfo, &stream_); int ret = jpeg_read_header(&cinfo, TRUE); if (ret != JPEG_HEADER_OK) throw image_reader_exception("JPEG Reader read(): failed to read header"); jpeg_start_decompress(&cinfo); JSAMPARRAY buffer; int row_stride; unsigned char a,r,g,b; row_stride = cinfo.output_width * cinfo.output_components; buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); unsigned w = std::min(unsigned(image.width()),width_ - x0); unsigned h = std::min(unsigned(image.height()),height_ - y0); const std::unique_ptr<unsigned int[]> out_row(new unsigned int[w]); unsigned row = 0; while (cinfo.output_scanline < cinfo.output_height) { jpeg_read_scanlines(&cinfo, buffer, 1); if (row >= y0 && row < y0 + h) { for (unsigned int x = 0; x < w; ++x) { unsigned col = x + x0; a = 255; // alpha not supported in jpg r = buffer[0][cinfo.output_components * col]; if (cinfo.output_components > 2) { g = buffer[0][cinfo.output_components * col + 1]; b = buffer[0][cinfo.output_components * col + 2]; } else { g = r; b = r; } out_row[x] = color(r, g, b, a).rgba(); } image.setRow(row - y0, out_row.get(), w); } ++row; } jpeg_finish_decompress(&cinfo); }