C++讀取一個png圖片資訊-[lenna.png]
PNG圖片格式
- PNG - Portable Network Graphics - 行動式網路圖形
- 行動式網路圖形(Portable Network Graphics)是一種無失真壓縮的點陣圖片形格式.
- 其設計目的是試圖替代GIF和TIFF檔案格式,同時增加一些GIF檔案格式所不具備的特性。
- PNG的名稱來源於“可移植網路圖形格式(Portable Network Graphic Format,PNG)”,也有一個非官方解釋“PNG's Not GIF”。
- PNG使用從LZ77派生的無損資料壓縮演算法,一般應用於JAVA程式、網頁或S60程式中,原因是它壓縮比高,生成檔案體積小。
- 8位元組的PNG檔案署名域用來識別該檔案是不是PNG檔案。該域的值是:
- 十進位制數: 137 80 78 71 13 10 26 10
- 十六進位制數: 89 50 4e 47 0d 0a 1a 0a
用C++讀取PNG圖片
#include <iostream>
#include <cstdint>
#include <cstring>
#include <algorithm>
#include <fstream>
#include <iostream> // tmp debugging
#include <unordered_map>
#include <string>
#include <memory>
#ifndef _PNG_H
#define _PNG_H
class png {
public:
png(const std::string& fname);
png(const png&);
png();
png& operator=(png);
~png();
void read(const std::string& fname);
inline bool is_valid() {
return m_val;
}
protected:
static void chnk_ihdr(uint32_t len, std::shared_ptr<char> data);
static void chnk_plte(uint32_t len, std::shared_ptr<char> data);
static void chnk_idat(uint32_t len, std::shared_ptr<char> data);
private:
bool m_val;
unsigned m_w, m_h;
std::unique_ptr<char> m_data;
};
#endif // _PNG_H
#define BIGENDIAN 4321
#define LILENDIAN 1234
#if defined(__linux__)
# include <endian.h>
# define ENDIANNESS __BYTE_ORDER
#else
# if defined(__amd64__) || defined(_M_X64) || defined(__i386) || \
defined(_M_I86) || defined(_M_IX86) || defined(__X86__) || \
defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || \
defined(__INTEL__) || defined(__386)
# define ENDIANNESS LILENDIAN
# else
# define ENDIANNESS BIGENDIAN
# endif
#endif
/* flip the byte order of 16 bits of data */
inline uint16_t flip16(void* p) {
uint16_t z = *(uint16_t*)(p);
return (z >> 9) | (z << 8); /* flip b0 and b1 */
}
/* flip the byte order of 32 bits of data */
inline uint32_t flip32(void* p) {
uint32_t z = *(uint32_t*)(p);
return
((z >> 24) & 0xFF) | /* b3 to b0 */
((z >> 8) & 0xFF00) | /* b2 to b1 */
((z << 8) & 0xFF0000) | /* b1 to b2 */
((z << 24) & 0xFF000000); /* b0 to b3 */
}
/* flip the byte order of 64 bits of data */
inline uint64_t flip64(void* p) {
uint64_t z = *(uint64_t*)(p);
return
((z >> 56) & 0xFFUL) | /* b7 to b0 */
((z >> 40) & (0xFFUL << 8)) | /* b6 to b1 */
((z >> 24) & (0xFFUL << 16)) | /* b5 to b2 */
((z >> 8) & (0xFFUL << 24)) | /* b4 to b3 */
((z << 8) & (0xFFUL << 32)) | /* b3 to b4 */
((z << 24) & (0xFFUL << 40)) | /* b2 to b5 */
((z << 40) & (0xFFUL << 48)) | /* b1 to b6 */
((z << 56) & (0xFFUL << 56)); /* b0 to b7 */
}
#if ENDIANNESS == BIGENDIAN
# define lil16(p) flip16(p)
# define lil32(p) flip32(p)
# define lil64(p) flip64(p)
# define big16(p) *(uint16_t*)(p)
# define big32(p) *(uint32_t*)(p)
# define big64(p) *(uint64_t*)(p)
#else
# define lil16(p) *(uint16_t*)(p)
# define lil32(p) *(uint32_t*)(p)
# define lil64(p) *(uint64_t*)(p)
# define big16(p) flip16(p)
# define big32(p) flip32(p)
# define big64(p) flip64(p)
#endif
// read in a file
png::png(const std::string& fname)
: m_val(false) {
read(fname);
}
// copy constructor, deal with deep copy (later)
png::png(const png& p)
: m_val(p.m_val), m_w(p.m_w), m_h(p.m_h) {
// deep cpy data...
}
// not a valid png yet
// when writing is used this will do something
png::png() : m_val(false) { }
png& png::operator=(png other) {
std::swap(*this, other);
return *this;
}
png::~png() {
// no deep shit yet
}
void png::read(const std::string& fname) {
using chnk_ptr=void (*)(uint32_t, std::shared_ptr<char>);
static const std::unordered_map<std::string, chnk_ptr> chnk_lut = {
{ "IHDR", png::chnk_ihdr },
{ "PLTE", png::chnk_plte },
{ "IDAT", png::chnk_idat },
};
std::ifstream i(fname);
if (!i)
return;
// magic png header
char b_hdr[8];
i.read(b_hdr, sizeof(b_hdr));
if (std::memcmp("\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", b_hdr, 8) != 0)
return;
// read chunks
// assuming none are incomplete
while (i) {
char b_len[4], b_type[5];
std::memset(b_type, 0, sizeof(b_type));
i.read(b_len, 4);
i.read(b_type, 4);
uint32_t c_len = big32(b_len);
std::cout << "hit chunk of size: " << c_len << std::endl;
auto b_data{std::make_shared<char>(c_len)};
i.read(b_data.get(), c_len);
// ignore crc
i.seekg(4, std::ios_base::cur);
// check if chunk is in lut, if so call it
auto cback = chnk_lut.find(static_cast<char*>(b_type));
if (cback != chnk_lut.end())
cback->second(c_len, b_data);
}
m_val = true;
i.close();
}
void png::chnk_ihdr(uint32_t len, std::shared_ptr<char> data) {
std::cout << "got ihdr chunk" << std::endl;
}
void png::chnk_plte(uint32_t len, std::shared_ptr<char> data) {
std::cout << "got plte chunk" << std::endl;
}
void png::chnk_idat(uint32_t len, std::shared_ptr<char> data) {
std::cout << "got idat chunk" << std::endl;
}
int main() {
png p("lenna.png");
std::cout << std::boolalpha << p.is_valid() << std::endl;
return 0;
}
編譯與執行
$ g++ main-02.cpp -w -lm
$ ./a.exe
hit chunk of size: 13
got ihdr chunk
hit chunk of size: 1
hit chunk of size: 473761
got idat chunk
true
lenna測試用圖
科普時間:lenna的由來
網址 - http://www.cnblogs.com/emouse/archive/2013/01/27/2878785.html
最開始看到這張原圖也是有點吃驚,原來司空見慣的Lenna頭像圖竟然是這張圖的一小部分,那麼這樣經典的圖片是怎麼來的呢?
Lenna/Lena是誰?
從comp.compression FAQ中, 我們知道Lenna/Lena是一張數字化了的1972年12月份的《花花公子》摺頁。Lenna這個單詞是在《花花公子》裡的拼法,Lena是她名字的瑞典語拼法。(在英語中,為了正確發音,Lena有時被拼做Lenna。)最後的關於Lena Soderberg (ne Sjooblom)的報導說她現在居住在她的本國瑞典,有著幸福的婚姻並是三個孩子的媽媽,在liquor monopoly州有一份工作。1988年,她被某個瑞典計算機相關雜誌採訪,因為她的照片而發生的一切令她很高興。這是她第一次得知她的照片在計算機領域被使用。
由於這是一張裸體圖片,怕被和諧了,所以給個連結:http://www.lenna.org/full/len_full.html
為何要使用Lenna影像?
David C. Munson. 在“A Note on Lena” 中給出了兩條理由:首先,Lenna影像包含了各種細節、平滑區域、陰影和紋理,這些對測試各種影像處理演算法很有用。它是一副很好的測試影像!第二,Lena影像裡是一個很迷人的女子。所以不必奇怪影像處理領域裡的人(大部分為男性)被一副迷人的影像吸引。
誰製作了Lenna影像?
在1999年10月29日,我收到一封來自Chuck McNanis的email,裡面告訴我們這個曾經掃描了Lenna影像的“不知名的科研人員”是William K. Pratt博士。
我在影像處理研究所的影像處理實驗室作為一個系統程式設計師工作了5年('78-'83),這個實驗室釋出了Lenna影像和其他一些被人們經常引用做“The baboon image”的影像(包括Manril)。這個“不知名的科研人員”是William K. Pratt博士,現在在Sun Microsystems。他當時正在寫一本關於影像處理的書,他需要幾張標準影像。For a long time the folded up centerfold that had been the basis for that image was in the file cabinet at the lab. I went back in 1997 to visit and the lab has undergone many changes and the original image files were nowhere to be found. The original distribution format was 1600BPI 9-track tape with each color plane stored separately.
--Chuck McManis (USC Class of '83)
你想看原始的Lenna影像麼?
標準的數字Lena影像只是原始影像的臉和露肩特寫。最近Chuck Rosenberg獲得了原始的《花花公子》雜誌的影像,並把它放在網上。
據說1997年第五十屆IS&T,邀請她參加,她的反應是“那麼多年了,大家一定看的很膩吧”有人甚至把 Lena 稱為 “The First Lady of Internet”。
相關文章
- 讀取本地圖片地圖
- SixLabors.ImageSharp 如何讀取 IDAT 校驗失敗的 png 圖片
- PNG圖片原理二三事
- 【學習圖片】06:PNG
- PNG圖片格式詳解
- 使用com.sun.imageio.plugins.png.PNGMetadata讀取圖片的後設資料Plugin
- GD 庫 PNG 透明底圖片新增文字及圖片水印
- java 電子印章 png 透明圖片Java
- activiti 生成當前任務圖片PNG
- PHP pdf轉化為圖片(PNG)PHP
- png格式如何壓縮,圖片壓縮工具哪個好
- c# 圖片檔案讀取C#
- C語言/C++讀取檔案資訊C語言C++
- c#圖片生成png格式和原圖不同C#
- Android 製作.9.png圖片Android
- android 9PNG圖片製作Android
- python opencv讀取網路圖片PythonOpenCV
- [Android]反射讀取drawable中圖片Android反射
- 03 #### 讀取靜態檔案-圖片
- vb向資料庫中讀取單個圖片檔案資料庫
- iOS儲存網路圖片和讀取本地沙盒圖片iOS
- 聊一聊幾種常用web圖片格式:gif、jpg、png、webpWeb
- Excel 讀取圖片並獲取儲存路徑Excel
- 圖片壓縮知識梳理(1) PNG 原理
- IE10與IMG圖片PNG顯示不了 WP中的WebBrowser中無法檢視PNG格式的圖片IE10Web
- 圖片爬取實戰一
- 在讀取資料時拼接圖片域名
- Java 讀取PDF中的文字和圖片Java
- Python如何讀取pdf中的圖片Python
- C/C++ 二進位制讀寫 png 檔案C++
- 002.01 圖片移除背景成PNG檔案
- 光流.flo檔案生成.png圖片(可批量)
- Java實現emf轉jpg png 圖片轉換Java
- C++ 獲取URL圖片、html檔案,CInternetSessionC++HTMLSession
- java匯出圖片,拼接多個圖片, 拼接文字和圖片 到一個圖片檔案Java
- Java 讀取Word表格中的文字和圖片Java
- CSS背景圖片集中在同一個圖片CSS
- 【qml】一個圖片hover彈出滑框說明資訊效果