heic(HEIF)格式图像处理(四)

读取heic格式图像

读取heic格式图像主要通过第三方库实现,首先创建读取的入口,在前面几期中讲过增加“打开”菜单按钮实现功能。

增加“打开图片”菜单:

	QMenu *pMenu = menuBar()->addMenu(QStringLiteral("文件(&F)"));
	QAction *pOpenFile = new QAction(QStringLiteral("打开图片(&O)"));
	connect(pOpenFile, &QAction::triggered, this, &heicExample::OpenFile);
	QAction *pExit = new QAction(QStringLiteral("退出(&Q)"));
	pMenu->addAction(pOpenFile);
	pMenu->addAction(pExit);

实现槽函数OpenFile:

void heicExample::OpenFile()
{
	QString fileName = QFileDialog::getOpenFileName(
		this, 
		tr("open image file"), "./", 
		tr("Image files(*.bmp *.jpg *.pbm *.pgm *.png *.ppm *.xbm *.xpm *.heic);;All files (*.*)"));  
	if (pixItem && fileName != "")
	{
		m_graphicsScene->removeItem(pixItem);   //将上一个图元从场景中移除,重新添加新的图元
		delete pixItem;
		pixItem = NULL;
		for (int i = 0; i < m_loldrgb.length(); i++)
		{
			delete m_loldrgb[i];
			m_loldrgb[i] = NULL;
		}
		m_loldrgb.clear();
	}
	
	if(fileName.contains(".heic"))
	{
		ReadHeif(fileName);
	}
}

读取heic格式文件:

void heicExample::ReadHeif(QString filename)
{
	filename = QDir::fromNativeSeparators(filename);
	Array itemIds;
	const char* outputFileName = "./abc";

	// Make an instance of Heif Reader
	auto *reader = Reader::Create();
	if (reader->initialize(filename.toLatin1().data()) != ErrorCode::OK)
		return;
	// Verify that the file is HEIF format.
	FileInformation fileInfo;
	if (reader->getFileInformation(fileInfo) != ErrorCode::OK) {
		cout << "Unable to get MetaBox! Wrong heif format." << endl;
		return;
	}
	if (!(fileInfo.features & FileFeatureEnum::HasSingleImage ||
		fileInfo.features & FileFeatureEnum::HasImageCollection)) {
		cout << "The file don't have images in the Metabox. " << endl;
		return;
	}
	
	uint64_t memoryBufferSize = 1024 * 1024;
	ofstream outfile(outputFileName, ofstream::binary);
	auto *memoryBuffer = new uint8_t[memoryBufferSize];

	const auto metaBoxFeatures = fileInfo.rootMetaBoxInformation.features;
	if (metaBoxFeatures & MetaBoxFeatureEnum::HasThumbnails)
	{
		//reader->getMasterImages(itemIds);
		//const ImageId masterId = itemIds[0];
		cout << "The file have Thumbnail." << endl;
		// Thumbnail references ('thmb') are from the thumbnail image to the master image
		//reader->getReferencedToItemListByType(masterId, "thmb", itemIds);
		//const auto thumbnailId = itemIds[0];

		//if (reader->getItemDataWithDecoderParameters(thumbnailId.get(), memoryBuffer, memoryBufferSize) == ErrorCode::OK)
		//{
			// ...decode data and display the image, show master image later
		//	EncodePlay(memoryBuffer, memoryBufferSize);
		//	return;
		//}
	}

	// when the file is iPhone heic.
	Array gridIds;
	Grid gridData;
	if (reader->getItemListByType("grid", gridIds) == ErrorCode::OK &&
		(fileInfo.features & FileFeatureEnum::HasImageCollection) &&
		reader->getItem(gridIds[0].get(), gridData) == ErrorCode::OK)
	{
		//return iphoneHeic(reader, gridData, outputFileName);
		qDebug("iphone heic");
	}

	// The image have collections
	
	if (fileInfo.features & FileFeatureEnum::HasImageCollection)
	{
		Array itemIds;
		reader->getMasterImages(itemIds);
		// all the image items
		for (unsigned int i = 0; i < itemIds.size; i++) {
			const ImageId masterId = itemIds[i];
			if (reader->getItemDataWithDecoderParameters(
				masterId.get(), memoryBuffer, memoryBufferSize) == ErrorCode::OK) {
				DecoderConfiguration decodeConf; // struct containing
				reader->getDecoderParameterSets(masterId.get(), decodeConf);
				auto decoSpeInfo = decodeConf.decoderSpecificInfo;

				for (unsigned int j = 0; j < decoSpeInfo.size; ++j) {
					auto entry = decoSpeInfo[j];
					outfile.write((const char *)entry.decSpecInfoData.begin(),
						entry.decSpecInfoData.size);
				}
				outfile.write(reinterpret_cast(memoryBuffer), memoryBufferSize);
				if (i == 0)
				{
					EncodePlay(memoryBuffer, memoryBufferSize);
				}
				
			}
			else { cout << "getItemDataWithDecoderParameters error" << endl; }
		};
		delete[] memoryBuffer;
		Reader::Destroy(reader);
		return;
	}// The image only have 1 master image.
	else if (fileInfo.features & FileFeatureEnum::HasSingleImage)
	{
		Array itemIds;
		reader->getMasterImages(itemIds);

		// Find the item ID of the first master image
		const ImageId masterId = itemIds[0];
		if (reader->getItemDataWithDecoderParameters(masterId.get(), memoryBuffer, memoryBufferSize) == ErrorCode::OK)
		{
			outfile.write(reinterpret_cast(memoryBuffer), memoryBufferSize);
			cout << "Get the master image" << endl;
			// ffmpeg
			// Get HEVC decoder configuration
			EncodePlay(memoryBuffer, memoryBufferSize);
		}
	}
	 cout << "There no image in the file MetaBox! ";
	Reader::Destroy(reader);
	return;
}

通过EncodePlay函数解析heic格式图像:

void heicExample::EncodePlay(uint8_t * pData, int nDataLength)
{
	AVPacket packet;
	av_init_packet(&packet);
	packet.data = (uint8_t*)pData;
	packet.size = nDataLength;
	packet.pts = (90000 / 25) * m_nFrameCounter++;

	int ret = -1;
	ret = avcodec_send_packet(m_pCodecContext, &packet);
	// Again EAGAIN is not expected
	if (ret < 0)
	{
		return;
	}
	while (!ret)
	{
		ret = avcodec_receive_frame(m_pCodecContext, m_pSrcFrame);
		if (!ret)
		{
			//成功解码一帧
			int w = m_pCodecContext->width;
			int h = m_pCodecContext->height;
			if (m_pRGBSwsContext == NULL)
			{
				m_pRGBSwsContext = sws_getContext(w, h, m_pCodecContext->pix_fmt, w, h, AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);
				av_image_alloc(m_pFrameRGB->data, m_pFrameRGB->linesize, w, h, AV_PIX_FMT_RGB32, 1);
			}
			//转换图像格式,将解压出来的YUV420P的图像转换为RGB的图像
			sws_scale(m_pRGBSwsContext, (uint8_t const * const *)m_pSrcFrame->data, m_pSrcFrame->linesize, 0, h, m_pFrameRGB->data, m_pFrameRGB->linesize);
			//把这个RGB数据 用QImage加载
			QImage tmpImg((uchar *)m_pFrameRGB->data[0], m_pCodecContext->width, m_pCodecContext->height, QImage::Format_RGB32);
			image = tmpImg.copy();
			//把图像复制一份 传递给界面显示
			//emit signal_sendQImage(image);
			//ui.label->resize(w, h);
			//QImage img = image.scaled(ui.label->size(), Qt::KeepAspectRatio);
			//ui.label->setPixmap(QPixmap::fromImage(img));
			
			pixItem = new PixItem(QPixmap::fromImage(image));
			//将该图元对象添加到场景中,并设置此图元在场景中的位置为中心(0,0)
			m_graphicsScene->addItem(pixItem);
			pixItem->setPos(0, 0);
			//保存原来的颜色
			for (int x = 0; x < image.width(); x++) {
				for (int y = 0; y < image.height(); y++) {
					QColor *oldColor = new QColor(image.pixel(x, y));
					m_loldrgb.append(oldColor);
				}
			}

			av_frame_unref(m_pSrcFrame);
		}

	}
}

通过ffmpeg解码heic格式,然后转换成RGB32格式,最后通过画布进行展示。

你可能感兴趣的:(Qt,.heic格式图像处理教程,C++,c++)