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 i1 u 2 j1 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 Da , b= 2 cos2 b1 a si a0 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 i1 u 2 j1 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 1i 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, yC 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