c 試水解碼jpeg圖片比特流(已成功解碼)

1c07421828194f0abd0b837d28bd185c.jpeg找到一張采用霍夫曼通用DC,AC編碼表的圖片,提取出此圖片的比特流準備對它解碼,再反推怎樣編碼。

下圖是此圖片比特流前100個字節。解碼是每次讀一字節,對這8比特解碼,如8比特不能解碼,再讀入一字節。因為霍夫曼表最多是16比特位編碼,意思是說超過16位比特還沒有被解碼就是錯誤的。當然不一定都是8比特,有時候是2比特等,這就涉及到比特的移位等操作。但操作單位是1字節8比特。

75a09a2e3d96400a96bb9e896184c227.jpeg

圖1

上傳此圖片文件

下面是霍夫曼4張通用表;

cd389c8f03844d67a41b950187f2301c.jpeg

此圖片幀全局(0xffc0)

ff ,c0 ,0 ,11 ,8 ,1 ,67 ,1 ,da ,3 ,1 ,22 ,0 ,2 ,11 ,1 ,3 ,11 ,1 ,

對全局頭分析:

總長0x11=17位,8 代表采樣精度是8位,1,67? 是圖片行數=1×256+0 x67=359行,1,da 代表圖片列數:1x256+0xda=474,? ? 3 代表圖片的分量數:亮度Y,色度U,V 三個。

后9字節分為3組,每組3字節,第一組id為1(Y),第二為2(U),第三3(V),id號為第一字節,第3字節為每個分量采樣的量化表id,第二個字節高4位代表水平采樣個數,低4位垂直采樣個數。

1,22,0? ? 表示Y? 在MCU中水平垂直隔有2個

2, 11 ,1? ?U 各一次

3, 11,? 1? ? ? ? ?V 各一次?

意思就是說:此圖片采樣的是YUV 422 格式,有2個Y,1個U,1個V。

------------------------------------------------

此圖片掃描頭 SOS (0xffda)

ff ,da ,0 ,c ,3 ,1 ,0 ,2 ,11 ,3 ,11 ,0 ,3f ,0 ,

0,c:? ?掃描頭長度 0×256+0xc=12?字節

?3: 3分量 ,Y,U,V

1,0,2,11,3,11? 分位三組,每組2字節,第一個是id號

第二字節高4位是DC 號,低4位為AC 號

0 :代表Z排序是從0開始編號

3f: 0x3f=63? ?表示Z排序是63結束,最后一字節默認是0

有這些信息就可以解碼了。

因為采用的是yuv422格式,那比特流開始就是2個Y,.緊跟1個U? ,1個V,組成一個MCU。比特流以此MCU格式為單位循環直到結束。

首先是亮度DC解碼,馬上是亮度AC解碼,再是第二個亮度DC解碼,再是第二個亮度AC解碼。

現在在驗證轉換的方法是否正確:對,正確!現在解碼出亮度DC=94,馬上就是對亮度AC解碼。

其實最簡單粗暴的方法是把每一個比特位用一個char數組元素存儲,這樣就可連續讀取。

特別要注意存入char數組時,讀入的比特位是存儲在數組的最高位。換一句話說,比特流是反序排列的,比如編碼后是2字節,是先寫入高字節,再寫入低字節。8位二進制數是先讀入高位,最后讀入低位。
??下一步把另外3張表加入,完整解碼看還遇到什么問題

已加入Y_AC? 表,遇到0xff 0? 報錯

太繞了,還有各種判斷要加,如0xff 0.? ? ?0.0

雖然報錯,也解出4對:

94,(9, 1),(0 ,-17),(0,3)

現在有點麻煩,不能驗證這些數據是否正確。感覺不理想,咋DC過后是9個0。只有一個辦法驗證了,手算,把前幾位data數據全部用二進制位表示后手算驗證程序是否正確。如正確再往下進行。

b9029bc6d23948d0a408354a494b1f1e.jpeg? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

I上圖是驗證數據,程序正確解碼。證明ALI,霍夫曼解碼部分正確。

?
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>  
#include <string.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <math.h>int main(void) {
//	unsigned char dc0[28]={0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0xa,0xb};char y_dc(unsigned char len,int bit ){   //亮度DCif((len==2)&&(bit==0b00)){return 0;	}	if((len==3)&&(bit==0b010)){return 1;}if((len==3)&&(bit==0b011)){return 2;}if((len==3)&&(bit==0b100)){return 3;}if((len==3)&&(bit==0b101)){return 4;}if((len==3)&&(bit==0b110)){return 5;}if((len==4)&&(bit==0b1110)){return 6;}if((len==5)&&(bit==0b11110)){return 7;}if((len==6)&&(bit==0b111110)){return 8;}if((len==7)&&(bit==0b1111110)){return 9;}if((len==8)&&(bit==0b11111110)){return 10;}if((len==9)&&(bit==0b111111110)){return 11;}else return -1;}//----------------------------------char ali(char len,char i){            //ALI   char o;if (len == 0) {o = 0;}if ((len == 1) && (i == 0)) {o = -1;}if ((len == 1) && (i == 1)) {o = 1;}//--------------------------if ((i >= pow(2, len - 1)) && (i <= pow(2, len))) {o = i;}if ((i >= 0) && (i < pow(2, len - 1))) {o = i - pow(2, len) + 1;}return o;}	//-------Y——AC-----------------?int  y_ac(unsigned char cd,unsigned int i,unsigned char out[2]){int bb=1;unsigned int i_bit=i;unsigned char i_len=cd;unsigned char len;unsigned char o;unsigned char  ws[16]={0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d};unsigned char zh[162]={0x1, 0x2, 0x3, 0x0, 0x4, 0x11, 0x5,0x12,0x21,0x31,0x41,0x6, 0x13,0x51,0x61,0x7,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf9,0xfa};unsigned char  cx_ws,cx_b;unsigned char hfm[17][0x7d]={};int t=0;for(int a=0;a<16;a++){             if(ws[a]==0){continue;}for(int b=0;b<ws[a];b++){hfm[a+1][b]=zh[t];t++;}}
//---------------------------------------cx_ws=i_len;int o_js=0;      if(cx_ws==2){o_js=0;cx_b=i_bit-o_js;}if(cx_ws==3){o_js=0b100;cx_b=i_bit-o_js;}if(cx_ws==4){o_js=0b1010;cx_b=i_bit-o_js;}if(cx_ws==5){o_js=0b11010;cx_b=i_bit-o_js;}if(cx_ws==6){o_js=0b111010;cx_b=i_bit-o_js;}if(cx_ws==7){o_js=0b1111000;cx_b=i_bit-o_js;}if(cx_ws==8){o_js=0b11111000;cx_b=i_bit-o_js;}if(cx_ws==9){o_js=0b111110110;cx_b=i_bit-o_js;}if(cx_ws==10){o_js=0b1111110110;cx_b=i_bit-o_js;}if(cx_ws==11){o_js=0b11111110110;cx_b=i_bit-o_js;}if(cx_ws==12){o_js=0b111111110100;cx_b=i_bit-o_js;}if(cx_ws==15){o_js=0b111111111000000;cx_b=i_bit-o_js;}if(cx_ws==16){o_js=0b1111111110000010;cx_b=i_bit-o_js;}//-----------------------------------------unsigned char o_zj=hfm[cx_ws][cx_b];if(o_zj==0)  bb=-1;len=o_zj/16;o=o_zj%16;out[0]=len;out[1]=o;if((cx_ws==4)&&((i_bit-0b1010)==0)){out[0]=0;out[1]=0;bb=0;}return bb;	}?//------------------------------------------------------------------unsigned char data[100]={0xf5,0xe6,0x24,0x4e,0xff,0x41,0xfd,0x68,0xde,0xde,0xb4,0xd6,0xff,0,0x8f,0x97,0xfa,0xf,0xeb};//    0xf5           ,  0xe6       ,    0x24//  1 1 1 1 0 1 0 1 ,1 1 1 0 0 1 1 0,0 0 1 0 0 1 0 0//11110   得到7,馬上取7位 1011110=x   現在就可把7位加x,利用ALI 反退出真實的DC系數=94。    //思路:	
//--------一個字節的段位字------------------------------------typedef struct{unsigned char b1:1;unsigned char b2:1;unsigned char b3:1;unsigned char b4:1;unsigned char b5:1;unsigned char b6:1;unsigned char b7:1;unsigned char b8:1;}BIT;BIT bit;unsigned char z[10000]={};     //一個程序單位int t=0;for(int dn=0;dn<10000;dn=dn+8){memset(&bit,0,1);memcpy(&bit,&data[t],1);z[dn+0]=bit.b8;	      z[dn+1]=bit.b7;	z[dn+2]=bit.b6;		z[dn+3]=bit.b5;	z[dn+4]=bit.b4;	z[dn+5]=bit.b3;		z[dn+6]=bit.b2;z[dn+7]=bit.b1;		t++;if(t==16){break;}           //驗證數據:-8,12,10,1,-7,(2,-4),EOF}//    1               1               1     1           1                         1
//	unsigned char z[1000]={1,0,1,0,1,1,1,1,0,1,1,1,1,0,0,1,0,1,1,1,0,1,0,0,0,1,1,0,0,0,0,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0};/*  for(int a=0;a<100;a++){printf("%d  ,",z[a]);}*/int o=0;                //輸出位數int y=0;unsigned char yac_o[2]={0};unsigned char n0=0;int a=0;int jb=0;int n=0;while(1){	for( a=2;a<17;a++){          //霍夫曼轉換都是從2位開始,最多16位int ls=0;int b=0;for(b=0;b<a;b++){       //位數讀取char ls=ls+z[jb+b]*(pow(2,(a-b-1)));   //把n個char 轉換為2進制的a位二進制整數		}if(y==0){           //處理 Y_DCo=y_dc(a,ls);	if(o>=0){         //得到位數len,此位數是馬上要從data[]讀取的二進制位,此o位二進制的值假如是c,不用解碼jb=jb+a;      // ali 利用len 和 c  推算出DC值//	y=1;          break;}}else{             //處理 Y_ACo=y_ac(a,ls,yac_o);if(o>=0){         //得到位數len,此位數是馬上要從data[]讀取的二進制位,此o位二進制的值假如是c,不用解碼jb=jb+a;      // ali 利用len 和 c  推算出DC值break;}}if(a==16){puts("hfm error");exit(-1);}}//--------------------
//	
//-----讀len 二進制 c-------------if(y==1){n0=yac_o[0];o=yac_o[1];}int ls=0;for(int b=0;b<o;b++){ls=ls+z[jb+b]*(pow(2,(o-b-1)));		}printf("n0:%d  o:%d\n",n0,ali(o,ls)); jb=jb+o;y=1;n++;//	y_ac(10,0b1111111010,yac_o);//	printf("%d   %d,",yac_o[0],yac_o[1]);if(n==15){break;}if((n0==0)&&(o==0)){puts("one Y over");break;}};return 0;
}?

為了簡單,讀比特流采用char數組,一個比特存入一個char.連續讀取。

終于解碼出亮度DC,AC。下一條也是亮度數據,但它的DC頭是與首DC(94)的差。后面緊跟的是U與V,這4條組成一個MCU,可以解碼出一個16*8的yuv塊。此解碼數據和手算的相同,如遇到0xff,0,則舍棄0。意思就是跳過0讀下一字節。

到目前為止,已攻克了jpeg編碼,解碼的所有環節,完整編解碼就是把這些環節串聯起來。

bef5af04690b4662900ca3893a31942c.jpeg

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/283913.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/283913.shtml
英文地址,請注明出處:http://en.pswp.cn/news/283913.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Raft算法詳解

Raft算法屬于Multi-Paxos算法&#xff0c;它是在Multi-Paxos思想的基礎上&#xff0c;做了一些簡化和限制&#xff0c;比如增加了日志必須是連續的&#xff0c;只支持領導者、跟隨者和候選人三種狀態&#xff0c;在理解和算法實現上都相對容易許多 從本質上說&#xff0c;Raft算…

淘寶彈性布局方案lib-flexible研究

1. lib-flexible不能與響應式布局兼容 先說說響應式布局的一些基本認識&#xff1a; 響應式布局的表現是&#xff1a;網頁通過css媒介查詢判斷可視區域的寬度&#xff0c;在不同的范圍應用不同的樣式&#xff0c;以便在不同尺寸的設備上呈現最佳的界面效果。典型的例子是&#…

[No0000DB]C# FtpClientHelper Ftp客戶端上傳下載重命名 類封裝

using System; using System.Diagnostics; using System.IO; using System.Text; using Shared;namespace Helpers {public static class FileHelper{#region Methods/// <summary>/// 向文本文件的尾部追加內容/// </summary>/// <param name"filePa…

WPF效果第一百九十四篇之伸縮面板

前面一篇玩耍了一下登錄實現效果;今天在原來的基礎上來玩耍一下伸縮面板的效果;閑話不多扯直接看效果:1、關于前臺簡單布局:2、左側面板伸縮動畫&#xff1a;<Storyboard x:Key"ShowConfigSb"><ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty…

你不知道的JavaScript(二)

第三章 原生函數 JS有很多原生函數&#xff0c;為基本的數據類型值提供了封裝對象&#xff0c;String&#xff0c;Number&#xff0c;Boolean等。我們可以通過{}.call.toString()來查看所有typeof返回object的對象的內置屬性[[class]],這個屬性無法直接訪問。我們基本類型調用的…

[轉]guava快速入門

Guava工程包含了若干被Google的 Java項目廣泛依賴 的核心庫&#xff0c;例如&#xff1a;集合 [collections] 、緩存 [caching] 、原生類型支持 [primitives support] 、并發庫 [concurrency libraries] 、通用注解 [common annotations] 、字符串處理 [string processing] 、I…

數據庫編程1 Oracle 過濾 函數 分組 外連接 自連接

【本文謝絕轉載原文來自http://990487026.blog.51cto.com】<大綱>數據庫編程1 Oracle 過濾 函數 分組 外連接 自連接本文實驗基于的數據表:winsows安裝好Oracle11g之后,開始實驗SQLplus 登陸 ORaclesqlplus 退出的方式查看用戶之下有什么表查看表的所有記錄&#xff0c;不…

【.NET 6】開發minimal api以及依賴注入的實現和代碼演示

前言&#xff1a;.net 6 LTS版本發布已經有一段時間了。此處做一個關于使用.net 6 開發精簡版webapi&#xff08;minimal api&#xff09;的入門教程演示。1、新建一個項目。此處就命名為 SomeExample:2、選擇 .net6版本&#xff0c;并且此處先去掉HTTPS配置以及去掉使用控制器…

(轉載)VS2010/MFC編程入門之四(MFC應用程序框架分析)

上一講雞啄米講的是VS2010應用程序工程中文件的組成結構&#xff0c;可能大家對工程的運行原理還是很模糊&#xff0c;理不出頭緒&#xff0c;畢竟跟C編程入門系列中的例程差別太大。這一節雞啄米就為大家分析下MFC應用程序框架的運行流程。 一.SDK應用程序與MFC應用程序運行過…

個人博客開發-開篇

邁出第一步&#xff1a; 很久以前就有這個想法&#xff0c;自己動手開發一套個人博客系統&#xff0c;終于&#xff0c;現在開始邁出了第一步。做這件事一點是做一個有個人風格的博客系統&#xff0c;第二點是對做這件事所使用的技術棧進行學習&#xff0c;所謂最好的學習就是實…

2022年中國中小學教育信息化行業研究報告

教育信息化丨研究報告 核心摘要&#xff1a; 背景篇 目前&#xff0c;我國中小學教育主要呈現信息時代教育的特征&#xff0c;智能時代教育特征初露端倪&#xff1b;中小學教育信息化正從量變邁向質變&#xff0c;創新引領與生態變革成為行業縱深的主旋律&#xff1b; 2021年…

使用curl指令發起websocket請求

昨日的文章沒指出websocket請求協商切換的精髓&#xff0c;刪除重發。前文相關&#xff1a;? .NET WebSockets 核心原理初體驗[1]? SignalR 從開發到生產部署避坑指南[2]tag&#xff1a;瀏覽器--->nginx--> server其中提到nginx默認不會為客戶端轉發Upgrade、Connectio…

Yii 2 的安裝 之 踩坑歷程

由于剛接觸yii2 ,決定先裝個試試&#xff1b;可是這一路安裝差點整吐血&#xff0c;可能還是水平有限吧&#xff0c; 但還是想把這個過程分享出來&#xff0c;讓遇到同樣問題的同學有個小小的參考&#xff0c;好了言歸正傳&#xff01;&#xff01; <(~.~)> 下面是安裝流…

設計模式之代理模式(上) 靜態代理與JDK動態代理

2019獨角獸企業重金招聘Python工程師標準>>> 代理模式 給某一個對象提供一個代理&#xff0c;并由代理對象控制對原對象的引用。靜態代理 靜態代理是由我們編寫好的類&#xff0c;在程序運行之前就已經編譯好的的類&#xff0c;此時就叫靜態代理。 說理論還是比較懵…

mysql 分頁查詢

使用limit函數 limit關鍵字的用法&#xff1a; LIMIT [offset,] rows offset指定要返回的第一行的偏移量&#xff0c;rows第二個指定返回行的最大數目。初始行的偏移量是0(不是1)。轉載于:https://www.cnblogs.com/xping/p/6703986.html

WPF 實現更換主題色

WPF 實現更換主題色WPF 使用 WPFDevelopers.Minimal 如何更換主題色作者&#xff1a;WPFDevelopersOrg原文鏈接&#xff1a; https://github.com/WPFDevelopersOrg/WPFDevelopers.Minimal框架使用大于等于.NET40&#xff1b;Visual Studio 2022;項目使用 MIT 開源許可協議&a…

vue3與vue2的區別

先來說說當下市場開發使用的問題&#xff0c;目前2021年使用vue3開發的企業還是少&#xff0c;基本上都還是以vue2的形式進行開發&#xff0c;vue3的開發模式跟react很像&#xff0c;這時候有人就會想那我學vue3有用么&#xff0c;淦&#xff0c;他喵的&#xff0c;先別激動&am…

Spring Data REST API集成Springfox、Swagger

原文: Documenting a Spring Data REST API with Springfox and Swagger 使用Spring Date REST&#xff0c;你可以迅速為Spring Date repositories的創建REST API&#xff0c;并提供CRUD和更多功能。然而&#xff0c;在嚴謹的API開發過成功&#xff0c;您還希望擁有自動生成的最…

【系統設計】S3 對象存儲

在本文中&#xff0c;我們設計了一個類似于 Amazon Simple Storage Service (S3) 的對象存儲服務。S3 是 Amazon Web Services (AWS) 提供的一項服務&#xff0c; 它通過基于 RESTful API 的接口提供對象存儲。根據亞馬遜的報告&#xff0c;到 2021 年&#xff0c;有超過 100 萬…