Le Format JPEG - Nicolas Richeton Consulting

Transcription

Le Format JPEG - Nicolas Richeton Consulting
TIPE : Le Format JPEG
Thème général : Transformations et fonctions
RICHETON
Nicolas
TIPE
Le Format JPEG
Page 1/68
TIPE : Le Format JPEG
Le Format JPEG
1 - Introduction.................................................................................................................................... 3
2 - Présentation du JPEG..................................................................................................................... 3
3 - Les étapes de l'algorithme.............................................................................................................. 4
4 – Définition de l'image à compresser................................................................................................4
5 – Pré-traitement................................................................................................................................ 5
6 – La Transformée de Cosinus Discrète (DCT)................................................................................. 6
7 - Quantification.................................................................................................................................7
8 – Format du fichier JPEG................................................................................................................. 9
9 – Une compression sans pertes : Huffman..................................................................................... 10
10 – La décompression de l'image.....................................................................................................12
11 – Le JPEG Progressif....................................................................................................................12
12 - Le JPEG sans pertes................................................................................................................... 13
13 - Programmes d’application..........................................................................................................14
14 - Conclusion..................................................................................................................................14
15 - Annexe 1 : Programmes............................................................................................................. 15
16 - Annexe 2 : Librairies..................................................................................................................21
17 - Annexe 3 : Bibliographie........................................................................................................... 68
Page 2/68
TIPE : Le Format JPEG
1 - Introduction
La résolution des images utilisées en informatique augmente régulièrement, en même temps que la
puissance des ordinateurs. Il en est de même pour l’espace nécessaire afin de les stocker. Cependant, il est
difficilement acceptable de stocker ces images sous une forme brute. Une image d’une résolution de
800x600 en 16.7 millions de couleurs , occupe déjà 1.44 Mo, ce qui représente la totalité de l'espace offert
par une disquette 31/2 ainsi que plus de quatre minutes de téléchargement sur un modem 56K. On a donc
recourt à la compression de données. Cependant si les algorithmes de compression « classiques », c'est à dire
« sans pertes » sont efficaces sur des images comportant un faire nombre de couleurs, ainsi que sur de
simples dessins, ils montrent leurs limites sur des images « naturelles », telles que des photos ou des
peintures. Le nombre important de couleurs et l'absence de zones ne comportant qu'une seule teinte de
couleurs rend difficile la reconnaissance de similarité ou de redondances dans l'image. Tels sont les constats
qui ont dirigé l'élaboration de la norme JPEG.
2 - Présentation du JPEG
À la fin des années 80, le « Joint Photographic Expert Group » s'est composé, afin de définir un
format standard de compression d'images fixes répondant à de nombreuses contraintes, donc les plus
importantes sont :
• Travail sur des images « naturelles », 256 niveaux de gris ou 16.7 Millions de couleurs
• Format avec pertes, mais dont la dégradation des images serait invisible, ou difficilement
visible.
• Une compression de l'image de gauche à droite et de haut en bas
• Un temps de compression acceptable et une complexité suffisamment faible pour pouvoir
développer des circuits intégrés réalisant cette compression.
L'aboutissement de ce travail est la norme SPIFF, qui est une explication détaillée des
manipulations à effectuer sur l'image pour réaliser sa compression. Malheureusement, elle ne définissait pas
de format de fichier standard, ce qui empêchait les échanges entre les applications. La norme SPIFF fût donc
complétée, et devint la norme JFIF, désignée communément par « norme JPEG ».
La compression utilisée dans la norme JPEG est basée sur l'utilisation de la Transformée de Cosinus
Discrète, ou DCT, qui est une simplification de la Transformée de Fourrier, et qui permet une
décomposition de l'image en fréquence. Les fréquences les moins significatives sont alors détruites pour
favoriser la compression.
Le format JPEG est donc bien un format « avec pertes », c'est-à-dire que l'image reconstituée ne
sera pas exactement l'image de départ, mais une très bonne approximation.
Page 3/68
TIPE : Le Format JPEG
3 - Les étapes de l'algorithme
Le processus de compression proprement dit peut se décomposer en trois phases :
1 - Une séparation des différentes fréquences composant l’image à compresser (DCT)
2 - L’élimination des fréquences les moins significatives (Quantification)
3 - Le stockage des fréquences restantes par une compression sans pertes
traditionnelle (l’algorithme d’Huffman)
Compression
Décompression
Les différentes étapes de l’algorithme du format JPEG
La DCT ne pouvant s’appliquer qu’à des images codées sur une seule composante, il est nécessaire
d’effectuer un pré-traitement de l’image. A cette occasion, il est possible de réaliser quelques
transformations, qui vont permettre d’améliorer le taux de compression.
4 – Définition de l'image à compresser
Considérons une image en niveaux de gris, de X x Y pixels. Elle peut être représentée par une
matrice de dimension (X,Y) où chaque coefficient, représente l'intensité de chaque pixel.
Pour une image en 256 niveau de gris, il suffit d'utiliser 8 bits pour décrire l'intégralité des pixels
8
Chaque pixel peut donc prendre, en notation non signée, une valeur entre 0 et 2 - 1 = 255 :
0
255
On va donc considérer que l'image est une matrice :
122
135
96
...
110
156
75
...
80
180
42
...
...
...
...
...
Dans le cas d'une image couleur, la couleur d'un pixel est définie par 3 composantes primaires : Rouge, Vert,
Bleu. Chaque pixel est donc représenté par une intensité pour chaque composante primaire. Chaque
intensité étant codée sur 8 bits, on a donc 24 bits par pixel.
Page 4/68
TIPE : Le Format JPEG
5 – Pré-traitement
Étant assez difficile, dans le cas d'une image couleur, d'appliquer la transformée de Fourier sur 3
composantes en même temps, on décompose l'image en 3 matrices, chacune représentant l'intensité d'une
couleur primaire.
Une image couleur est donc considérée comme 3 images en niveau de gris.
Un premier traitement est alors possible, mais pas obligatoire, et consiste à changer l'espace des
couleurs, c'est à dire passer du codage RVB au codage Luminance Chrominance (YUV). La conversion se
fait par le système linéaire ci-dessous:
Y =
0.299 R +
0.587 V +
0.114 B
U = -0.16874 R - 0.33126 V +
0.5 B
V =
0.5 R - 0.41869 V - 0.08131 B
Cela permet en premier lieu d'augmenter légèrement la compression, car les images «naturelles»
comportent souvent des zones de même luminosité, ou de même couleur pour lesquelles ce codage est plus
propice à la compression
Mais cette transformation permet surtout d’exploiter le fonctionnement de l ' oeil humain, qui est
beaucoup plus sensible à la luminosité qu’aux couleurs. Il est ainsi possible d'utiliser une compression
beaucoup plus destructrice pour la chrominance, sans que l’altération ne soit visible.
Ainsi, on peut dès maintenant diviser la taille des matrices représentant la chrominance (U et V) par
2 ou par 4. Chaque pixel est obtenu en réalisant la moyenne de 4 ou 8 pixels, et cela réduit considérablement
le volume des données à traiter.
800*600 RVB
800*600 Y
800*600 U
400*300 U
800 *600 V
400*300 V
800*600 Y
Enfin, on soustrait 128 à toutes les valeurs des matrices, pour passer d'une représentation non signée
( de 0 à 255), à une représentation signée ( de -128 à 127)
Page 5/68
TIPE : Le Format JPEG
6 – La Transformée de Cosinus Discrète (DCT)
La DCT est une fonction qui va passer un ensemble de points d'une représentation spatiale, à une
représentation fréquencielle. Elle est définie par la formule suivante :
DCT :
F u , v =
n−1 n−1
2 i1 u
2 j1 v
1
 u  v ∑ ∑ f i , j cos
cos
2n
2n
2 n
i=0 j=0
1
si x=0
avec  x =
2
1 sinon
Cette définition a une complexité assez élevée : O n 4  . C'est pourquoi, on utilise préfère
souvent utiliser la Fast DCT, au résultat identique, mais définit par une multiplication matricielle :
Fast DCT :
F = tD f D
avec
Da , b=


2
cos2 b1 a
 si a0
n
2n
1
sinon
n

La complexité de cette multiplication matricielle est alors de
O n3  .
On définit de même la DCT inverse :
iDCT :
n−1 n−1
2 i1 u
2 j1 v
1
f u , v=
 u v F i , j cos
cos
∑
∑
2n
2n
 2 n i=0 j=0
Ainsi que la Fast DCT inverse :
Fast iDCT :
f = tD F D
Malgré tout, une telle complexité interdit le réaliser directement cette transformation sur l'ensemble
de l'image à traiter. Celle-ci est donc divisée en bloc de 8x8 pixels. Dans l'hypothèse ou les dimensions de
l'image ne sont pas des multiples de 8, l'image est complétée par une valeur fixe, généralement 0 ou 255. Ces
pixels supplémentaires n'apparaîtront pas dans l'image reconstituée grâce aux dimensions de l'image
d'origine, qui sont stockées dans le fichier compressé.
Page 6/68
TIPE : Le Format JPEG
Matrice
-99
-5
-63
-57
-22
-35
13
6
source (Signée) :
-33
-68
-68
-43
-9
-14
-49
-46
-22
-49
-29
-46
-42
-38
20
-29
-49
-25
27
-40
-26
32
-35
-24
-64
-10
-13
-9
4
-5
-20
-31
-76
-25
-33
-6
4
-15
-33
-26
-67
-33
-31
-32
-12
-13
-10
-23
-65
-25
-55
-22
34
-11
-25
0
Matrice
-214
-103
-40
-20
-21
-68
-58
4
DCT :
-23
-15
66
-19
-19
11
-19
1
18
-8
-24
8
-4
-37
-13
13
-27
8
-13
-3
-20
-18
-10
8
-24
19
-30
-9
7
-23
-18
-21
-12
19
-6
-7
-17
8
-5
-17
-4
-52
41
4
9
0
-17
-2
8
-16
-11
-7
-20
6
-4
-6
Dans la matrice obtenue par la DCT, les coefficients se trouvant en haut à gauche représentent les
basses fréquences, les coefficients en bas à droite, les hautes fréquences. Ces fréquences correspondent aux
variations de la fonction en trois dimensions f(x,y) = z, avec x, y : coordonnes de l'image, et z : intensité du
point correspondant.
Les basses fréquences correspondent donc aux grandes zones de l'image, les hautes fréquences, aux
détails.
7 - Quantification
A cette étape de la compression, mis à par la réduction optionnelle, de la quantité de données codant
la chrominance de l'image, seule des opérations sans pertes on été réalisés : la DCT et la conversion RVB
vers YUV sont parfaitement réversibles, aux erreurs d'arrondis près.
C'est la quantification est l'étape déterminante, aussi bien pour la qualité de l'image reconstituée que
pour le taux de compression, car c'est ici que certaines parties de l'image vont être altérées.
On utilise pour cela une matrice de quantification de la même taille que celle des blocs sur lesquels
travaille la DCT. Chaque coefficient de la matrice obtenue par DCT, va être divisé par le coefficient
correspondant de la matrice de quantification :
Soit m(i,j) la matrice DCT et q(i,j) la matrice de quantification :
mq(i,j) = E( m(i,j) / q(i,j) )
La matrice n'est pas imposée par l'algorithme du JPEG. Elle sera stockée dans le fichier JPEG, car
elle est nécessaire à la reconstruction de l'image.
Les matrices de quantification donnant les meilleurs résultats sont évidement les matrices possédant
de faibles coefficients en haut à gauche, et de fort coefficients en bas à gauche, car elles font disparaître les
coefficients peu significatifs.
Exemple de matrice de quantification:
Q u , v=1 1i n j n  Fq avec Fq facteur de qualité
Page 7/68
TIPE : Le Format JPEG
Effets de la quantification sur la matrice image :
Matrice
29
123
65
71
106
93
141
134
source (Non signée) :
95
60
60
85
119
114
79
82
106
79
99
82
86
90
148
99
79
103
155
88
102
160
93
104
64
118
115
119
132
123
108
97
52
103
95
122
132
113
95
102
61
95
97
96
116
115
118
105
63
103
73
106
162
117
103
128
Matrice
-214
-103
-40
-20
-21
-68
-58
4
DCT :
-23
-15
66
-19
-19
11
-19
1
18
-8
-24
8
-4
-37
-13
13
-27
8
-13
-3
-20
-18
-10
8
-24
19
-30
-9
7
-23
-18
-21
-12
19
-6
-7
-17
8
-5
-17
Matrice
3
5
7
9
11
13
15
17
de quantification :
5
7
9
7
9
11
9
11
13
11
13
15
13
15
17
15
17
19
17
19
21
19
21
23
11
13
15
17
19
21
23
25
13
15
17
19
21
23
25
27
15
17
19
21
23
25
27
29
17
19
21
23
25
27
29
31
Matrice
-71
-20
-5
-2
-1
-5
-3
0
DCT quantifiée :
-4
0
0
-2
-5
-1
7
3
0
-1
0
0
-1
0
-1
0
0
0
-1
0
0
0
0
0
1
0
-1
0
0
-1
0
0
-2
0
0
0
0
0
0
0
-1
1
-1
0
0
0
0
0
0
1
0
0
0
0
0
0
Matrice
52
107
71
67
98
100
127
140
décompressée :
73
75
106
107
76
86
80
96
99
105
102
85
140
98
151
101
70
121
107
112
136
114
99
102
57
97
98
109
126
113
104
96
65
91
88
100
120
112
111
116
62
97
93
113
146
122
103
122
-4
-52
41
4
9
0
-17
-2
8
-16
-11
-7
-20
6
-4
-6
61
108
89
100
126
102
98
109
On observe que la matrice décompressée est proche de la matrice initiale, sans être identique.
La quantification provoque par ailleurs des effets de blocs qui
apparaissent sur l'image décompressée a des forts taux de compression.
A des taux adaptés, les dégradations de l'image sont invisibles.
Page 8/68
TIPE : Le Format JPEG
8 – Format du fichier JPEG
Le fichier JPEG final va d'abord recevoir les informations de base sur l'image :
•
•
•
•
Dimensions horizontales et verticales
Matrice(s) de quantification
Format des données (RVB ou YUV)
Dimension de chat couches, nécessaires pour ré-échantilloner la chrominance.
Puis, les coefficients de chaque matrice sont développés en une chaîne de coefficients, des basses
fréquences aux hautes fréquences. Ce ré-ordonnement se fait donc en zig-zag :
Les coefficients DC vont alors faire l'objet d'une sauvegarde prédictive. Seule sera stockée la
différence en le coefficient courant, et le coefficient précédent. Les coefficients DC représentant les basses
fréquences, il y a peu de variations entre les différents blocs. Les valeurs écrites seront donc petites ce qui
permet d'augmenter le taux de compression par une compression sans pertes, en augmentant leur fréquence
de répétition.
Les coefficients AC sont ensuite sauvegardés par bloc. On réalise alors l'étape la plus importante du
JPEG en ce qui concerne le taux de compression : les zéros présents à la fin des chaînes de coefficients AC
ne sont pas sauvegardés. On place alors un code de fin de bloc, signifiant que tout les coefficients restant
sont des zéros. Grâce à la quantification, c'est la majorité des coefficients qui disparaissent, le nombre de
coefficients par bloc ce voit divisé par plus de 3, en fonction des matrices de quantification.
La taille déjà nettement inférieure à celle du fichier original, mais l'utilisation d'une compression
sans pertes permet encore d'améliorer ce résultat.
Page 9/68
TIPE : Le Format JPEG
9 – Une compression sans pertes : Huffman
L'algorithme d'Huffman est le plus utilisé dans le format JPEG. La compression arithmétique fait
aussi partie de la norme JPEG, mais est plus rarement utilisée car faisant l'objet de brevets.
Il est utilisé sur l'ensemble du fichier précédemment sauvegardé.
L'algorithme d'Huffman est une compression statistique. C'est-à-dire qu'il utilise la répétition de
valeurs dans le fichier à compresser.
Dans le code ASCII, chaque valeur est codée sur 8 bits. L'espace occupé par un fichier et donc
directement proportionnel à son nombre de valeurs. L'algorithme d'Huffman va réaliser une économie, en
diminuant le nombre de bits codant les valeurs les plus utilisées. On utilise une table d'Huffman, construite
selon l'algorithme suivant :
• On commence par compter les occurrences de chaque valeur. Par exemple :
0 1 3 7 185 236 251 252 253 254 255
Octet
Occurrences 39 3 1 1
1
1
3
1
1
3
3
• Puis on construit un arbre d'Huffman. Chaque valeur va être considérée comme une arbre
de hauteur 0. Les 2 valeurs ayant la plus petite probabilité vont être regroupées sous la
forme d'un arbre dont le sommet a pour probabilité la somme des probabilités des 25
valeurs. De tels regroupements sont réalisés jusqu'à l'obtention d'un sommet unique :
• En nommant 0 la branche supérieure de chaque nœud, et 1 la branche inférieure, on observe
que chaque valeur est obtenue en partant du somment de l'arbre et en passant par une
unique suite de 0 et de 1. Cette suite est le code d'Huffman associé à cette valeur.
Octet
0
1
3
7
185
236
0000000 00000001 00000011 00000111 10111001 1110110
0
0
Codage
Binaire
0
Codage
1100
111010
111011
111100
111101
251
252
253
254
255
1111101 11111100 11111101 11111110 11111111
1
1101
111110
111111
11100
10
Huffman
Ainsi, plus la valeur apparaît souvent dans le fichier, plus son code d'Huffman est court.
Page 10/68
TIPE : Le Format JPEG
Un tel algorithme donne souvent des taux de compression très corrects, de l'ordre de 40%.
Cependant, il est nécessaire d'inclure la table des occurrences dans le fichier compressé, car sans elle, il est
impossible de reconstruire le fichier initial. C'est pourquoi, cet algorithme doit être évité pour les fichiers de
très petite taille, car dans un tel cas, le fichier compressé prend plus de place que le fichier original. Dans le
cas du JPEG, le problème ne se pose pas, car la taille des images est toujours suffisante.
La décompression de fichiers compressés par l'algorithme d'Huffman se fait en reconstruisant l'arbre
d'Huffman et la table des codes d'Huffman. Il suffit alors de suivre au fur et à mesure de la lecture du fichier,
l'arbre d'Huffman, pour reconstituer le fichier original.
Malgré les apparences, il est impossible de confondre 2 codes d'Huffman à la lecture du fichier, car
le début de l'analyse d'un code se fait juste après le dernier caractère trouvé, et celle-ci s'arrête dès qu'une
signification est trouvée.
Ce mode opératoire rend malheureusement l'algorithme d'Huffman très sensible à la corruption de
données, car un seul bit modifié fausse la lecture de tout les codes d'Huffman suivants.
Page 11/68
TIPE : Le Format JPEG
10 – La décompression de l'image
La décompression de l'image sur le processus inverse de le compression :
• Les données sont d'abord décompressées selon l'algorithme d'Huffman
• Les matrices quantifiées sont reconstituées
• La lecture de la matrice de quantification dans le fichier JPEG permet de déquantifier
l'ensemble des matrices composant l'image
• La DCT inverse permet de trouver une très bonne approximation des matrices originales
• Le ré-échantillonage de la chrominance et la conversion YUV vers RVB sont réalisés
• L'image obtenu peut alors faire l'objet de filtres, servant à réduire l'effet de bloc provoqué
par la compression JPEG
11 – Le JPEG Progressif
Un des inconvénients du mode opératoire du JPEG est que puisque les images sont compressées de
la gauche vers la droite, et du haut vers le bas, leur transmission à travers un réseau au débit limité implique
un affichage identique : Il est impossible que savoir ce qui compose la zone inférieure de l'image avant la fin
du téléchargement.
Ce problème est résolu par le JPEG progressif : Au lieu de stocker les coefficients AC dans l'ordre
dans lequel ils sont calculés, ceux si sont stockés par couches, c'est-à-dire par groupe de position dans la
matrice DCT.
Ainsi, dès qu'un groupe a été lu en entier, on obtient une matrice DCT équivalente à celle obtenue
après une quantification plus ou moins forte. Il est donc possible de calculer une première approximation de
l'image, puis de l'affiner au fur et à mesure de la lecture les autres coefficients.
Couche 1
Couche 2
Couche 3
Cette méthode, largement utilisée sur internet, a pour seul défaut de nécessiter plusieurs
décompression de la même image, et ainsi, de ralentir l'affichage de celle-ci. Cependant, la puissance
actuelle des ordinateurs rend ce ralentissement imperceptible.
Page 12/68
TIPE : Le Format JPEG
12 - Le JPEG sans pertes
Pour les applications où toute perte de données est inconcevable, il existe une variante du JPEG
basée sur un algorithme sans pertes («lossless»). Cependant les performances de cet algorithme, en ce qui
concerne le taux de compression, sont largement inférieures à celles du JPEG classique.
Afin d’éliminer les pertes lors de la compression, toutes les étapes destructrices, ou pouvant
introduire des erreurs lors d’arrondis sont éliminées (DCT, quantification, etc...). Seule la conversion RVB
-> YUV est encore tolérée, mais doit être évitée.
La DCT est alors remplacée par un algorithme de prédiction, dont le but est de prévoir la couleur
des pixels, en fonction des pixels déjà traités. Les différences entre la couleur prédite, et la couleur réelle
sont alors compressées avec un algorithme sans pertes, par exemple l’algorithme d’Huffman. Plusieures
fonctions de prédiction existent. On citera :
C  x , y=
C  x−1, yC  x , y−1
2
Cette fonction prédit la valeur d’un pixel par la moyenne des valeurs du pixel immédiatement à
gauche, et du pixel immédiatement supérieur.
Cet algorithme est assez efficace sur les images dites « naturelles », car les variations brusques de
couleur entre deux pixels sont rares. Les valeurs définissant les pixels se retrouvent alors cantonnées dans
un petit intervalle, ce qui augmente grandement le nombre d'occurrence de chaque valeur, ainsi que le taux
de compression.
Les taux de compression supérieur du JPEG avec pertes sont expliqués par le fait qu’avant de
compresser les données suivant l’algorithme d’Huffman, chaque pixel est codé par une valeur dans le JPEG
sans pertes, alors qu’un grand nombre de zéros on déjà été supprimés dans l’algorithme avec pertes.
Page 13/68
TIPE : Le Format JPEG
13 - Programmes d’application
Deux programmes d’application ont été réalisés :
Le premier (MATC) lit un bloc de 8x8 pixels (fichier au format RAW), chacun codé sur 8
bits. Il réalise ensuite sa compression suivant l’algorithme JPEG (DCT, quantification), en affichant les
résultats intermédiaires :
Ce programme a, entre autre, servi à générer les matrices servant à la présentation du TIPE.
Le second (RAW2NJG) compresse et décompresse des images suivant l’algorithme JPEG
complet. Le format des fichiers en entrée est le format RAW (brut). Le format des fichiers de sortie est un
format spécifique, car le format défini par la norme JPEG est assez complexe.
Les taux de compression obtenus sont assez bons : une image 640*480, 16.7 millions de couleurs,
de taille initiale 900 Ko est réduite à 70 Ko, soit 7.7% de sa taille originale, avec une perte de qualité
acceptable.
Ces deux programmes utilisent une base commune, qui a été écrite sous forme de librairies.
Le listing des programmes d’application se trouve dans l’annexe 1 (Programmes) et l’annexe 2
(Librairies).
14 - Conclusion
Le format JPEG s’est largement imposé comme format d’image standard, grâce à son efficacité,
mais surtout à sa gratuité, et ce, malgré son incapacité à gérer la transparence des images, car celle-ci
nécessite :
• Soit des couleurs fixes, ce qui n'est pas réalisable avec le JPEG, puisqu'il est impossible de
prévoir la couleur d'un pixel après décompression
• Soit une couche supplémentaire pour la transparence, ce qui amène à 32 bits par pixels, ce
qui n'est pas supporté par le JPEG.
L’étude de cet l’algorithme de compression, permet par ailleurs de se familiariser avec des
transformations largement utilisées en compression de l’image et de la vidéo : codage YUV, DCT,
quantification. Ces transformations se retrouvent aujourd’hui dans des normes telles que la norme MPEG2,
utilisée pour les DVDs.
Page 14/68
TIPE : Le Format JPEG
15 - Annexe 1 : Programmes
Compression d'une matrice 8x8 avec affichage des résultats intermédiaires (MATC) :
// MATC.cpp :
// (C) 2000-2001 Nicolas Richeton
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "matrix.h"
#include "menu.h"
#include "raw_io.h"
#include "file_io.h"
#include "color.h"
#include "huffman.h"
#include "example.h"
// void JPEGMatrixCompress( char *input, int q )
// Compress a single 8x8 matrix
// Input : Input RAW file, quality
// Ouput : Nothing
void JPEGMatrixCompress( char *input, int q );
int main( int argc, char* argv[] )
{
char input[1024];
int q;
Menu_DisplayHelp();
// Ask for file & quality
printf( "\nFile : ");
scanf( "%s", input );
printf( "Quality : ");
scanf( "%i", &q );
// Call function
JPEGMatrixCompress( input, q );
return( 0 );
}
// void JPEGMatrixCompress( char *input, int q )
// Compress a single 8x8 matrix
// Input : Input RAW file, quality
// Ouput : Nothing
void JPEGMatrixCompress( char *input, int q )
{
MATRIX quant;
TRIMATRIX rvbmat;
short str[64];
// Allocate matrix
Matalloc( 8, 8, &quant );
Page 15/68
TIPE : Le Format JPEG
// Generate quantize matrix
MatQuantGen( &quant, q );
// Read bloc data
File_ReadInit( &rvbmat, 8, 8 );
File_ReadRawData( input, &rvbmat, 8, 8 );
// Show each stage of compression
printf( "\nMatrice source (Non signée) :\n" );
ShowMat( &(rvbmat.a) );
MatSign( &(rvbmat.a) );
printf( "\nMatrice source (Signée) :\n" );
ShowMat( &(rvbmat.a) );
fDCT( &(rvbmat.a) );
printf( "\nMatrice DCT :\n" );
ShowMat( &(rvbmat.a) );
printf( "\nMatrice de quantification :\n" );
ShowMat( &quant );
Quantize( &(rvbmat.a), &quant );
printf( "\nMatrice DCT quantifiée :\n" );
ShowMat( &(rvbmat.a) );
Mat2Str( &(rvbmat.a), str );
printf( "\nDéveloppement en zig-zag :\n" );
ShowStr( str, 64 );
printf( "\nDéveloppement en zig-zag non signé :\n" );
ShowStrUnsigned( str, 64 );
// Free buffers
File_ReadExit( &rvbmat );
Matfree( &quant );
}
// EOF
Page 16/68
TIPE : Le Format JPEG
Compression et décompression d'images RAW suivant l'algorithme JPEG (RAW2NJG):
// RAW2NJG.cpp
// (C) 2000-2001 Nicolas Richeton
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "matrix.h"
#include "menu.h"
#include "raw_io.h"
#include "file_io.h"
#include "color.h"
#include "huffman.h"
#include "example.h"
// void JPEGCompress( char *input, char *output, int q )
// Compress a file using JPEG algorithm
// Input : Input RAW file, output NJG file, quality
// Ouput : Nothing
void JPEGCompress( char *input, char *output, int q );
// void JPEGUncompress( char *input, char *output )
// Uncompress a file using JPEG algorithm
// Input : Input NJG file, output RAW file
// Ouput : Nothing
void JPEGUncompress( char *input, char *output );
int main(int argc, char* argv[])
{
char input[1024], output[1024], ext[1024], tmp[1024], tmpfile[1024];
int q = 2;
Menu_DisplayHelp();
// Ask for file
printf( "\nFile : ");
scanf( "%s", input );
// Remove extension
strcpy( tmpfile, input );
strcat( tmpfile, ".tmp" );
File_GetPath( output, input );
strcat( output, File_GetName( tmp, input ) );
// Check the extension to know what to do
File_GetExt( ext, input );
strlwr( ext );
if( strcmp( ext, "raw" ) == 0 )
{
// Ask quality
printf( "Quality : ");
scanf( "%i", &q );
// Add output file ext
strcat( output, ".njg" );
Page 17/68
TIPE : Le Format JPEG
// Process file
JPEGCompress( input, tmpfile, q );
Huffman_Encode( tmpfile, output );
}
else if( strcmp( ext, "njg" ) == 0 )
{
// Add output file ext
strcat( output, ".raw" );
// Process file
Huffman_Decode( input, tmpfile );
JPEGUncompress( tmpfile, output );
}
return 0;
}
// void JPEGCompress( char *input, char *output, int q )
// Compress a file using JPEG algorithm
// Input : Input RAW file, output NJG file, quality
// Ouput : Nothing
void JPEGCompress( char *input, char *output, int q )
{
MATRIX quant;
MATRIX buf;
TRIMATRIX rvbmat;
long x, y, i, j;
// Alocate buffer and quantization matrix
Matalloc( 8, 8, &quant );
Matalloc( 8, 8, &buf );
// Generate Quantization matrix
MatQuantGen( &quant, q );
// Read RAW picture
File_ReadRawSize( &x, &y );
File_ReadInit( &rvbmat, File_AdaptSize( x ), File_AdaptSize( y ) );
File_ReadRawData( input, &rvbmat, x, y );
// Colorspace conversion
RVB2YUV( &rvbmat );
// Sign matrix
MatSign( &(rvbmat.a) );
MatSign( &(rvbmat.b) );
MatSign( &(rvbmat.c) );
// Apply DCT + quantize on each block
for( j = 0; j < File_AdaptSize( y ); j = j + 8 )
{
for( i = 0; i < File_AdaptSize( x ); i = i + 8 )
{
MatCopy( &(rvbmat.a), &buf, i, j, 0, 0, 8, 8 );
fDCT( &buf );
Quantize( &buf, &quant );
MatCopy( &buf , &(rvbmat.a), 0, 0, i, j, 8, 8 );
MatCopy( &(rvbmat.b), &buf, i, j, 0, 0, 8, 8 );
fDCT( &buf );
Quantize( &buf, &quant );
MatCopy( &buf , &(rvbmat.b), 0, 0, i, j, 8, 8 );
Page 18/68
TIPE : Le Format JPEG
MatCopy( &(rvbmat.c), &buf, i, j, 0, 0, 8, 8 );
fDCT( &buf );
Quantize( &buf, &quant );
MatCopy( &buf , &(rvbmat.c), 0, 0, i, j, 8, 8 );
}
}
// Save datas
FileSave( output, &rvbmat, &quant );
// Free matrix
File_ReadExit( &rvbmat );
Matfree( &buf );
Matfree( &quant );
}
// void JPEGUncompress( char *input, char *output )
// Uncompress a file using JPEG algorithm
// Input : Input NJG file, output RAW file
// Ouput : Nothing
void JPEGUncompress( char *input, char *output )
{
MATRIX quant;
MATRIX buf;
TRIMATRIX rvbmat;
long x, y, i, j;
// Alloc buffer & quantize matrix
Matalloc( 8, 8, &quant );
Matalloc( 8, 8, &buf );
// Read datas
FileRead( input, &rvbmat, &quant );
// Get x, y from the compressed datas
x = rvbmat.a.x;
y = rvbmat.a.y;
// Apply Unquatize and iDCT on each block
for( j = 0; j < File_AdaptSize( y ); j = j + 8 )
{
for( i = 0; i < File_AdaptSize( x ); i = i + 8 )
{
MatCopy( &(rvbmat.a), &buf, i, j, 0, 0, 8, 8 );
UnQuantize( &buf, &quant );
fiDCT( &buf );
MatCopy( &buf , &(rvbmat.a), 0, 0, i, j, 8, 8 );
MatCopy( &(rvbmat.b), &buf, i, j, 0, 0, 8, 8 );
UnQuantize( &buf, &quant );
fiDCT( &buf );
MatCopy( &buf , &(rvbmat.b), 0, 0, i, j, 8, 8 );
MatCopy( &(rvbmat.c), &buf, i, j, 0, 0, 8, 8 );
UnQuantize( &buf, &quant );
fiDCT( &buf );
MatCopy( &buf , &(rvbmat.c), 0, 0, i, j, 8, 8 );
}
}
// Color space convertion
Page 19/68
TIPE : Le Format JPEG
MatUnsign( &(rvbmat.a) );
MatUnsign( &(rvbmat.b) );
MatUnsign( &(rvbmat.c) );
YUV2RVB( &rvbmat );
// Write RAW picture
File_WriteRawData( output, &rvbmat, x, y );
// Free buffers
File_ReadExit( &rvbmat );
Matfree( &buf );
Matfree( &quant );
}
// EOF
Page 20/68
TIPE : Le Format JPEG
16 - Annexe 2 : Librairies
// Color.h : Definitions for Color.ccp :
// RVB <-> YUV convertion, Chroma downsampling
// (C) 2000-2001 Nicolas Richeton
// TRIMATRIX *RVB2YUV( TRIMATRIX *mat )
// Convert colorspace from RVB to YUV
// Input : Matrix using RVB color sheme
// Ouput : Matrix using YUV colorspace
extern TRIMATRIX *RVB2YUV( TRIMATRIX *mat );
// TRIMATRIX *YUV2RVB( TRIMATRIX *mat )
// Convert colorspace from YUV to RVB
// Input : Matrix using YUV color sheme
// Ouput : Matrix using RVB colorspace
extern TRIMATRIX *YUV2RVB( TRIMATRIX *mat );
// TRIMATRIX *DownSample( TRIMATRIX *mat, int c )
// Downsample U&V layers of a YUV matrix
// Input : Matrix using YUV color sheme, downsample ratio
// Ouput : Nothing :-) (Not working)
extern TRIMATRIX *DownSample( TRIMATRIX *mat, int c );
// EOF
Page 21/68
TIPE : Le Format JPEG
// Color.cpp : RVB <-> YUV convertion, Chroma downsampling
// (C) 2000-2001 Nicolas Richeton
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "matrix.h"
#include "color.h"
// TRIMATRIX *RVB2YUV( TRIMATRIX *mat )
// Convert colorspace from RVB to YUV
// Input : Matrix using RVB color sheme
// Ouput : Matrix using YUV colorspace
TRIMATRIX *RVB2YUV( TRIMATRIX *mat )
{
long i, j;
float r,v,b;
for( j = 0; j < (mat->a).y; j++ )
{
for( i = 0; i < (mat->a).x; i++ )
{
// For each pixel
// Read values in RVB
r = (mat->a).data[i][j];
v = (mat->b).data[i][j];
b = (mat->c).data[i][j];
// Write values in YUV
(mat->a).data[i][j] = (float)( (int)( 0.29900 * r + 0.58700 * v + 0.11400 * b ) );
(mat->b).data[i][j] = (float)( (int)( -0.16874 * r - 0.33126 * v + 0.50000 * b ) + 128 );
(mat->c).data[i][j] = (float)( (int)( 0.50000 * r - 0.41869 * v - 0.08131 * b ) + 128 );
}
}
return( mat );
}
// TRIMATRIX *YUV2RVB( TRIMATRIX *mat )
// Convert colorspace from YUV to RVB
// Input : Matrix using YUV color sheme
// Ouput : Matrix using RVB colorspace
TRIMATRIX *YUV2RVB( TRIMATRIX *mat )
{
long i, j;
float y,u,v;
for( j = 0; j < (mat->a).y; j++ )
{
for( i = 0; i < (mat->a).x; i++ )
{
// For each pixel
// Read values in YUV
y = (mat->a).data[i][j];
u = (mat->b).data[i][j] - 128;
v = (mat->c).data[i][j] - 128;
// Write values in RVB
(mat->a).data[i][j] = (float)( (int)( 1.402 * v + y ) );
Page 22/68
TIPE : Le Format JPEG
(mat->b).data[i][j] = (float)( (int)( y - 0.34414 * u - 0.71414 * v ) );
(mat->c).data[i][j] = (float)( (int)( y + 1.77200 * u ) );
}
}
return( mat );
}
// TRIMATRIX *DownSample( TRIMATRIX *mat, int c )
// Downsample U&V layers of a YUV matrix
// Input : Matrix using YUV color sheme, downsample ratio
// Ouput : Nothing :-) (Not working)
TRIMATRIX *DownSample( TRIMATRIX *mat, int c )
{
MATRIX buf;
long i, j, k, l;
float tmp;
if( ( c == 3 ) | ( c > 4 ) )
printf( "\nColor.ccp : Error : Can only Downsample by 2 or 4" );
else
{
Matalloc( ( (mat->b).x / c ), ( (mat->b).y / c ), &buf );
for( j = 0; j < (mat->b).y; j = j + c )
{
for( i = 0; i < (mat->b).x; i = i + c )
{
tmp = 0;
for( k = 0; k < c; k++ )
{
for( l = 0; l < c; l++ )
{
tmp = (mat->b).data[i + l][j + k] + tmp;
}
}
buf.data[i/c][j/c] = (unsigned char)( tmp / (c*c) );
}
}
Matfree( &(mat->b) );
(mat->b).data = buf.data;
mat->b.x = buf.x;
mat->b.y = buf.y;
/*
buf->x , buf->y, &(mat->b) );*/
}
return( mat );
}
// EOF
Page 23/68
TIPE : Le Format JPEG
// Example.h : Definitions for Example.ccp :
// Statics matrix data used for debug in early stage
// (C) 2000-2001 Nicolas Richeton
// MATRIX *MatExample( MATRIX *mat )
// Fill the matrix with the example
// Input : 8x8 matrix
// Ouput : 8x8 example matrix
extern MATRIX *MatExample( MATRIX *mat );
//EOF
// Example.cpp : Static matrix data used for debug in early stage
// (C) 2000-2001 Nicolas Richeton
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "stdafx.h"
#include "matrix.h"
// Matrix data
unsigned char example[8][8] =
{ {100, 120, 120, 120, 135, 120, 135, 120},
{155, 135, 135, 155, 151, 151, 151, 151},
{131, 127, 151, 151, 135, 155, 167, 179},
{116, 88, 100, 108, 120, 151, 167, 151},
{151, 155, 179, 191, 167, 151, 151, 151},
{135, 131, 116, 112, 112, 116, 151, 131},
{131, 155, 155, 155, 179, 179, 167, 155},
{211, 179, 167, 179, 179, 179, 171, 167} };
// MATRIX *MatExample( MATRIX *mat )
// Fill the matrix with the example
// Input : 8x8 matrix
// Ouput : 8x8 example matrix
MATRIX *MatExample( MATRIX *mat )
{
char i,j;
for( i = 0; i < 8; i++ )
{
for( j = 0; j < 8; j++ )
{
// Assign value
(mat->data)[i][j] = example[i][j];
}
}
return( mat );
}
// EOF
Page 24/68
TIPE : Le Format JPEG
// File_io.h : Definitions for File_io.ccp :
// Pictures data Read/Write
// (C) 2000-2001 Nicolas Richeton
// 3 matrix sizes, used in FileSaveSize & FileReadSize
typedef struct
{
long x1;
long x2;
long x3;
long y1;
long y2;
long y3;
} DCTFILEDIM;
// int FileSave( char *filename, TRIMATRIX *data, MATRIX *quant )
// Save a RVB or YUV matrix using the quantization matrix provided
// Input : Filename, Data matrix, quantization matrix
// Ouput : Always 0 (OK)
extern int FileSave( char *filename, TRIMATRIX *data, MATRIX *quant );
// int FileSaveDC( FILE *stream, MATRIX *data )
// Save all the DC coefs of a matrix (predictive)
// Input : Stream (write mode), a matrix of any size
// Ouput : Always 0 (OK)
extern int FileSaveDC( FILE *stream, MATRIX *data );
// int FileSaveAC( FILE *stream, MATRIX *data, MATRIX *buf )
// Save all the AC coefs of a matrix
// Input : Stream (write mode), a matrix of any size, an allocated 8x8 matrix
// Ouput : Always 0 (OK)
extern int FileSaveAC( FILE *stream, MATRIX *data, MATRIX *buf );
// int FileSaveSize( FILE *stream, TRIMATRIX *mat )
// Save size data of a TRIMATRIX
// Input : Stream (write mode), a RVB or YUV matrix
// Ouput : Always 0 (OK)
extern int FileSaveSize( FILE *stream, TRIMATRIX *mat );
// int FileSaveQMat( FILE *stream, MATRIX *mat )
// Save the quantization matrix
// Input : Stream (write mode), the quantization matrix (8x8)
// Ouput : Always 0 (OK)
extern int FileSaveQMat( FILE *stream, MATRIX *mat );
// int FileRead( char *filename, TRIMATRIX *data, MATRIX *quant )
// Read a RVB or YUV matrix and read the quantization matrix
// Input : Filename, Data matrix, quantization matrix
// Ouput : Always 0 (OK)
Page 25/68
TIPE : Le Format JPEG
extern int FileRead( char *filename, TRIMATRIX *data, MATRIX *quant );
// int FileReadDC( FILE *stream, MATRIX *data )
// Read all the DC coefs of a matrix (predictive)
// Input : Stream (read mode), an allocated matrix
// Ouput : Always 0 (OK)
extern int FileReadDC( FILE *stream, MATRIX *data );
// int FileReadAC( FILE *stream, MATRIX *data, MATRIX *buf )
// Read all the AC coefs of a matrix
// Input : Stream (read mode), an allocated matrix, an allocated 8x8 matrix
// Ouput : Always 0 (OK)
extern int FileReadAC( FILE *stream, MATRIX *data, MATRIX *buf );
// int FileReadSize( FILE *stream, TRIMATRIX *mat )
// Read size data of a TRIMATRIX
// Input : Stream (read mode), an allocated RVB or YUV matrix
// Ouput : Always 0 (OK)
extern int FileReadSize( FILE *stream, TRIMATRIX *mat );
// int FileReadQMat( FILE *stream, MATRIX *mat )
// Read the quantization matrix
// Input : Stream (read mode), an allocated 8x8 matrix
// Ouput : Always 0 (OK)
extern int FileReadQMat( FILE *stream, MATRIX *mat );
// TRIMATRIX *File_ReadInit( TRIMATRIX *mat, long x, long y )
// Round matrix size, allocate and fill with 0
// Input : An empty TRIMATRIX, x and y sizes of the matrix
// Ouput : The allocated TRIMATRIX
extern TRIMATRIX *File_ReadInit( TRIMATRIX *mat, long x, long y );
// void File_ReadExit( TRIMATRIX *mat )
// Free TRIMATRIX
// Input : An allocated TRIMATRIX
// Ouput : Nothing
extern void File_ReadExit( TRIMATRIX *mat );
// long File_AdaptSize( long x )
// Round size to 32 to allow downsampling and division per 8
// Input : Size value (x or y)
// Ouput : Rounded value
extern long File_AdaptSize( long x );
// char *File_GetExt( char *dest, char *src )
// Gives file extension
// Input : a buffer, and the full filename
// Ouput : pointer on dest with contains the ext
Page 26/68
TIPE : Le Format JPEG
extern char *File_GetExt( char *dest, char *src );
// char *File_GetName( char *dest, char *src )
// Gives file name (without ext)
// Input : a buffer, and the full filename
// Ouput : pointer on dest with contains the filename
extern char *File_GetName( char *dest, char *src );
// char *File_GetPath( char *dest, char *src )
// Gives file path
// Input : a buffer, and the full filename
// Ouput : pointer on dest with contains the path
extern char *File_GetPath( char *dest, char *src );
// EOF
Page 27/68
TIPE : Le Format JPEG
// File_io.cpp : Pictures data Read/Write
// (C) 2000-2001 Nicolas Richeton
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "matrix.h"
#include "file_io.h"
#include <string.h>
// int FileSaveDC( FILE *stream, MATRIX *data )
// Save all the DC coefs of a matrix (predictive)
// Input : Stream (write mode), a matrix of any size
// Ouput : Always 0 (OK)
int FileSaveDC( FILE *stream, MATRIX *data )
{
long i, j;
short buf, last = 0;
for( j = 0; j < data->y; j = j + 8 )
{
for( i = 0; i < data->x; i = i + 8 )
{
// Calc & Write buffer
buf = (short)( data->data[i][j] - last );
fwrite( &buf, sizeof(short), 1, stream );
// Remind last value
last = (short)( data->data[i][j] );
}
}
return( 0 );
}
// int FileSaveAC( FILE *stream, MATRIX *data, MATRIX *buf )
// Save all the AC coefs of a matrix
// Input : Stream (write mode), a matrix of any size, an allocated 8x8 matrix
// Ouput : Always 0 (OK)
int FileSaveAC( FILE *stream, MATRIX *data, MATRIX *buf )
{
long i, j;
short str[64];
unsigned char len;
for( j = 0; j < data->y; j = j + 8 )
{
for( i = 0; i < data->x; i = i + 8 )
{
len = 63;
// Extract 8x8 bloc and convert to 1 dim array
MatCopy( data, buf, i, j, 0, 0, 8, 8 );
Mat2Str( buf, str );
// Suppress trailling zeros
while( ( len > 0 ) && ( str[len] == 0 ) )
len--;
Page 28/68
TIPE : Le Format JPEG
//If shortened, insert End Flag
if( len < 63 )
{
len++;
str[len] = -32767;
}
fwrite( &str[1], sizeof(short), len, stream );
}
}
return( 0 );
}
// int FileSaveSize( FILE *stream, TRIMATRIX *mat )
// Save size data of a TRIMATRIX
// Input : Stream (write mode), a RVB or YUV matrix
// Ouput : Always 0 (OK)
int FileSaveSize( FILE *stream, TRIMATRIX *mat )
{
DCTFILEDIM psize;
// Fill struct
psize.x1 = mat->a.x;
psize.x2 = mat->b.x;
psize.x3 = mat->c.x;
psize.y1 = mat->a.y;
psize.y2 = mat->b.y;
psize.y3 = mat->c.y;
// Save struct
fwrite( &psize, 1, sizeof( DCTFILEDIM ), stream );
return( 0 );
}
// int FileSaveQMat( FILE *stream, MATRIX *mat )
// Save the quantization matrix
// Input : Stream (write mode), the quantization matrix (8x8)
// Ouput : Always 0 (OK)
int FileSaveQMat( FILE *stream, MATRIX *mat )
{
unsigned char str[64], i, j, cnt = 0;
// Convert the matrix to an array
for( j = 0; j < 8; j++ )
{
for( i = 0; i < 8; i++ )
{
str[cnt] = (unsigned char)mat->data[i][j];
cnt++;
}
}
fwrite( str, sizeof( unsigned char), 64, stream );
return( 0 );
}
// int FileSave( char *filename, TRIMATRIX *data, MATRIX *quant )
Page 29/68
TIPE : Le Format JPEG
// Save a RVB or YUV matrix using the quantization matrix provided
// Input : Filename, Data matrix, quantization matrix
// Ouput : Always 0 (OK)
int FileSave( char *filename, TRIMATRIX *data, MATRIX *quant )
{
FILE *stream;
MATRIX buf;
// Alloc buffer & open file
Matalloc( 8, 8, &buf );
stream = fopen( filename, "wb" );
// Save size & quantization matrix
FileSaveSize( stream, data );
FileSaveQMat( stream, quant );
// Save data
FileSaveDC( stream, &(data->a) );
FileSaveDC( stream, &(data->b) );
FileSaveDC( stream, &(data->c) );
FileSaveAC( stream, &(data->a), &buf );
FileSaveAC( stream, &(data->b), &buf );
FileSaveAC( stream, &(data->c), &buf );
// Release buffer & close file
Matfree( &buf );
fclose( stream );
return( 0 );
}
// int FileReadDC( FILE *stream, MATRIX *data )
// Read all the DC coefs of a matrix (predictive)
// Input : Stream (read mode), an allocated matrix
// Ouput : Always 0 (OK)
int FileReadDC( FILE *stream, MATRIX *data )
{
long i, j;
short buf, last = 0;
for( j = 0; j < data->y; j = j + 8 )
{
for( i = 0; i < data->x; i = i + 8 )
{
// Read & recalc
fread( &buf, sizeof(short), 1, stream );
data->data[i][j] = (float)( buf + last );
//Remind last value
last = buf + last;
}
}
return( 0 );
}
// int FileReadAC( FILE *stream, MATRIX *data, MATRIX *buf )
// Read all the AC coefs of a matrix
// Input : Stream (read mode), an allocated matrix, an allocated 8x8 matrix
// Ouput : Always 0 (OK)
Page 30/68
TIPE : Le Format JPEG
int FileReadAC( FILE *stream, MATRIX *data, MATRIX *buf )
{
long i, j;
short str[64];
unsigned char k, flag;
float tmp;
for( j = 0; j < data->y; j = j + 8 )
{
for( i = 0; i < data->x; i = i + 8 )
{
flag = 0;
// Save the DC coef
tmp = data->data[i][j];
for( k = 1; k < 64; k++ )
{
// If there are still datas to read
if( flag == 0 )
{
fread( &str[k], sizeof(short), 1, stream );
// Check of End of Block flag
if( str[k] == -32767 )
{
flag = 1;
str[k] = 0;
}
}
else // Fill with 0
str[k] = 0;
}
// Copy buffer into the matrix
Str2Mat( str, buf );
MatCopy( buf, data, 0, 0, i, j, 8, 8 );
// Restore the DC coef (erased by Str2Mat)
data->data[i][j] = tmp;
}
}
return( 0 );
}
// int FileReadSize( FILE *stream, TRIMATRIX *mat )
// Read size data of a TRIMATRIX
// Input : Stream (read mode), an allocated RVB or YUV matrix
// Ouput : Always 0 (OK)
int FileReadSize( FILE *stream, TRIMATRIX *mat )
{
DCTFILEDIM psize;
// Fill DCTFILEDIM struct with datas
fread( &psize, 1, sizeof( DCTFILEDIM ), stream );
//Distribute datas & allocate matrix
Matalloc( psize.x1, psize.y1, &mat->a );
MatZero( &mat->a );
Page 31/68
TIPE : Le Format JPEG
Matalloc( psize.x2, psize.y2, &mat->b );
MatZero( &mat->b );
Matalloc( psize.x3, psize.y3, &mat->c );
MatZero( &mat->c );
return( 0 );
}
// int FileReadQMat( FILE *stream, MATRIX *mat )
// Read the quantization matrix
// Input : Stream (read mode), an allocated 8x8 matrix
// Ouput : Always 0 (OK)
int FileReadQMat( FILE *stream, MATRIX *mat )
{
unsigned char str[64], i, j, cnt = 0;
// Read the matrix datas
fread( str, sizeof( unsigned char), 64, stream );
// Fill the matrix
for( j = 0; j < 8; j++ )
{
for( i = 0; i < 8; i++ )
{
mat->data[i][j] = (float)str[cnt];
cnt++;
}
}
return( 0 );
}
// int FileRead( char *filename, TRIMATRIX *data, MATRIX *quant )
// Read a RVB or YUV matrix and read the quantization matrix
// Input : Filename, Data matrix, quantization matrix
// Ouput : Always 0 (OK)
int FileRead( char *filename, TRIMATRIX *data, MATRIX *quant )
{
FILE *stream;
MATRIX buf;
// Alloc buffer & open file
Matalloc( 8, 8, &buf );
stream = fopen( filename, "rb" );
// Read matrix size and quantization matrix
FileReadSize( stream, data );
FileReadQMat( stream, quant );
// Read datas
FileReadDC( stream, &(data->a) );
FileReadDC( stream, &(data->b) );
FileReadDC( stream, &(data->c) );
FileReadAC( stream, &(data->a), &buf );
FileReadAC( stream, &(data->b), &buf );
FileReadAC( stream, &(data->c), &buf );
Page 32/68
TIPE : Le Format JPEG
// Release buffer & close file
fclose( stream );
Matfree( &buf );
return( 0 );
}
// TRIMATRIX *File_ReadInit( TRIMATRIX *mat, long x, long y )
// Round matrix size, allocate and fill with 0
// Input : An empty TRIMATRIX, x and y sizes of the matrix
// Ouput : The allocated TRIMATRIX
TRIMATRIX *File_ReadInit( TRIMATRIX *mat, long x, long y )
{
// Round size
x = File_AdaptSize( x );
y = File_AdaptSize( y );
// Allocate and fill matrix
Matalloc( x, y, &mat->a );
MatZero( &mat->a );
Matalloc( x, y, &mat->b );
MatZero( &mat->b );
Matalloc( x, y, &mat->c );
MatZero( &mat->c );
return( mat );
}
// void File_ReadExit( TRIMATRIX *mat )
// Free TRIMATRIX
// Input : An allocated TRIMATRIX
// Ouput : Nothing
void File_ReadExit( TRIMATRIX *mat )
{
Matfree( &mat->a );
Matfree( &mat->b );
Matfree( &mat->c );
}
// long File_AdaptSize( long x )
// Round size to 32 to allow downsampling and division per 8
// Input : Size value (x or y)
// Ouput : Rounded value
long File_AdaptSize( long x )
{
if( x%8 != 0 )
{
// Set the closest higher right value
x = x + (32 - x%32 );
}
return( x );
}
// char *File_GetExt( char *dest, char *src )
Page 33/68
TIPE : Le Format JPEG
// Gives file extension
// Input : a buffer, and the full filename
// Ouput : pointer on dest with contains the ext
char *File_GetExt( char *dest, char *src )
{
long j = 0, i;
i = strlen( src ) - 1;
strcpy( dest, "" );
// Find first '.' from the right
while( (i >= 0) && (src[i] != '\\') && (src[i] != '.') )
i--;
// Copy what is at its right
if( src[i] == '.' )
{
j = i;
for( i++; i < strlen( src ); i++ )
{
dest[i-j-1] = src[i];
}
dest[i-j-1] = 0;
}
return( dest );
}
// char *File_GetName( char *dest, char *src )
// Gives file name (without ext)
// Input : a buffer, and the full filename
// Ouput : pointer on dest with contains the filename
char *File_GetName( char *dest, char *src )
{
long j = 0;
long i = strlen( src ) - 1;
// Find the first '\' from the right
strcpy( dest, "" );
while( (i >= 0) && (src[i] != '\\') )
i--;
j = i;
// Copy until the end or a '.'
for( i++; ( (i < strlen( src )) && (src[i] != '.') ); i++ )
{
dest[i-j-1] = src[i];
}
dest[i-j-1] = 0;
return( dest );
}
// char *File_GetPath( char *dest, char *src )
// Gives file path
// Input : a buffer, and the full filename
// Ouput : pointer on dest with contains the path
char *File_GetPath( char *dest, char *src )
{
long i = strlen( src ) - 1;
Page 34/68
TIPE : Le Format JPEG
int flag = 0;
// Find the first "\\" from the right
strcpy( dest, "" );
while( (i >= 0) && (src[i] != '\\') )
i--;
dest[i+1] = 0;
// Copy until the end
while( flag == 0 )
{
dest[i] = src [i];
if( i == 0 )
flag = -1;
else
i--;
}
return( dest );
}
// EOF
Page 35/68
TIPE : Le Format JPEG
// Huffman.h : Definitions for Huffman.cpp :
// Compress & UnCompress using Huffman's algorithm
// (C) 2000-2001 Nicolas Richeton
// Struct used in Huffman's Trees
typedef struct HUFF_NODE
{
long
val;
long
oc;
HUFF_NODE
*fils0;
HUFF_NODE
*fils1;
HUFF_NODE
HUFF_NODE
} HUFF_NODE;
*prev;
*next;
// Struct used for Huffman's codes and buffers
typedef struct
{
char data[256];
long size;
} HUFF_CODE;
// Size of the Huffman's Table, written at the beginning of each compressed file
#define HUFFMAN_TABLE_LENGTH 1024
// int Huffman_Encode( char *infile, char *outfile )
// Compress file using Huffman
// Input : Input & output file names
// Ouput : 0 (Ok)
extern int Huffman_Encode( char *infile, char *outfile );
// int Huffman_Decode( char *infile, char *outfile )
// Uncompress file using Huffman
// Input : Input & output file names
// Ouput : 0 (Ok)
extern int Huffman_Decode( char *infile, char *outfile );
// int Huffman_Scan( char *infile, long *tab )
// Create occurences table
// Input : Input file, allocated table
// Ouput : 0 (Ok)
extern int Huffman_Scan( char *infile, long *tab );
// HUFF_NODE *Huffman_AddNodes( HUFF_NODE *bigger, HUFF_NODE *nnew )
// Add inital node & sort nodes
// Input : Huffman tree, new node
// Ouput : Pointer on Huffman tree
extern HUFF_NODE *Huffman_AddNodes( HUFF_NODE *bigger, HUFF_NODE *nnew );
Page 36/68
TIPE : Le Format JPEG
// HUFF_NODE *Huffman_InitNodes( long *tab )
// Create inital nodes
// Input : Occurence table
// Ouput : Pointer on the 1st node
extern HUFF_NODE *Huffman_InitNodes( long *tab );
// HUFF_NODE *Huffman_Tree( HUFF_NODE *bigger )
// Built Huffman tree
// Input : 1st inital node
// Ouput : pointer on the top of the Huffman Tree
extern HUFF_NODE *Huffman_Tree( HUFF_NODE *bigger );
// int Huffman_TreeInitDisplay( HUFF_NODE *bigger )
// Display 1st step of the building of Huffman tree (inital nodes)
// Input : 1st node
// Ouput : 0 (Ok)
extern int Huffman_TreeInitDisplay( HUFF_NODE *bigger );
// int Huffman_TreeDisplay( HUFF_NODE *bigger )
// Display Huffman Tree (Debug)
// Input : Huffman tree
// Ouput : 0 (Ok)
extern int Huffman_TreeDisplay( HUFF_NODE *bigger );
// HUFF_CODE *Huffman_CodeBuilt( HUFF_NODE *bigger, HUFF_CODE *table )
// Init & Call Huffman_CodeBuiltRec()
// Input : Huffman tree, Empty huffman table
// Ouput : Pointer on Huffman table
extern HUFF_CODE *Huffman_CodeBuilt( HUFF_NODE *bigger, HUFF_CODE *table );
// HUFF_CODE *Huffman_CodeBuiltRec( HUFF_NODE *bigger, HUFF_CODE *table, HUFF_CODE *buf )
// Built Huffman table from huffman tree
// Input : Huffman tree, empty Huffman table, buffer
// Ouput : Pointer on Huffman table
extern HUFF_CODE *Huffman_CodeBuiltRec( HUFF_NODE *bigger, HUFF_CODE *table, HUFF_CODE *buf );
// char *Huffman_CodeCopy( char *dest, char *source, long s1, long s2, long len )
// Copy Huffman code from one var to another, using start point 1 & 2 and length
// Input : Destination, Source, Start point 1, Start point 2, Length
// Ouput : pointer on Destination
extern char *Huffman_CodeCopy( char *dest, char *source, long s1, long s2, long len );
// int Huffman_CodeDisplay( HUFF_CODE *table )
// Display Huffman table (Debug)
// Input : Huffman table
// Ouput : 0 (Ok)
extern int Huffman_CodeDisplay( HUFF_CODE *table );
Page 37/68
TIPE : Le Format JPEG
// int Huffman_WriteOcc( FILE *outfile, long *tab )
// Write occurence table to disk
// Input : File stream (write mode), occurence table
// Ouput : 0 (Ok)
extern int Huffman_WriteOcc( FILE *outfile, long *tab );
// int Huffman_ReadOcc( FILE *infile, long *tab )
// Read occurence table from disk
// Input : File stream (read mode)
// Ouput : 0 (Ok)
extern int Huffman_ReadOcc( FILE *infile, long *tab );
// int Huffman_WriteSaveBuffer( FILE *outfile, HUFF_CODE *buffer )
// if buffer (compressed data) is full (128 bits), write it
// Input : File stream (write mode), the buffer
// Ouput : 0 (ok)
extern int Huffman_WriteSaveBuffer( FILE *outfile, HUFF_CODE *buffer );
// int Huffman_WriteFlushBuffer( FILE *outfile, HUFF_CODE *buffer )
// Write remaining buffer (compressed data) to disk
// Input : File stream (write mode), the buffer
// Ouput : 0 (Ok)
int Huffman_WriteFlushBuffer( FILE *outfile, HUFF_CODE *buffer );
// int Huffman_ReadData2Buffer( FILE *infile, HUFF_CODE *tablehuff, HUFF_CODE *buffer )
// Read 1 char, compress it, and copy to buffer
// Input : File stream (read mode), Huffman table, the buffer
// Ouput : 0 (Ok)
extern int Huffman_ReadData2Buffer( FILE *infile, HUFF_CODE *tablehuff, HUFF_CODE *buffer );
// int Huffman_WriteCompressedData( char *infile, char *outfile, long *tableocc, HUFF_CODE *tablehuff )
// Compress data using huffman table & write it to disk
// Input : Input filename, output filename, occurence table, huffman table
// Ouput : 0 (Ok)
extern int Huffman_WriteCompressedData( char *infile, char *outfile, long *tableocc, HUFF_CODE *tablehuff );
// int Huffman_Bit( unsigned char a, int bit )
// Extract a bit from a char
// Input : a char, bit number (from right to left)
// Ouput : bit value
extern int Huffman_Bit( unsigned char a, int bit );
// int Huffman_ReadCData2Buffer( FILE *infile, HUFF_NODE *hufftree, HUFF_CODE *buffer, double long *fpos, long *fbit )
// Read & unpack one char to the buffer
// Input : File stream (read mode), huffman tree, file position (byte), 1st bit number
// Ouput : 0 (ok)
extern int Huffman_ReadCData2Buffer( FILE *infile, HUFF_NODE *hufftree, HUFF_CODE *buffer, double long *fpos, long
*fbit );
Page 38/68
TIPE : Le Format JPEG
// int Huffman_WriteSaveUBuffer( FILE *outfile, HUFF_CODE *buffer )
// if buffer (uncompressed data) is full (128 bytes), write it
// Input : File stream (write mode), buffer
// Ouput : 0 (Ok)
extern int Huffman_WriteSaveUBuffer( FILE *outfile, HUFF_CODE *buffer );
// int Huffman_WriteFlushUBuffer( FILE *outfile, HUFF_CODE *buffer )
// Write remaining buffer (uncompressed data) to disk
// Input : File stream (write mode), buffer
// Ouput : 0 (Ok)
extern int Huffman_WriteFlushUBuffer( FILE *outfile, HUFF_CODE *buffer );
// int Huffman_FreeTree( HUFF_NODE *tree )
// Free the tree under the provided node
// Input : Start node
// Ouput : 0 (Ok)
extern int Huffman_FreeTree( HUFF_NODE *tree );
// EOF
Page 39/68
TIPE : Le Format JPEG
// Huffman.cpp : Compress & UnCompress using Huffman's algorithm
// (C) 2000-2001 Nicolas Richeton
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "huffman.h"
// int Huffman_Encode( char *infile, char *outfile )
// Compress file using Huffman
// Input : Input & output file names
// Ouput : 0 (Ok)
int Huffman_Encode( char *infile, char *outfile )
{
long occ[256];
HUFF_NODE *treedata;
HUFF_CODE tabledata[256];
// Search occurences
Huffman_Scan( infile, occ );
// Bluit tree
treedata = Huffman_InitNodes( occ );
treedata = Huffman_Tree( treedata );
// Bluit table
Huffman_CodeBuilt( treedata, tabledata );
// Compress file
Huffman_WriteCompressedData( infile, outfile, occ, tabledata );
// Release memory
Huffman_FreeTree( treedata );
return( 0 );
}
// int Huffman_Decode( char *infile, char *outfile )
// Uncompress file using Huffman
// Input : Input & output file names
// Ouput : 0 (Ok)
int Huffman_Decode( char *infile, char *outfile )
{
long occ[256], fbit = 0;
double long fsize = 0, fpos = 0, i;
FILE *streamo, *streami;
HUFF_CODE dskbuffer, tabledata[256];
HUFF_NODE *treedata;
dskbuffer.size = 0;
// open files
streamo = fopen( outfile, "wb" );
streami = fopen( infile, "rb" );
// Read occurences table
Huffman_ReadOcc( streami, occ );
// Bluit tree
treedata = Huffman_InitNodes( occ );
Page 40/68
TIPE : Le Format JPEG
treedata = Huffman_Tree( treedata );
// Built Huffman table
Huffman_CodeBuilt( treedata, tabledata );
// Calc file size
for( i = 0; i < 256; i++ )
fsize = fsize + occ[(unsigned char)i];
// Uncompress file
for( i = 0; i < fsize; i++ )
{
Huffman_ReadCData2Buffer( streami, treedata, &dskbuffer, &fpos, &fbit );
Huffman_WriteSaveUBuffer( streamo, &dskbuffer );
}
Huffman_WriteFlushUBuffer( streamo, &dskbuffer );
// Close files
fclose( streami );
fclose( streamo );
// Release memory
Huffman_FreeTree( treedata );
return( 0 );
}
// int Huffman_Scan( char *infile, long *tab )
// Create occurences table
// Input : Input file, allocated table
// Ouput : 0 (Ok)
int Huffman_Scan( char *infile, long *tab )
{
unsigned char buf;
int i;
FILE *stream;
// Init table
for( i = 0; i< 256; i++ )
tab[i] = 0;
stream = fopen( infile, "rb" );
// Calc occurences of each ASCII code
while( !feof( stream ) )
{
if( fread( &buf, 1, 1, stream ) )
tab[buf]++;
}
fclose( stream );
return( 0 );
}
// HUFF_NODE *Huffman_AddNodes( HUFF_NODE *bigger, HUFF_NODE *nnew )
// Add inital node & sort nodes
// Input : Huffman tree, new node
// Ouput : Pointer on Huffman tree
Page 41/68
TIPE : Le Format JPEG
HUFF_NODE *Huffman_AddNodes( HUFF_NODE *bigger, HUFF_NODE *nnew )
{
int flag;
HUFF_NODE *buf = NULL;
HUFF_NODE *prev = NULL;
// Init
flag = 0;
buf = bigger;
prev = NULL;
// Each of new node's place
while( ( buf != NULL) && ( flag == 0 ))
{
if( buf->oc >= nnew->oc )
{
prev = buf;
buf = buf->next;
}
else
flag = 1;
}
// Set prev & next var of new node
nnew->next = buf;
nnew->prev = prev;
// Set prev & next of new noce's neighborhood
if( prev != NULL )
prev->next = nnew;
if( buf != NULL )
buf->prev = nnew;
if( bigger == NULL )
bigger = nnew;
if( nnew->oc > bigger->oc )
bigger = nnew;
return( bigger );
}
// HUFF_NODE *Huffman_InitNodes( long *tab )
// Create inital nodes
// Input : Occurence table
// Ouput : Pointer on the 1st node
HUFF_NODE *Huffman_InitNodes( long *tab )
{
int i;
HUFF_NODE *bigger = NULL;
HUFF_NODE *buf;
// For each ASCII value
for( i = 0; i < 256; i++ )
{
// If the value exists in file
if( tab[i] != 0 )
{
// Create node
buf = (HUFF_NODE *)malloc( sizeof( HUFF_NODE ) );
buf->val = i;
buf->oc = tab[i];
Page 42/68
TIPE : Le Format JPEG
buf->fils0 = NULL;
buf->fils1 = NULL;
// Add it
bigger = Huffman_AddNodes( bigger, buf );
}
}
return( bigger );
}
// HUFF_NODE *Huffman_Tree( HUFF_NODE *bigger )
// Built Huffman tree
// Input : 1st inital node
// Ouput : pointer on the top of the Huffman Tree
HUFF_NODE *Huffman_Tree( HUFF_NODE *bigger )
{
HUFF_NODE *buf;
HUFF_NODE *smaller;
// Search for the 2 smallest occurences
smaller = bigger;
while( smaller->next != NULL )
smaller = smaller->next;
// Merge them to a new node
if( smaller->prev != NULL )
{
// Create node
buf = (HUFF_NODE *)malloc( sizeof( HUFF_NODE ) );
buf->val = -1;
buf->fils0 = smaller->prev;
buf->next = NULL;
buf->prev = NULL;
buf->fils1 = smaller;
buf->oc = buf->fils0->oc + buf->fils1->oc ;
// Add in tree
if( smaller->prev->prev != NULL )
{
smaller->prev->prev->next = NULL;
bigger = Huffman_AddNodes( bigger, buf );
buf = Huffman_Tree( bigger );
}
}
else // Only one -> the end
buf = bigger;
return( buf );
}
// int Huffman_TreeInitDisplay( HUFF_NODE *bigger )
// Display 1st step of the building of Huffman tree (inital nodes)
// Input : 1st node
// Ouput : 0 (Ok)
int Huffman_TreeInitDisplay( HUFF_NODE *bigger )
{
HUFF_NODE *buf;
buf = bigger;
Page 43/68
TIPE : Le Format JPEG
// Print each node
while( buf != NULL )
{
printf( "\n %i : %i", buf->val, buf->oc );
buf = buf->next;
}
printf( "\n" );
return( 0 );
}
// int Huffman_TreeDisplay( HUFF_NODE *bigger )
// Display Huffman Tree (Debug)
// Input : Huffman tree
// Ouput : 0 (Ok)
int Huffman_TreeDisplay( HUFF_NODE *bigger )
{
// Print current value
printf( "\n %i : %i", bigger->val, bigger->oc );
// Rec call on left child
if( bigger->fils0 != NULL )
Huffman_TreeDisplay( bigger->fils0 );
//Rec call on right child
if( bigger->fils1 != NULL )
Huffman_TreeDisplay( bigger->fils1 );
return( 0 );
}
// HUFF_CODE *Huffman_CodeBuilt( HUFF_NODE *bigger, HUFF_CODE *table )
// Init & Call Huffman_CodeBuiltRec()
// Input : Huffman tree, Empty huffman table
// Ouput : Pointer on Huffman table
HUFF_CODE *Huffman_CodeBuilt( HUFF_NODE *bigger, HUFF_CODE *table )
{
HUFF_CODE buf;
long i;
// Init buffer
buf.size = 0;
// Init tale
for( i = 0; i< 256; i++ )
table[i].size = 0;
// Start
Huffman_CodeBuiltRec( bigger, table, &buf );
return( table );
}
// HUFF_CODE *Huffman_CodeBuiltRec( HUFF_NODE *bigger, HUFF_CODE *table, HUFF_CODE *buf )
// Built Huffman table from huffman tree
// Input : Huffman tree, empty Huffman table, buffer
// Ouput : Pointer on Huffman table
Page 44/68
TIPE : Le Format JPEG
HUFF_CODE *Huffman_CodeBuiltRec( HUFF_NODE *bigger, HUFF_CODE *table, HUFF_CODE *buf )
{
HUFF_CODE buf1, buf2;
// If this is the last node
if( ( bigger->fils0 == NULL ) && ( bigger->fils1 == NULL ) )
{
table[bigger->val].size = buf->size;
Huffman_CodeCopy( table[bigger->val].data, buf->data, 0, 0, buf->size );
}
// Rec call on left child
if( bigger->fils0 != NULL )
{
Huffman_CodeCopy( buf1.data, buf->data, 0, 0, buf->size );
// Add node's value
buf1.data[buf->size] = 0;
buf1.size = buf->size + 1;
Huffman_CodeBuiltRec( bigger->fils0, table, &buf1 );
}
// Rec call on right child
if( bigger->fils1 != NULL )
{
Huffman_CodeCopy( buf2.data, buf->data, 0, 0, buf->size );
// Add node's value
buf2.data[buf->size] = 1;
buf2.size = buf->size + 1;
Huffman_CodeBuiltRec( bigger->fils1, table, &buf2 );
}
return( table );
}
// char *Huffman_CodeCopy( char *dest, char *source, long s1, long s2, long len )
// Copy Huffman code from one var to another, using start point 1 & 2 and length
// Input : Destination, Source, Start point 1, Start point 2, Length
// Ouput : pointer on Destination
char *Huffman_CodeCopy( char *dest, char *source, long s1, long s2, long len )
{
long i;
// Copy value
for( i = 0; i < len; i++ )
dest[s1 + i] = source[s2 + i];
return( dest );
}
// int Huffman_CodeDisplay( HUFF_CODE *table )
// Display Huffman table (Debug)
// Input : Huffman table
// Ouput : 0 (Ok)
int Huffman_CodeDisplay( HUFF_CODE *table )
{
long i, j;
Page 45/68
TIPE : Le Format JPEG
// Print each ASCII code's Huffman code
for( i = 0; i < 256; i++ )
{
if( table[i].size != 0 )
{
printf( "\n%i : ", i );
for( j = 0; j < table[i].size; j++ )
printf( "%i ", table[i].data[j] );
}
}
return( 0 );
}
// int Huffman_WriteOcc( FILE *outfile, long *tab )
// Write occurence table to disk
// Input : File stream (write mode), occurence table
// Ouput : 0 (Ok)
int Huffman_WriteOcc( FILE *outfile, long *tab )
{
long i, buf2;
// Write occurences for each ASCII code
for( i = 0; i < 256; i++ )
{
buf2 = tab[i];
fwrite( &buf2, sizeof( long ), 1, outfile );
}
return( 0 );
}
// int Huffman_ReadOcc( FILE *infile, long *tab )
// Read occurence table from disk
// Input : File stream (read mode)
// Ouput : 0 (Ok)
int Huffman_ReadOcc( FILE *infile, long *tab )
{
long i, buf2;
// Read occurences for each ASCII code
for( i = 0; i < 256; i++ )
{
fread( &buf2, sizeof( long ), 1, infile );
tab[i] = buf2;
}
return( 0 );
}
// int Huffman_WriteSaveBuffer( FILE *outfile, HUFF_CODE *buffer )
// if buffer (compressed data) is full (128 bits), write it
// Input : File stream (write mode), the buffer
// Ouput : 0 (ok)
int Huffman_WriteSaveBuffer( FILE *outfile, HUFF_CODE *buffer )
{
unsigned char charbuf;
long i, j;
Page 46/68
TIPE : Le Format JPEG
// If enough data
if( buffer->size > 128 )
{
for( i = 0; i< 128; i = i + 8 )
{
// Create char from 8 separate bits
charbuf = 0;
for( j =0; j < 8; j++ )
{
charbuf = charbuf * 2;
if( buffer->data[i+j] == 1 )
charbuf++;
}
// Write it
fwrite( &charbuf, 1, 1, outfile );
}
// Move reamining datas to the begining of the buffer
buffer->size = buffer->size - 128;
Huffman_CodeCopy( buffer->data, buffer->data, 0, 128, buffer->size );
}
return( 0 );
}
// int Huffman_WriteFlushBuffer( FILE *outfile, HUFF_CODE *buffer )
// Write remaining buffer (compressed data) to disk
// Input : File stream (write mode), the buffer
// Ouput : 0 (Ok)
int Huffman_WriteFlushBuffer( FILE *outfile, HUFF_CODE *buffer )
{
unsigned char charbuf;
long i, j;
// If buffer size is not multiple of 8
if( buffer->size%8 != 0 )
{
// Fill with 0
for( i = 0; i < ( 8 - buffer->size%8 ); i++ )
{
buffer->data[buffer->size] = 0;
buffer->size++;
}
}
// Write buffer
for( i = 0; i< buffer->size; i = i + 8 )
{
// Create char from 8 separate bits
charbuf = 0;
for( j =0; j < 8; j++ )
{
charbuf = charbuf * 2;
if( buffer->data[i+j] == 1 )
charbuf++;
}
// Write it
fwrite( &charbuf, 1, 1, outfile );
}
buffer->size = 0;
return( 0 );
Page 47/68
TIPE : Le Format JPEG
}
// int Huffman_ReadData2Buffer( FILE *infile, HUFF_CODE *tablehuff, HUFF_CODE *buffer )
// Read 1 char, compress it, and copy to buffer
// Input : File stream (read mode), Huffman table, the buffer
// Ouput : 0 (Ok)
int Huffman_ReadData2Buffer( FILE *infile, HUFF_CODE *tablehuff, HUFF_CODE *buffer )
{
unsigned char buf;
// Read 1 byte
fread( &buf, 1, 1, infile );
// Compress & copy to buffer
Huffman_CodeCopy( buffer->data, tablehuff[buf].data, buffer->size, 0, tablehuff[buf].size );
buffer->size = buffer->size + tablehuff[buf].size;
return( 0 );
}
// int Huffman_WriteCompressedData( char *infile, char *outfile, long *tableocc, HUFF_CODE *tablehuff )
// Compress data using huffman table & write it to disk
// Input : Input filename, output filename, occurence table, huffman table
// Ouput : 0 (Ok)
int Huffman_WriteCompressedData( char *infile, char *outfile, long *tableocc, HUFF_CODE *tablehuff )
{
FILE *streamo;
FILE *streami;
HUFF_CODE dskbuffer;
dskbuffer.size = 0;
// Open input & output files
streamo = fopen( outfile, "wb" );
streami = fopen( infile, "rb" );
// Write occurence table for further rebuilt of huffman tree
Huffman_WriteOcc( streamo, tableocc );
// Process data
while( !feof( streami ) )
{
Huffman_ReadData2Buffer( streami, tablehuff, &dskbuffer );
Huffman_WriteSaveBuffer( streamo, &dskbuffer );
}
Huffman_WriteFlushBuffer( streamo, &dskbuffer );
// Close files
fclose( streami );
fclose( streamo );
return( 0 );
}
// int Huffman_Bit( unsigned char a, int bit )
// Extract a bit from a char
// Input : a char, bit number (from right to left)
// Ouput : bit value
Page 48/68
TIPE : Le Format JPEG
int Huffman_Bit( unsigned char a, int bit )
{
// Mask bits & return
return( ( a >> ( 7 - bit ) ) & 0x00000001 );
}
// int Huffman_ReadCData2Buffer( FILE *infile, HUFF_NODE *hufftree, HUFF_CODE *buffer, double long *fpos, long *fbit )
// Read & unpack one char to the buffer
// Input : File stream (read mode), huffman tree, file position (byte), 1st bit number
// Ouput : 0 (ok)
int Huffman_ReadCData2Buffer( FILE *infile, HUFF_NODE *hufftree, HUFF_CODE *buffer, double long *fpos, long *fbit )
{
unsigned char buf[16], tbpos = 0;
HUFF_NODE *temp;
unsigned char i = 0;
// Set file pointer to actual decoding position
fseek( infile, HUFFMAN_TABLE_LENGTH + (long)*fpos, SEEK_SET );
// Read 16 bytes if possible
while( ( !feof( infile ) ) && ( i < 16 ) )
{
fread( &buf[i], 1, 1, infile );
i++;
}
// Find first meaningfull code
temp = hufftree;
while( temp->val == -1 )
{
// Follow Huffman tree
if( Huffman_Bit( buf[tbpos], *fbit ) == 0 )
temp = temp->fils0;
else
temp = temp->fils1;
*fbit = *fbit + 1;
if( *fbit == 8 )
{
*fbit = 0;
tbpos++;
}
}
// Update file position
*fpos = *fpos + tbpos;
// Add char to buffer
buffer->data[buffer->size] = (char)temp->val;
buffer->size++;
return( 0 );
}
// int Huffman_WriteSaveUBuffer( FILE *outfile, HUFF_CODE *buffer )
// if buffer (uncompressed data) is full (128 bytes), write it
// Input : File stream (write mode), buffer
// Ouput : 0 (Ok)
int Huffman_WriteSaveUBuffer( FILE *outfile, HUFF_CODE *buffer )
{
long i;
Page 49/68
TIPE : Le Format JPEG
if( buffer->size == 128 )
{
for( i = 0; i < 128; i++ )
fwrite( &buffer->data[i], 1, 1, outfile );
buffer->size = buffer->size - 128;
}
return( 0 );
}
// int Huffman_WriteFlushUBuffer( FILE *outfile, HUFF_CODE *buffer )
// Write remaining buffer (uncompressed data) to disk
// Input : File stream (write mode), buffer
// Ouput : 0 (Ok)
int Huffman_WriteFlushUBuffer( FILE *outfile, HUFF_CODE *buffer )
{
long i;
// Write all buffer
for( i = 0; i< buffer->size; i++ )
fwrite( &buffer->data[i], 1, 1, outfile );
buffer->size = 0;
return( 0 );
}
// int Huffman_FreeTree( HUFF_NODE *tree )
// Free the tree under the provided node
// Input : Start node
// Ouput : 0 (Ok)
int Huffman_FreeTree( HUFF_NODE *tree )
{
// Free one child
if( tree->fils0 != NULL )
Huffman_FreeTree( tree->fils0 );
// And the other
if( tree->fils1 != NULL )
Huffman_FreeTree( tree->fils1 );
// Free node
free( tree );
return( 0 );
}
// EOF
Page 50/68
TIPE : Le Format JPEG
// Matrix.h : Definitions for Matrix.cpp :
// Matrix manipulation
// (C) 2000-2001 Nicolas Richeton
// Approximated Pi constant
#define PI 3.14159265359
// Definition of a matrix
typedef struct
{
long x;
long y;
float **data;
} MATRIX;
// Definition of a RVB or YUV matrix
typedef struct
{
MATRIX a;
MATRIX b;
MATRIX c;
} TRIMATRIX;
// MATRIX *Matalloc( long x, long y, MATRIX *mat )
// Allocate a matrix
// Input : x & y sizes, pointer on a MATRIX
// Ouput : Pointer on the allocated MATRIX
extern MATRIX *Matalloc( long x, long y, MATRIX *mat );
// int Matfree( MATRIX *mat )
// Free an allocated MATRIX
// Input : Allocated MATRIX
// Ouput : 0 (Ok)
extern int Matfree( MATRIX *mat );
// int MatZero( MATRIX *mat )
// Fill a MATRIX with 0
// Input : Allocated MATRIX
// Ouput : 0 (Ok)
extern int MatZero( MATRIX *mat );
// MATRIX *MatCopy( MATRIX *mat1, MATRIX *mat2, long x1, long y1, long x2, long y2, long w, long h )
// Copy a MATRIX to another
// Input : Source MATRIX, Destination MATRIX, Starts points (x1, y1 & x2, y2), width and height
// Ouput : Pointer on the destination MATRIX
extern MATRIX *MatCopy( MATRIX *mat1, MATRIX *mat2, long x1, long y1, long x2, long y2, long w, long h );
// MATRIX *RandMat( MATRIX *mat )
// Random values
// Input : An allocated MATRIX
// Ouput : Pointer on the MATRIX
extern MATRIX *RandMat( MATRIX *mat );
// void ShowMat( MATRIX *mat )
Page 51/68
TIPE : Le Format JPEG
// Display a MATRIX (signed int)
// Input : An allocated MATRIX
// Ouput : 0 (Ok)
extern void ShowMat( MATRIX *mat );
// void ShowMatFloat( MATRIX *mat )
// Display a MATRIX (float)
// Input : An allocated MATRIX
// Ouput : 0 (Ok)
extern void ShowMatFloat( MATRIX *mat );
// MATRIX *MatSign( MATRIX *mat )
// Sign a MATRIX
// Input : An allocated MATRIX
// Ouput : 0 (Ok)
extern MATRIX *MatSign( MATRIX *mat );
// MATRIX *MatUnsign( MATRIX *mat )
// Unsign a MATRIX
// Input : An allocated MATRIX
// Ouput : 0 (Ok)
extern MATRIX *MatUnsign( MATRIX *mat );
// MATRIX *MatDGen( MATRIX *mat )
// Generate 'D' MATRIX for fDCT & ifDCT
// Input : An allocated MATRIX
// Ouput : Pointer on the 'fD' MATRIX
extern MATRIX *MatDGen( MATRIX *mat );
// MATRIX *MattDGen( MATRIX *mat )
// Generate t'D' MATRIX for fDCT & ifDCT
// Input : An allocated MATRIX
// Ouput : Pointer on the t'D' MATRIX
extern MATRIX *MattDGen( MATRIX *mat );
// MATRIX *MatMultiply( MATRIX *mat1, MATRIX *mat2, MATRIX *matr )
// Multiply 2 MATRIX
// Input : Two allocated MATRIX, an allocated free matrix to store the result
// Ouput : Pointer on the result (MATRIX)
extern MATRIX *MatMultiply( MATRIX *mat1, MATRIX *mat2, MATRIX *matr );
// MATRIX *fDCT( MATRIX *mat )
// Apply Fast DCT to the MATRIX
// Input : An allocated MATRIX
// Ouput : Pointer on this MATRIX
extern MATRIX *fDCT( MATRIX *mat );
// MATRIX *fDCT( MATRIX *mat )
// Apply inverse Fast DCT to the MATRIX
Page 52/68
TIPE : Le Format JPEG
// Input : An allocated MATRIX
// Ouput : Pointer on this MATRIX
extern MATRIX *fiDCT( MATRIX *mat );
// MATRIX *MatQuantGen( MATRIX *mat, int q )
// Generate quantization MATRIX
// Input : An allocated MATRIX, quality
// Ouput : Pointer on the quantization MATRIX
extern MATRIX *MatQuantGen( MATRIX *mat, int q );
// MATRIX *Quantize( MATRIX *mat, MATRIX *matq )
// Quantize
// Input : MATRIX to quantize, Quantization MATRIX
// Ouput : Pointer on Quantized MATRIX
extern MATRIX *Quantize( MATRIX *mat, MATRIX *matq );
// MATRIX *UnQuantize( MATRIX *mat, MATRIX *matq )
// UnQuantize
// Input : MATRIX to unquantize, Quantization MATRIX
// Ouput : Pointer on UnQuantized MATRIX
extern MATRIX *UnQuantize( MATRIX *mat, MATRIX *matq );
// short *Mat2Str( MATRIX *mat, short *str )
// Convert a MATRIX to a String
// Input : A MATRIX, a string buffer
// Ouput : Pointer on the String
extern short *Mat2Str( MATRIX *mat, short *str );
// MATRIX *Str2Mat( short *str, MATRIX *mat )
// Convert a String to a MATRIX
// Input : a string buffer, A MATRIX
// Ouput : Pointer on the MATRIX
extern MATRIX *Str2Mat( short *str, MATRIX *mat );
// void ShowStr( short *str, int len )
// Display String (signed)
// Input : String, string length
// Ouput : Nothing
extern void ShowStr( short *str, int len );
// void ShowStrUnsigned( short *str, int len )
// Display String (unsigned)
// Input : String, string length
// Ouput : Nothing
extern void ShowStrUnsigned( short *str, int len );
// EOF
Page 53/68
TIPE : Le Format JPEG
// Matrix.cpp : Matrix manipulation
// (C) 2000-2001 Nicolas Richeton
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "matrix.h"
// MATRIX *Matalloc( long x, long y, MATRIX *mat )
// Allocate a matrix
// Input : x & y sizes, pointer on a MATRIX
// Ouput : Pointer on the allocated MATRIX
MATRIX *Matalloc( long x, long y, MATRIX *mat )
{
long i;
// Set size
mat->x = x;
mat->y = y;
// Allocate x coordinates
mat->data = (float **)malloc( sizeof( float* ) * x );
// Allocate y coordinates
for( i = 0; i < x; i++ )
(mat->data)[i] = (float *)malloc( sizeof( float ) * y );
return( mat );
}
// int Matfree( MATRIX *mat )
// Free an allocated MATRIX
// Input : Allocated MATRIX
// Ouput : 0 (Ok)
int Matfree( MATRIX *mat )
{
long i;
// Free y coordinates
for( i = 0; i < mat->x; i++ )
free( mat->data[i] );
// Free x coordinates
free( mat->data );
return( 0 );
}
// int MatZero( MATRIX *mat )
// Fill a MATRIX with 0
// Input : Allocated MATRIX
// Ouput : 0 (Ok)
int MatZero( MATRIX *mat )
{
long i, j;
// For each coef
Page 54/68
TIPE : Le Format JPEG
for( i = 0; i < mat->x; i++ )
{
for( j = 0; j < mat->y; j++ )
{
// Set 0
mat->data[i][j] = 0;
}
}
return( 0 );
}
// MATRIX *MatCopy( MATRIX *mat1, MATRIX *mat2, long x1, long y1, long x2, long y2, long w, long h )
// Copy a MATRIX to another
// Input : Source MATRIX, Destination MATRIX, Starts points (x1, y1 & x2, y2), width and height
// Ouput : Pointer on the destination MATRIX
MATRIX *MatCopy( MATRIX *mat1, MATRIX *mat2, long x1, long y1, long x2, long y2, long w, long h )
{
long i, j;
for( i = 0; i < w; i++ )
{
for( j = 0; j < h; j++ )
{
// Copy coef
mat2->data[i + x2][j + y2] = mat1->data[i + x1][j + y1];
}
}
return( mat2 );
}
// MATRIX *RandMat( MATRIX *mat )
// Random values
// Input : An allocated MATRIX
// Ouput : Pointer on the MATRIX
MATRIX *RandMat( MATRIX *mat )
{
long i,j;
for( i = 0; i < mat->x; i++ )
{
for( j = 0; j < mat->y; j++ )
{
// Set random coef
(mat->data)[i][j] = (unsigned char)( rand() * 255);
}
}
return( mat );
}
// void ShowMat( MATRIX *mat )
// Display a MATRIX (signed int)
// Input : An allocated MATRIX
// Ouput : 0 (Ok)
void ShowMat( MATRIX *mat )
{
long i, j;
for( j = 0; j < mat->y; j++ )
Page 55/68
TIPE : Le Format JPEG
{
for( i = 0; i < mat->x; i++ )
{
// Print coef
printf( "%i\t", (int)mat->data[i][j] );
}
printf( "\n" );
}
printf( "\n" );
}
// void ShowMatFloat( MATRIX *mat )
// Display a MATRIX (float)
// Input : An allocated MATRIX
// Ouput : 0 (Ok)
void ShowMatFloat( MATRIX *mat )
{
long i, j;
for( j = 0; j < mat->y; j++ )
{
for( i = 0; i < mat->x; i++ )
{
printf( "%f\t ", mat->data[i][j] );
}
printf( "\n" );
}
printf( "\n" );
}
// MATRIX *MatSign( MATRIX *mat )
// Sign a MATRIX
// Input : An allocated MATRIX
// Ouput : 0 (Ok)
MATRIX *MatSign( MATRIX *mat )
{
long i, j;
for( i = 0; i < mat->x; i++ )
{
for( j = 0; j < mat->y; j++ )
{
// Substract 128 to each coef
mat->data[i][j] = mat->data[i][j] - 128;
}
}
return( mat );
}
// MATRIX *MatUnsign( MATRIX *mat )
// Unsign a MATRIX
// Input : An allocated MATRIX
// Ouput : 0 (Ok)
MATRIX *MatUnsign( MATRIX *mat )
{
long i, j;
for( i = 0; i < mat->x; i++ )
Page 56/68
TIPE : Le Format JPEG
{
for( j = 0; j < mat->y; j++ )
{
// Add 128 to each coef
mat->data[i][j] = mat->data[i][j] + 128;
}
}
return( mat );
}
// MATRIX *MatDGen( MATRIX *mat )
// Generate 'D' MATRIX for fDCT & ifDCT
// Input : An allocated MATRIX
// Ouput : Pointer on the 'fD' MATRIX
MATRIX *MatDGen( MATRIX *mat )
{
long x, y;
float n;
n = (float)mat->x;
for( x = 0; x < 8; x++ )
{
for( y = 0; y < 8; y++ )
{
// Set values as defined in the fDCT
if( x == 0 )
mat->data[x][y] = (float)sqrt( 1/n );
else
mat->data[x][y] = (float)(sqrt(2/n)*cos((2*((float)y)+1)*((float)x)*PI / (2*n) ));
}
}
return( mat );
}
// MATRIX *MattDGen( MATRIX *mat )
// Generate t'D' MATRIX for fDCT & ifDCT
// Input : An allocated MATRIX
// Ouput : Pointer on the t'D' MATRIX
MATRIX *MattDGen( MATRIX *mat )
{
long x, y;
float n;
n = (float)mat->x;
for( x = 0; x < 8; x++ )
{
for( y = 0; y < 8; y++ )
{
// Set values as defined in the fDCT
if( x == 0 )
mat->data[y][x] = (float)sqrt( 1/n );
else
mat->data[y][x] = (float)(sqrt(2/n)*cos((2*((float)y)+1)*((float)x)*PI / (2*n) ));
}
}
return( mat );
}
Page 57/68
TIPE : Le Format JPEG
// MATRIX *MatMultiply( MATRIX *mat1, MATRIX *mat2, MATRIX *matr )
// Multiply 2 MATRIX
// Input : Two allocated MATRIX, an allocated free matrix to store the result
// Ouput : Pointer on the result (MATRIX)
MATRIX *MatMultiply( MATRIX *mat1, MATRIX *mat2, MATRIX *matr )
{
long i, j, k;
for( j = 0; j < mat2->y; j++ )
{
for( i = 0; i < mat1->x; i++ )
{
// For each coef
matr->data[i][j] = 0;
for( k = 0; k < mat1->y; k++ )
{
matr->data[i][j] = matr->data[i][j] + (mat1->data[i][k])*(mat2->data[k][j]);
}
}
}
return( matr );
}
// MATRIX *fDCT( MATRIX *mat )
// Apply Fast DCT to the MATRIX
// Input : An allocated MATRIX
// Ouput : Pointer on this MATRIX
MATRIX *fDCT( MATRIX *mat )
{
MATRIX temp;
MATRIX dct, tdct;
// Allocate room for D, tD and buffer
Matalloc( 8, 8, &dct );
Matalloc( 8, 8, &tdct );
Matalloc( 8, 8, &temp );
// Generate D and tD
MatDGen( &dct );
MattDGen( &tdct );
// Multiply matrix (F = D*f*tD)
MatMultiply( mat, &tdct, &temp );
MatMultiply( &dct, &temp, mat );
// Free D, tD and buffer
Matfree( &temp );
Matfree( &dct );
Matfree( &tdct );
return( mat );
}
// MATRIX *fDCT( MATRIX *mat )
// Apply inverse Fast DCT to the MATRIX
// Input : An allocated MATRIX
// Ouput : Pointer on this MATRIX
Page 58/68
TIPE : Le Format JPEG
MATRIX *fiDCT( MATRIX *mat )
{
MATRIX temp;
MATRIX dct, tdct;
// Allocate room for D, tD and buffer
Matalloc( 8, 8, &dct );
Matalloc( 8, 8, &tdct );
Matalloc( 8, 8, &temp );
// Generate D and tD
MatDGen( &dct );
MattDGen( &tdct );
// Multiply matrix (f = tD*F*D)
MatMultiply( mat, &dct, &temp );
MatMultiply( &tdct, &temp, mat );
// Free D, tD and buffer
Matfree( &temp );
Matfree( &dct );
Matfree( &tdct );
return( mat );
}
// MATRIX *MatQuantGen( MATRIX *mat, int q )
// Generate quantization MATRIX
// Input : An allocated MATRIX, quality
// Ouput : Pointer on the quantization MATRIX
MATRIX *MatQuantGen( MATRIX *mat, int q )
{
long i, j, n, a;
n = 2;
a = 2;
for( i = 0; i < mat->x; i++ )
{
for( j = 0; j < mat->y; j++ )
{
// Calc each coef
mat->data[i][j] = 1 + ( 1 + a*( (float)pow( i, n ) + (float)pow( j, n ) ) )*q;
}
}
return( mat );
}
// MATRIX *Quantize( MATRIX *mat, MATRIX *matq )
// Quantize
// Input : MATRIX to quantize, Quantization MATRIX
// Ouput : Pointer on Quantized MATRIX
MATRIX *Quantize( MATRIX *mat, MATRIX *matq )
{
long i, j;
for( i = 0; i < mat->x; i++ )
{
for( j = 0; j < mat->y; j++ )
{
// Quantize each coef
Page 59/68
TIPE : Le Format JPEG
mat->data[i][j] = (float) ( ( (int)(mat->data[i][j]) / (int)(matq->data[i][j]) ) );
}
}
return( mat );
}
// MATRIX *UnQuantize( MATRIX *mat, MATRIX *matq )
// UnQuantize
// Input : MATRIX to unquantize, Quantization MATRIX
// Ouput : Pointer on UnQuantized MATRIX
MATRIX *UnQuantize( MATRIX *mat, MATRIX *matq )
{
long i, j;
for( i = 0; i < mat->x; i++ )
{
for( j = 0; j < mat->y; j++ )
{
// UnQuantize each coef
mat->data[i][j] = ( ( (mat->data[i][j]) * (matq->data[i][j]) ) );
}
}
return( mat );
}
// short *Mat2Str( MATRIX *mat, short *str )
// Convert a MATRIX to a String
// Input : A MATRIX, a string buffer
// Ouput : Pointer on the String
short *Mat2Str( MATRIX *mat, short *str )
{
long l, i, cnt = 0;
// Copy coefs in zig-zag
for( l = 0; l < 8; l = l+2 )
{
for( i = 0; i <= l; i++ )
{
str[cnt] = ( short)mat->data[i][l-i];
cnt++;
}
for( i = 0; i <= (l + 1 ); i++ )
{
str[cnt] = ( short)mat->data[l-i+1][i];
cnt++;
}
}
for( l = 6; l >= 0; l = l-2 )
{
for( i = l; i >= 0; i-- )
{
str[cnt] = ( short)mat->data[7-i][7-l+i];
cnt++;
}
for( i = l-1; i >= 0; i-- )
{
str[cnt] = ( short)mat->data[7-l+i+1][7-i];
cnt++;
Page 60/68
TIPE : Le Format JPEG
}
}
return( str );
}
// MATRIX *Str2Mat( short *str, MATRIX *mat )
// Convert a String to a MATRIX
// Input : a string buffer, A MATRIX
// Ouput : Pointer on the MATRIX
MATRIX *Str2Mat( short *str, MATRIX *mat )
{
long l, i, cnt = 0;
// Copy coefs in zig-zag
for( l = 0; l < 8; l = l+2 )
{
for( i = 0; i <= l; i++ )
{
mat->data[i][l-i] = str[cnt];
cnt++;
}
for( i = 0; i <= (l + 1 ); i++ )
{
mat->data[l-i+1][i] = str[cnt];
cnt++;
}
}
for( l = 6; l >= 0; l = l-2 )
{
for( i = l; i >= 0; i-- )
{
mat->data[7-i][7-l+i] = str[cnt];
cnt++;
}
for( i = l-1; i >= 0; i-- )
{
mat->data[7-l+i+1][7-i] = str[cnt];
cnt++;
}
}
return( mat );
}
// void ShowStr( short *str, int len )
// Display String (signed)
// Input : String, string length
// Ouput : Nothing
void ShowStr( short *str, int len )
{
int i;
for( i = 0; i < len; i++ )
{
printf( "%i ", (short)str[i] );
}
}
Page 61/68
TIPE : Le Format JPEG
// void ShowStrUnsigned( short *str, int len )
// Display String (unsigned)
// Input : String, string length
// Ouput : Nothing
void ShowStrUnsigned( short *str, int len )
{
int i;
for( i = 0; i < len; i++ )
{
printf( "%i ", (unsigned short)str[i] );
}
}
// EOF
Page 62/68
TIPE : Le Format JPEG
// Menu.h : Definitions for Menu.cpp
// (C) 2000-2001 Nicolas Richeton
// void Menu_DisplayHelp( void )
// Display Help
// Input : Nothing
// Ouput : Nothing
extern void Menu_DisplayHelp( void );
// EOF
// Menu.cpp : Display helps & copyrights
// (C) 2000-2001 Nicolas Richeton
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "matrix.h"
#include "menu.h"
// void Menu_DisplayHelp( void )
// Display Help
// Input : Nothing
// Ouput : Nothing
void Menu_DisplayHelp( void )
{
printf( "TIPE : Format JPEG\n" );
printf( "Par Nicolas Richeton\n" );
printf( "");
}
// EOF
Page 63/68
TIPE : Le Format JPEG
// Raw_io.h : Definitions for Raw_io.cpp :
// Raw picture Read/Write
// (C) 2000-2001 Nicolas Richeton
// void File_ReadRawSize( long *x, long *y )
// Ask picture size (RAW pictures does not contain such data)
// Input : pointers an x and y vars
// Ouput : Nothing
extern void File_ReadRawSize( long *x, long *y );
// TRIMATRIX *File_ReadRawData( char *file, TRIMATRIX *mat, long x, long y )
// Fill TRIMATRIX with picture datas
// Input : RAW file name, an allocated TRIMATRIX (right size), x and y : size of the picture
// Ouput : Pointer on the TRIMATRIX
extern TRIMATRIX *File_ReadRawData( char *file, TRIMATRIX *mat, long x, long y );
// TRIMATRIX *File_WriteRawData( char *file, TRIMATRIX *mat, long x, long y )
// Write TRIMATRIX datas to disk
// Input : RAW file name, an allocated TRIMATRIX (right size), x and y : size of the picture
// Ouput : Pointer on the TRIMATRIX
extern TRIMATRIX *File_WriteRawData( char *file, TRIMATRIX *mat, long x, long y );
// unsigned char Float2UChar( float val )
// Convert float to unsigned char with LIMITS
// Input : value (float)
// Ouput : value (unsigned char)
extern unsigned char Float2UChar( float val );
// EOF
Page 64/68
TIPE : Le Format JPEG
// Raw_io.cpp : Raw picture Read/Write
// (C) 2000-2001 Nicolas Richeton
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "matrix.h"
#include "raw_io.h"
// void File_ReadRawSize( long *x, long *y )
// Ask picture size (RAW pictures does not contain such data)
// Input : pointers an x and y vars
// Ouput : Nothing
void File_ReadRawSize( long *x, long *y )
{
printf( "\nRaw_io.cpp : Picture size needed :\nx=" );
scanf( "%u", x );
printf( "y=" );
scanf( "%u", y );
}
// TRIMATRIX *File_ReadRawData( char *file, TRIMATRIX *mat, long x, long y )
// Fill TRIMATRIX with picture datas
// Input : RAW file name, an allocated TRIMATRIX (right size), x and y : size of the picture
// Ouput : Pointer on the TRIMATRIX
TRIMATRIX *File_ReadRawData( char *file, TRIMATRIX *mat, long x, long y )
{
FILE *stream;
long i, j;
unsigned char buf;
// open file
stream = fopen( file, "rb" );
// Read and assign all datas
for( j = 0; j < y; j++ )
{
for( i = 0; i < x; i++ )
{
fread( &buf, 1, 1, stream );
(mat->a).data[i][j] = (float)buf;
fread( &buf, 1, 1, stream );
(mat->b).data[i][j] = (float)buf;
fread( &buf, 1, 1, stream );
(mat->c).data[i][j] = (float)buf;
}
}
// Close file
fclose( stream );
return( 0 );
}
// TRIMATRIX *File_WriteRawData( char *file, TRIMATRIX *mat, long x, long y )
// Write TRIMATRIX datas to disk
// Input : RAW file name, an allocated TRIMATRIX (right size), x and y : size of the picture
// Ouput : Pointer on the TRIMATRIX
Page 65/68
TIPE : Le Format JPEG
TRIMATRIX *File_WriteRawData( char *file, TRIMATRIX *mat, long x, long y )
{
FILE *stream;
long i, j;
unsigned char buf;
// Open file
stream = fopen( file, "wb" );
// Write each pixel
for( j = 0; j < y; j++ )
{
for( i = 0; i < x; i++ )
{
buf = Float2UChar( (mat->a).data[i][j] );
fwrite( &buf, 1, 1, stream );
buf = Float2UChar( (mat->b).data[i][j] );
fwrite( &buf, 1, 1, stream );
buf = Float2UChar( (mat->c).data[i][j] );
fwrite( &buf, 1, 1, stream );
}
}
// Close file
fclose( stream );
return( 0 );
}
// unsigned char Float2UChar( float val )
// Convert float to unsigned char with LIMITS
// Input : value (float)
// Ouput : value (unsigned char)
unsigned char Float2UChar( float val )
{
// Check for limits
if( val > 255 )
return( 255 );
else if( val < 0 )
return( 0 );
else // Return unchanged value
return( (unsigned char) val );
}
// EOF
Page 66/68
TIPE : Le Format JPEG
// stdafx.ccp : W32 stuffs
#include "stdafx.h"
// EOF
// stdafx.h : Again W32 stuff
#if !defined(AFX_STDAFX_H__91C198F5_572E_47CF_BC04_378A5DA1B036__INCLUDED_)
#define AFX_STDAFX_H__91C198F5_572E_47CF_BC04_378A5DA1B036__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define WIN32_LEAN_AND_MEAN
// Exclude rarely-used stuff from Windows headers
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__91C198F5_572E_47CF_BC04_378A5DA1B036__INCLUDED_)
//EOF
Page 67/68
TIPE : Le Format JPEG
17 - Annexe 3 : Bibliographie
Les documents suivant ont servit à l’élaboration de ce TIPE :
Livres :
« Techniques de compression des images, » Jean-Paul Guillois, Hermès
« Compression et cryptage de données multimédias, » Xavier Marsault, Hermès
Sites internet :
« Data Compression Reference Center »
http://www.rasip.fer.hr/research/compress/index.html
« Data Compression : a General Study »
http://www.stanford.edu/~udara/SOCO/index.htm
« Operation of the JPEG Algorithm »
http://www.ctie.monash.edu.au/emerge/multimedia/impl03.htm
« JPEG Compression Algorithm and Associated Data Structures »
http://people.aero.und.edu/~mschroed/jpeg.html
Sources C :
Sources de la librairie JPEG de l’« Independent JPEG Group » (jpegsr6b.zip)
Page 68/68

Documents pareils