谷歌開源項目Google Preview Image Extractor(PIEX) (附上完整demo代碼)


前天偶然看到谷歌開源項目中有一個近乎無人問津的項目Google Preview Image Extractor(PIEX) 。

項目地址:

https://github.com/google/piex

官方的描述是這樣的:

The Preview Image Extractor (PIEX) is designed to find and extract the largest
JPEG compressed preview image contained in a RAW file.

也就是說,這個項目是用來提取無損圖片格式(RAW格式)中內嵌的JPG預覽。
閱讀代碼和實際編寫demo后,發現不是所有的無損圖片格式(RAW格式)都有內嵌jpg預覽,理論上最新的攝像設備應該都支持內嵌預覽圖了。
支持解析載入如下圖像格式: ARW, CR2, DNG, NEF, NRW, ORF, PEF, RAF, RW2, SRW
感覺支持的格式也挺全面的。

而該項目下面沒有example相關的代碼,由於感興趣,故閱讀其代碼寫了demo。

這個項目可以考慮用在特定情況下加速加載無損格式的預覽圖,提升用戶體驗。

關於本人采用的一些RAW格式素材的下載,見鏈接:
http://www.ed2kfile.com/126607
注:這些素材有部分是沒有內嵌預覽jpg的。

貼上對應的提取效果圖:

[無損格式圖片集合].sony_a200_3[www.ed2kfile.com].ARW

電驢下載鏈接:
ed2k://|file|[%E6%97%A0%E6%8D%9F%E6%A0%BC%E5%BC%8F%E5%9B%BE%E7%89%87%E9%9B%86%E5%90%88].sony_a200_3[www.ed2kfile.com].ARW|10689180|c0ed57fc9898e1f75d55cdca62cd8ee8|h=gsggltnbno7emg4l2ns5qyi6pedcnub3|/
預覽圖:


縮略圖:

貼上完整demo代碼:

#include <iostream> 
#include <windows.h>
#include "piex/piex.h"
#include "piex/piex_types.h" 
#include <fstream> 
#include <vector>
#if defined(_MSC_VER) || defined(__ANDROID_API__)
#define USE_OMP
#endif
#ifndef USE_OMP
#include <chrono>
auto const epoch = std::chrono::steady_clock::now();
double now() {
	return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - epoch).count() / 1000.0;
};
#else
#include <omp.h>
auto const epoch = omp_get_wtime();
double now() {
	return omp_get_wtime() - epoch;
};
#endif
template<typename FN>
double bench(const FN &fn) {
	auto took = -now();
	return (fn(), took + now());
}
#include <chrono>
#include <thread>
void sleep(double secs) {
	std::chrono::microseconds duration((int)(secs * 1000000));
	std::this_thread::sleep_for(duration);
}


class FileStream : public piex::StreamInterface
{
public:
	FileStream(const std::string & file)
	{
		if (file.empty()) {
			buffer.clear();
			bufferSize = 0;
			return;
		}
		std::ifstream ifs(file.c_str(), std::ios::binary);
		if (!ifs.good()) {
			buffer.clear();
			bufferSize = 0;
			return;
		}
		std::vector<unsigned char> curBuffer((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
		buffer.swap(curBuffer);
		bufferSize = buffer.size();

	}
	FileStream(std::vector<unsigned char>& abuffer)
	{
		int bufsize = abuffer.size();
		if (bufsize > 0)
		{
			buffer.resize(bufsize);
			memcpy(buffer.data(), abuffer.data(), bufsize*sizeof(unsigned char));
			bufferSize = bufsize;
		}
	}
	~FileStream(){ bufferSize = 0; buffer.clear(); };
	piex::Error GetData(const size_t offset, const size_t length,
		unsigned char* data)
	{
		if (bufferSize > 0)
		{
			unsigned char *readOffset = &buffer[offset];
			unsigned char *endBuffer = &buffer[bufferSize - 1];
			if ((readOffset + length) <= endBuffer)
			{
				memcpy(data, readOffset, length);
				return	piex::kOk;
			}
			else
			{
				return	piex::kFail;
			}
		}
		return	piex::kUnsupported;
	}

	std::vector<unsigned char>& GetBuffer()
	{
		return	buffer;
	}
protected:
	std::vector<unsigned char> buffer;
	int  bufferSize = 0;
};

bool writefile(const std::string &filename, const std::vector< char>& buffer) {
	if (!buffer.empty()) {
		std::ofstream ofs(filename.c_str(), std::ios::binary);
		ofs.write(&buffer[0], buffer.size());
		return ofs.good();
	}
	return false;
}
int main(int argc, char **argv) {

	std::cout << "Google Preview Image Extractor(PIEX) Demo" << std::endl;
	std::cout << "項目地址:https://github.com/google/piex" << std::endl;
	std::cout << "-----------------------------------------------------" << std::endl;
	std::cout << "支持解析載入如下圖像格式: " << std::endl;
	std::cout << "ARW, CR2, DNG, NEF, NRW, " << std::endl;
	std::cout << "ORF, PEF, RAF, RW2, SRW" << std::endl;
	std::cout << " 輸出JPG圖像格式." << std::endl;
	std::cout << "Demo By Gaozhihan (Build 2016-01-19)" << std::endl;
	std::cout << "本人博客: http://tntmonks.cnblogs.com/" << std::endl;
	std::cout << "-----------------------------------------------------" << std::endl;
	if (argc < 2) {
		std::cout << "用法: " << argv[0] << " rawImage [rawImage [...]]" << std::endl;
		return -1;
	}
	std::string szfile;
	std::string savefile;

	for (int i = 1; i < argc; ++i) {
		szfile = argv[i];
		std::cout << "加載文件: " << std::endl << szfile.c_str() << std::endl;
		char drive[_MAX_DRIVE];
		char dir[_MAX_DIR];
		char fname[_MAX_FNAME];
		char ext[_MAX_EXT];
		_splitpath_s(szfile.c_str(), drive, dir, fname, ext);
		savefile += drive;
		savefile += dir;
		savefile += fname;
		savefile += "_";
		std::vector< char> previewBuffer;
		std::vector< char> previewThumbnail;

		try {
			double costTime = bench([&]{
				FileStream fsfile(szfile.c_str());
				piex::StreamInterface* data_stream = &fsfile;
				piex::PreviewImageData rawPreviewImage;
				piex::Error piexErr = piex::GetPreviewImageData(data_stream, &rawPreviewImage);
				if (piexErr == piex::Error::kFail) {
					std::cout << "傳入的無損格式文件數據有誤." << std::endl;
				}
				else if (piexErr == piex::Error::kUnsupported) {
					std::cout << "傳入的無損格式文件數據不支持." << std::endl;
				}
				else
				{
					std::cout << " 有效raw 格式,提取內嵌預覽數據." << std::endl;
					previewBuffer.resize(rawPreviewImage.preview_length);
					memcpy(previewBuffer.data(), fsfile.GetBuffer().data() + rawPreviewImage.preview_offset, rawPreviewImage.preview_length);

					previewThumbnail.resize(rawPreviewImage.thumbnail_length);
					memcpy(previewThumbnail.data(), fsfile.GetBuffer().data() + rawPreviewImage.thumbnail_offset, rawPreviewImage.thumbnail_length);
				}
			});
			std::cout << " 處理耗時: " << int(costTime * 1000) << " ms" << std::endl;

			std::string previewFile = savefile;
			previewFile += "_preview.jpg";

			std::string thumbnailFile = savefile;
			thumbnailFile += "_thumbnail.jpg";
			costTime = bench([&]{
				writefile(previewFile, previewBuffer);
				writefile(thumbnailFile, previewThumbnail);
			});
			std::cout << " 保存耗時: " << int(costTime * 1000) << " ms" << std::endl;
			ShellExecuteA(NULL, "open", previewFile.c_str(), NULL, NULL, SW_SHOW);
		}
		catch (...) {
			std::cout << "\r出錯!" << std::endl;
		}
	}
	std::cout << "處理完畢,按任意鍵退出." << std::endl;
	getchar();
	return 0;
}

 

本文只是拋磚引玉一下,若有其他相關問題或者需求也可以郵件聯系我探討。

 郵箱地址是:

gaozhihan@vip.qq.com


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM