前天偶然看到谷歌开源项目中有一个近乎无人问津的项目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

谷歌开源项目Google Preview Image Extractor(PIEX) (附上完整demo代码)的更多相关文章

  1. 谷歌开源项目Chromium的源码获取与项目构建(Win7+vs10/vs13)

    转自:http://blog.csdn.net/kuerjinjin/article/details/23563059 从12年那会儿开始获取源码和构建chromium项目都是按照那时候的官方要求用w ...

  2. 【转】Android开源项目(非组件)

    原文网址:http://blog.csdn.net/feizhixuan46789/article/details/9252887 学习开发一个有效的途径就是借鉴成熟的案例作为学习的对象,下面为大家推 ...

  3. apache基金会开源项目简介

    apache基金会开源项目简介   项目名称 描述 HTTP Server 互联网上首屈一指的HTTP服务器 Abdera Apache  Abdera项目的目标是建立一个功能完备,高效能的IETF ...

  4. Golang优秀开源项目汇总, 10大流行Go语言开源项目, golang 开源项目全集(golang/go/wiki/Projects), GitHub上优秀的Go开源项目

    Golang优秀开源项目汇总(持续更新...)我把这个汇总放在github上了, 后面更新也会在github上更新. https://github.com/hackstoic/golang-open- ...

  5. 如何参与开源项目 - 细说 GitHub 上的 PR 全过程

    目录 一.概述 二.为什么要参与开源项目 三.为什么我想介绍如何 PR 四.我想参与开源项目,怎么开始? 4.1.寻找一个合适的开源项目 4.2.寻找贡献点 五.我要提交 PR,怎么上手? 5.1.第 ...

  6. .NET平台开源项目速览(14)最快的对象映射组件Tiny Mapper

    好久没有写文章,工作甚忙,但每日还是关注.NET领域的开源项目.五一休息,放松了一下之后,今天就给大家介绍一个轻量级的对象映射工具Tiny Mapper:号称是.NET平台最快的对象映射组件.那就一起 ...

  7. Android(java)学习笔记207:开源项目使用之gif view

    1. 由于android没有自带的gif动画,我在Android(java)学习笔记198:Android下的帧动画(Drawable Animation) 播客中提到可以使用AnimationVie ...

  8. 开源项目福利-github开源项目免费使用Azure PipeLine

    微软收购Github后,很多人猜想微软可能会砍掉VSTS,然而事实VSTS并没有砍掉,关于Azure Devops的详细信息可以查看 这篇博客,如果想查看原文也可以从链接里提供的原始地址里查看. 今天 ...

  9. 如何把开源项目发布到Jcenter

    转载自:https://www.jianshu.com/p/f66972f0607a 首先我们应该注册一个JFrog Bintray的账号 Jfrog Bintray官网 这里我们可以注意到那个绿色的 ...

随机推荐

  1. 基于 ANSIBLE 自动化运维实践

    摘要:运维这个话题很痛苦,你做任何的产品都离不开运维.不管你用什么语言.什么平台.什么技术,真正能够决定你产品成熟度的很有可能就是你运维的能力.取自 云巴 CEO 张虎在 ECUG 大会上的分享. 云 ...

  2. memcache与memcached扩展的区别

    一.服务端 之前理解错误了.服务端只有一个memcache,一般把服务端称作memcached(带d),是因为守护进程的名称就是叫做memcached(一个这样的执行程序文件). 编写的语言:c语言 ...

  3. SQL Server性能影响的重要结论

    第一次访问数据会比接下来的访问慢的多,因为它要从磁盘读取数据然后写入到缓冲区: 聚合查询(sum,count等)以及其他要扫描大部分表或索引的查询需要大量的缓冲,而且如果它导致SQL Server从缓 ...

  4. 【使用 DOM】使用 DOM 元素

    1. 使用元素对象 HTMLElement对象提供了一组属性,可以用它们来读取和修改被代表的数据.下表介绍了这些属性. 下面代码展示了如何使用表中所列的一些基本属性. <!DOCTYPE htm ...

  5. thinkPHP学习笔记(1)

    现在对前端的要求越来越高了  基本上身为一个前端人员需要会一种后台语言,于是选择了当下流行的php.因为是自学对我这个不怎么懂代码的人来说还是有点难度的. 1.先看看thinkphp的目录结构 ├─T ...

  6. 2015年第14本(英文第10本):The A.B.C. Murders (A.B.C谋杀案)

    书名:The ABC Murders 推荐指数:5星 作者:Agatha Christie 单词数:7万 不重复单词数:不详 首万词不重复单词数:不详 蓝思值:740 阅读时间:2015年7月18日 ...

  7. VC连接mysql数据库错误:libmysql.lib : fatal error LNK1113: invalid machine 解决方法

    VC连接MySQL的配置过程在上一篇博文中,不过当你设置好,以为万事大吉的时候,运行却出现这个错误:libmysql.lib : fatal error LNK1113: invalid machin ...

  8. android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件

    简介 XStream 是一个开源项目,一套简单实用的类库,用于序列化对象与 XML 对象之间的相互转换. 将 XML 文件内容解析为一个对象或将一个对象序列化为 XML 文件. 1.下载工具 xstr ...

  9. C编程常见问题总结

    本文是C编程中一些常见错误的总结,有些是显而易见的,有些则是不容易发现 本文地址:http://www.cnblogs.com/archimedes/p/get-screwed-c.html,转载请注 ...

  10. JAVA基础学习day24--Socket基础一UDP与TCP的基本使用

    一.网络模型 1.1.OIS参考模型 1.2.TCP/IP参考模型 1.3.网络通讯要素 IP地址:IPV4/IPV6 端口号:0-65535,一般0-1024,都被系统占用,mysql:3306,o ...