Saving webp images as binary
-
I have implemented saving multiple jpeg binary data into one file for web. this works fine.
I want to switch to webp with smaller capacity.
The data structure of the file is:
For this, the following functions are used.
void WPubManager::SaveBkgndBitmap(QFile& file) { if(m_pList.size() == 0 || m_pList.size() < 0) return ; // _increment is Data address in file _increment = SizeHeaderOffBits(); for (const auto& bkgnd : m_pList) { _increment = bkgnd->encodeWebp(file, position, _increment); } } unsigned long CBackground::encodeWebp(QFile& file, fpos_t position, unsigned long newAddress) { QImageReader reader(m_strBkgndImagePath); if (!reader.canRead()) { throw std::runtime_error("Cannot read image"); } std::unique_ptr<QImage> unique_img(new QImage(reader.read())); if (unique_img->isNull()) { throw std::runtime_error("Cannot create image from file"); } int width = unique_img->size().width(); int height = unique_img->size().height(); WebPConfig config; WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, 80/*quality*/); config.lossless = 0; // Use lossy compression config.alpha_quality = 80; // Maximum alpha quality config.use_sharp_yuv = 1; // Use RGB color space // Set up memory writer WebPMemoryWriter writer; WebPMemoryWriterInit(&writer); WebPPicture pic; WebPPictureInit(&pic); // Set up picture pic.use_argb = 1; pic.width = width; pic.height = height; pic.colorspace = WEBP_YUV420; pic.writer = WebPMemoryWrite; pic.custom_ptr = &writer; // Copy image data to picture const uint8_t* src = reinterpret_cast<const uint8_t*>(unique_img->constBits()); const int src_stride = width * 4; if (!WebPPictureImportRGBA(&pic, src, src_stride)) { WebPPictureFree(&pic); throw std::runtime_error("WebPPictureImportRGBA failed"); // 예외 던지기 } if (!WebPEncode(&config, &pic)) { WebPPictureFree(&pic); throw std::runtime_error("WebPEncode failed"); // 예외 던지기 } // Write the compressed image data to file QByteArray byteArray(reinterpret_cast<const char*>(writer.mem), writer.size); // m_bkgndHeader is background struncture data m_bkgndHeader.ImageSize = (unsigned int)byteArray.size(); m_bkgndHeader.ImageAddress = newAddress; position = (fpos_t)newAddress; file.seek(position); file.write(byteArray.constData(), m_bkgndHeader.ImageSize); WebPPictureFree(&pic); cout << m_bkgndHeader.Page << "\t" << byteArray.size() << endl; return m_bkgndHeader.ImageSize + m_bkgndHeader.ImageAddress; }
But when I run this file it crashes and closes with the following result:
1 264 556
2-353680
3 76096
4 74454
5 186732
6 9220
7 11194
testpro.exe crashed.Debugging mode points this out.
if (!WebPPictureImportRGBA(&pic, src, src_stride)) { // here WebPPictureFree(&pic); return false; }
I've tried saving only one of these.
The following is an image when opened with a binary editor.
This is the Webp
This is what I saved as binary.
The data seems to be stored fine.
I am trying to open it with the following function but the image is not displayed.bool WPubManager::draw() { // image is QImage pointer if(!image->isNull()){ if (image->colorSpace().isValid()){ image->convertToColorSpace(QColorSpace::SRgb); } canvas.setPixmap(QPixmap::fromImage(*image)); canvas.setScaledContents(true); canvas.setFixedSize(image->size()); canvas.adjustSize(); return true; }else{ QMessageBox::information(nullptr, "Drawing Image", "Failed"); return false; } } void WPubManager::setDraw() { if(image == nullptr) return; draw(); if(!image->isNull()) delete image; image = nullptr; } void WPubManager::readBinaryFromFile() { QFile file(*m_projectPathName); image = &m_pBkgnd->decodeWebp(&file); setDraw(); } QImage &CBackground::decodeWebp(QFile *pFile) { long imageSize = m_bkgndHeader.ImageSize; long imageAddress = m_bkgndHeader.ImageAddress; if (!pFile->seek(imageAddress)) { throw std::runtime_error("Failed to seek to image data"); } QByteArray imageData(imageSize, 0); if (pFile->read(imageData.data(), imageSize) != imageSize) { throw std::runtime_error("Failed to read image data"); } int width, height; uchar* decodedData = WebPDecodeRGBA(reinterpret_cast<uchar*>(imageData.data()), imageSize, &width, &height); if (!decodedData) { throw std::runtime_error("Failed to decode WebP image"); } m_pBkgndImage = new QImage(decodedData, width, height, width*4, QImage::Format_RGBA8888); free(decodedData); qDebug() << "bkgng: width: " << m_bkgndHeader.Width << "height: " << m_bkgndHeader.Height; qDebug() << "QImage width:" << width << "height:" << height; return *m_pBkgndImage; }
It looks like an issue accessing an inaccessible memory block. Why am I getting this error?
And why does it fail to load the saved file and draw? -
Hi,
One thing that I see that I find problematic is that if the color space is invalid, you just load the data as they are. I might be wrong but I don't think it's in the correct format in that case.
-
@MyNameIsQt said in Saving webp images as binary:
uchar* decodedData = WebPDecodeRGBA(reinterpret_cast<uchar*>(imageData.data()), imageSize, &width, &height); if (!decodedData) { throw std::runtime_error("Failed to decode WebP image"); } m_pBkgndImage = new QImage(decodedData, width, height, width*4, QImage::Format_RGBA8888); free(decodedData);
Apart from all the other strang pointer stuff - why do you need to create averything as pointer (QString, QImage, ...) - it just makes the stuff unreadable you did a common error - not reading the documentation for stuff you're using:
"The buffer must remain valid throughout the life of the QImage and all copies that have not been modified or otherwise detached from the original buffer. The image does not delete the buffer at destruction. You can provide a function pointer cleanupFunction along with an extra pointer cleanupInfo that will be called when the last copy is destroyed."
-
@Christian-Ehrlicher
m_pBkgndImage is a member of CBackground.
This function returns a reference, not a pointer.
References do not cost copies upon return.
Thanks :) -
@MyNameIsQt said in Saving webp images as binary:
This function returns a reference, not a pointer.
References do not cost copies upon return.It would not cost anything extra when it would return a QImage object...
-
@Christian-Ehrlicher I've heard your opinion and reconsidered. I think it is not good from a design point of view to handle the drawing of m_pBkgndImage, which is a member of CBackground, in another class. It would be better to create an OnDraw function in CBackgrund and handle it. thank you
-