char* webpGetXMP(const uint8_t* data, size_t data_size, size_t* metadata_size) { char* metadata = NULL; WebPData webp_data = {data, data_size}; WebPDemuxer* demux = WebPDemux(&webp_data); uint32_t flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS); *metadata_size = 0; if(flags & XMP_FLAG) { WebPChunkIterator it; memset(&it, 0, sizeof(it)); if(WebPDemuxGetChunk(demux, "XMP ", 1, &it)) { if(it.chunk.bytes != NULL && it.chunk.size > 0) { metadata = (char*)malloc(it.chunk.size); memcpy(metadata, it.chunk.bytes, it.chunk.size); *metadata_size = it.chunk.size; } } WebPDemuxReleaseChunkIterator(&it); } WebPDemuxDelete(demux); return metadata; }
/** * Uses libwebp to extract xmp metadata. */ const std::vector<uint8_t> extractMetadata( JNIEnv* env, std::vector<uint8_t>& image_data) { // Create WebPDemux from provided data. // It is "index" of all chunks. It stores // list of pointers to particular chunks, but does // not copy memory from provided WebPData. WebPData webpdata = {image_data.data(), image_data.size()}; // Thsnks to using RAII we do not need to worry about // releasing WebPDemuxer structure auto demux = std::unique_ptr<WebPDemuxer, decltype(&WebPDemuxDelete)>{ WebPDemux(&webpdata), WebPDemuxDelete}; THROW_AND_RETURNVAL_IF( demux == nullptr, "Could not create WebPDemux from image. This webp might be malformed.", {}); // find xmp chunk WebPChunkIterator chunk_iterator; if (!WebPDemuxGetChunk(demux.get(), "XMP ", 1, &chunk_iterator)) { // we failed to find "XMP " chunk - don't worry, maybe it was not // there. Let the transcode proceed WebPDemuxReleaseChunkIterator(&chunk_iterator); return {}; } // we managed to find "XMP " chunk, let's return its size and pointer to it const unsigned int metadata_length = chunk_iterator.chunk.size; const uint8_t* metadata_ptr = chunk_iterator.chunk.bytes; WebPDemuxReleaseChunkIterator(&chunk_iterator); // If XMP chunk contains no data then return nullptr. if (metadata_length == 0) { return {}; } return {metadata_ptr, metadata_ptr + metadata_length}; }
bool QWebpHandler::ensureScanned() const { if (m_scanState != ScanNotScanned) return m_scanState == ScanSuccess; m_scanState = ScanError; if (device()->isSequential()) { qWarning() << "Sequential devices are not supported"; return false; } QWebpHandler *that = const_cast<QWebpHandler *>(this); // FIXME: should not read all when scanning that->m_rawData = device()->readAll(); that->m_webpData.bytes = reinterpret_cast<const uint8_t *>(m_rawData.data()); that->m_webpData.size = m_rawData.size(); that->m_demuxer = WebPDemux(&m_webpData); if (m_demuxer == NULL) return false; that->m_flags = WebPDemuxGetI(m_demuxer, WEBP_FF_FORMAT_FLAGS); that->m_width = WebPDemuxGetI(m_demuxer, WEBP_FF_CANVAS_WIDTH); that->m_height = WebPDemuxGetI(m_demuxer, WEBP_FF_CANVAS_HEIGHT); that->m_loop = WebPDemuxGetI(m_demuxer, WEBP_FF_LOOP_COUNT); that->m_frameCount = WebPDemuxGetI(m_demuxer, WEBP_FF_FRAME_COUNT); if (!WebPDemuxGetFrame(m_demuxer, 1, &(that->m_iter))) { return false; } m_scanState = ScanSuccess; return true; }