Vous êtes sur la page 1sur 76

TIFF to GIF Converter & LZW Compression Algorithm FPGA Implementation

by

Josquin S Corrales Prepared For Dr. Yacoub El-Ziq MatrixView USA February 8, 2007

Table of Contents
Overview .................................................................................................................................................. 3 Development Platform Configuration .................................................................................................. 3 TIFF to GIF Conversion ........................................................................................................................... 4 Reference TIFF to GIF Converter Design ............................................................................................4 TIFF File Format2 ................................................................................................................................ 4 GIF File Format ....................................................................................................................................4 Embedded LZW ........................................................................................................................................ 8 Device Driver ...................................................................................................................................9 DataFlow: ........................................................................................................................................ 9 malloc/xil_malloc .......................................................................................................................... 11 EDK Debugger .............................................................................................................................. 13 Fast Simplex Link ................................................................................................................................... 13 LZW Compression Algorithm..................................................................................................................13 Appendix A: Stand Alone Re/TIFF Sources ........................................................................................... 14 Appendix B: Microblaze Implementation Sources ................................................................................. 37

Overview
The project objective was to develop a chip design that performed image file format conversion for an input TIFF to output GIF. In order to simplify the process, the projected was divided into three parts. Part I demonstrates a C version of the converter than runs on common x86 architectures in order to gain an understanding of TIFF and GIF file formats. No specialized hardware or chip was used. Part II demonstrates porting the C converter an embedded processor running on an FPGA using IP cores provided by the Xilinx Embedded Development Kit (EDK) and the development board support packages (BSP). Part III demonstrates a Verilog module that performs the data conversion.

Development Platform Configuration


Software Windows Xp Home Edition with Service Pack 2 Xilinx Integrated Software Environment (ISE) Release Version 6.3.03i Xilinx Embedded Development Kit (EDK) Release Version 6.3 Microsoft Visual C++ Version 6.0 Development Environment Cygwin UNIX emulation for Windows (DLL Version 1.5.18) utilites including gcc (GCC) 3.4.4 (cygming special) (gdc 0.12, using dmd 0.125) ImageMagick's "convert" utility and source coders/gif.c (ImageMagick-6.2.8) with giflib-4.1.4 by Eric S. Raymond, and tiff-3.8.2 by Sam Leffler Hardware Spartan-3 LC development kit (DS-KIT-3SLC400 Rev 2)1 from AVNET, formerly Memec Design Serial port connect PC to dev board. The Spartan-3 LC development board features the 400K-gate Xilinx Spartan-3 device (XC3S400-4PQ208CES) in the 208-pin quad flat-pack package.

Figure 1: Spartan-3 LC development

TIFF to GIF Conversion


TIFF -> Re/TIFF -> GIF

Reference TIFF to GIF Converter Design


Re/TIFF LZW encoder sources were based upon an open source tool from ImageMagick (ImageMagick-6.2.8) which links against the giflib-4.1.4 for a working 12-bit implementation of the LZW compression algorithm. Uncompressed GIF images can be produced by setting the compile options to utilize libungif-4.1.4.

TIFF File Format2

Figure 2: TIFF File Format

GIF File Format


The elements of the GIF include the internals/mechanics of reader (aka decoder) and the writer (aka encoder). There are rules that define how the encoder and decoder work in the GIF specification3. Due to legal issues associated with LZW encoding, developers have devised GIF images using uncompressed data also know as an "ungif" Image Data block.

The GIF file format follows a grammar that provides a division of the byte steam and high level overview. The basic definition of the GIF allows for a data stream to contain only the header, the logical screen descriptor, a global color table and a trailer. This will define a GIF image, which can be processed by viewer without error, but will not display any picture because it does not contain image data block. The Grammar.
<GIF Data Stream> ::= Header <Logical Screen> <Data>* Trailer <Logical Screen> ::= Logical Screen Descriptor [Global Color Table] <Data> ::= <Graphic Block> | <Special-Purpose Block> <Graphic Block> ::= [Graphic Control Extension] <Graphic-Rendering Block> <Graphic-Rendering Block> ::= <Table-Based Image> | Plain Text Extension <Table-Based Image> ::= Image Descriptor [Local Color Table] Image Data <Special-Purpose Block> ::= Application Extension | Comment Extension

The header contains some constant values that describe the file format that follows, sometimes referred to as the "Magic Number". The Logical Screen Descriptor contains the image width, height, global color table flag, along with other settings that define the format of the data stored in the Image Data block. The Global Color Table contains red-green-blue (RGB) color triplets in three sets of octets (e.g. 24-bits of RGB color entires). This block defines a maximum of 256 RGB entries and at a very basic level each Image Data octet is an index into this color table. The Image Descriptor is a header type block that specifies left position, top, width, height and other data of the Image Data block that follows. The Image Data block specifies the LZW Minimum Code size and the Image Data represented by codewords output by the LZW compression algo. This is the heart of how GIFs store image data. The details of how LZW compression is used to produce the codewords stored in the Image Data block is as follows. LZW is a lossless compression scheme because no round off errors or quantization occurs as in the application of transforms (e.g. wavelets) or other schemes. LZW compression operates by reading the input data, and then producing fixed length output codewords that are used to substitute longer running data input sequences. The codewords are devised by advancing an internal state machine counter called the "string table". Two special code words are added and enumerated to the string table which are the "clear code" and "end of stream code". The "clear" codeword provides the key to the uncompressed gif format. When the clear codeword is encounted by the LZW decoder, it resets the internal string table state machine. Uncompressed GIFs are image files that do not use LZW compression to compress their image data but are still recognizable as GIF by decoders which expect LZW compression image blocks. The idea is to

emit only single-symbol string codes, plus a Clear code every so often to keep the decoder from increasing the code width. The GIF byte order is little-endian. TIFF which has a designator for either. Sample output run
jsc01@LOCALHOST ~/im $ ls -aFl hi_uc.tiff -rw-r--r-- 1 jsc01 None 17130 Nov 2 16:13 hi_uc.tiff jsc01@LOCALHOST ~/im $ ./retiff hi_uc.tiff hi_retiff.gif debug IFD offset 4224 IFD records 16 4226 Tag fe Type 4 4232 Tag 100 Type 3 cols 132 423e Tag 101 Type 3 rows 115 424a Tag 102 Type 3 bps 8 size 15180 from row x cols 4256 Tag 103 Type 3 4262 Tag 106 Type 3 426e Tag 10d Type 2 427a Tag 111 Type 4 strip count 15 strip offset 1632 4286 Tag 115 Type 3 4292 Tag 116 Type 4 rows per strip 8 429e Tag 117 Type 4 strip byte counts offset 69c 42aa Tag 11a Type 5

42b6 Tag 11b Type 5 42c2 Tag 128 Type 3 42ce Tag 131 Type 2 42da Tag 140 Type 3 colormap size 768 colormap offset 80 Strip byte sizes: offset 0 byte size 1056

offset 13 byte size 1056 offset 14 byte size 396 TIFF image size 15180 from byte counts Strip offsets: offset 0 is 6d8

offset 13 is 3c78 offset 14 is 4098 Read image data 0. Read 0420 bytes of 0420 byte counts, offset 0006d8

13. Read 0420 bytes of 0420 byte counts, offset 003c78 14. Read 018c bytes of 018c byte counts, offset 004098 EncodeGIF clear code 100 end of information code 101 clear code 00 69 08 1c 48 b0 a0 c1 83 08 13 2a 5c c8 b0 a1 c3 87 10 23 4a 9c 48 b1 a2 c5 8b 18 33 6a dc c8 b1 a3 c7 8f 20 43 8a 1c 49 b2 a4 c9 93 28 53 aa 5c 89 12 c5 89 14 2f 53 a0 60 1. wrote 0x0420 bytes 49 53 24 cc 14 38 53 a8 d0 a9 b3 a6 4f 8d 38 4f c4 5c b1 73 85 51 16 44 7f 2a 9d a8 d3 e5 4b 15 46 a1 aa 60 d1 02 69 8a a5 58 1b 36 3d 81 e2 83 09 13 42 85 b6 70 c1 02 a9 0a 15 21 4f 7c 5d 6b a2 26 d1 a0 5c 99 e2 ec ea 15

ec 55 b3 80

5c 16 38 83

9c 57 57 87

53 37 90 8e

cb 7e 5d fc

5a 05 91 d4

f5 7c 19 e8

f8 18 a3 64

f2 31 89 15

c3 60 0d 64

88 0f 80 01 bf 54 c9 42 a8 09 12 1f 38 70 00 7b 22 22 ce c0 24 ec ea 24 fa 36 45 11 1f 48 e0 34 89 99 84 07 0e 19 32 54 98 70 81 c3 07 14 53 1d c2 0c 1c da 6e 51 ae 23 a7 f0 0c 98 84 71 d1 24 51 78 46 9d c1 02 85 09 cf 33 90 38 d1 02 2d c3 e1 7b

length 254 5b 34 a1 d8 b5 eb 13 1f 36 5c b8 b0 3d f4 07 f1 2. wrote 0x0420 bytes

15. wrote 0x018c bytes 5f 04 87 24 17 7f 6f 1e 0a 2c 38 33 6e ee e7 16 48 08 6e ed fc 0a 32 6c dc 4c 7a 39 17 54 38 e0 83 22 f4 32 10 b9 f6 05 d9 e8 6c 38 92 e6 0a 14 d2 e8 e1 c3 4c 15 1c a7 f0 41 87 9c 76 3f 53 21 04 0f 1c 37 60 5f c4 0a 19 b2 54 14 1e 88 19 2c 72 10 8a 10 12 32 50 20 9c 51 17 5c a8 41 33 c5 c6 c0 80 02 67 0b 80 b0 61 21 54 d6 91 21 e6 da c4 af c2 03 06 bc 27 77 84 07 a8 7a 60 f3 09 0e 22 f7 38 66 12 24 3e f6 ee 28 26 77 ac 5c ec b6 4e f2 48 7a 19 e3 a4 ec ea 22 ac c7 48 c9 f5 ea 8b e0 a1 d3 6b cc 8e 64 62 85 d2 0b 29 7b 05 8b 17 71 a2 13 0b 13 2e 39 42 2f 18 27 5e 64 1d ae 2f 36 90 a0 41 70 26 ae 85 ab 22 ac 4a f8 11 96 aa c8 cc 18 03 c4 08 e4 18 63 ac 89 8c c6 21 a4 c3 b3 2c 97 82 4f 0f 7c 14 33

19cf bytes of 3b4c bytes compressed Done.

Figure 3: MSVC++ Binary View of File hi_retiff.gif used to verify correctness of output file format bytes

Figure 4: hi_retiff.gif image file

Embedded LZW
Several factors changed to nature of the assignment including the file format of TIFF in that it is not directly serializable and can be up to 2 GB in size.

Device Driver Device driver API allow access to VHDL and Verilog IP cores from an embedded processor application. UART Timing universal asynchronous receiver/transmitter interrupt based data I/O DataFlow: TIFF file -> Re/TIFF (host cpu) -> UART -> LZW (fpga) -> UART -> Re/TIFF (host cpu) -> GIF file The Xilinx Platform Studio (XPS) includes a wizard to design an embedded processor system. The EDK provides the VHDL IP cores listed Table in listed in cores which map to the Spartan-3 LC development hardware. The mapping is set via an Microprocessor Hardware Specification (MHS) file (e.g. System.mhs). An MHS file defines the configuration of the embedded processor system, and includes the Bus architecture, Peripherals, Processor, Connectivity, and Address space.4 The Base System Builder (BSB) wizard is a software tool that help users quickly build a working embedded processor system targeted at a specific development board. Peripheral microblaze opb_mdm lmb_bram_if_cntlr lmb_bram_if_cntlr bram_block opb_uartlite opb_gpio opb_gpio opb_gpio opb_gpio opb_intc HW Ver 3.00.a 2.00.a 1.00.b 1.00.b 1.00.a 1.00.b 3.01.b 3.01.b 3.01.b 3.01.b 1.00.c Instance Microblaze_0 debug_module dlmb_cntlr ilmb_cntlr lmb_bram RS232 LEDs_4Bit LED_7Segment Push_Buttons_1Bit DIP_Switches_4Bit opb_intc_0

Table 1: Hardware Platform Specification which maps to the System.mhs file

Serial Port Communication Parameters: 115,200 baud, 8 data bits, 1 parity bit, 50 MHz clock rate. 115200

8 0 1 50000000

Figure 5: MicroBlaze Processor Reference Guide. Embedded Development Kit EDK 6.3i. UG081 (v4.2) November 18 2004, pp 12.

Figure 6: Spartan3 LC Board Hardware Components

Figure 7: RS232 interface to the UART device, processor core, and BRAM5.

The text number plus the data and bss represent the total memory consumed by the embedded design.
At GMT date and time: 2007:1:14:15:55:43 Command bash -c "cd /xygdrive/d/design/m3d5/; mb-size D:/design/m3d5/tiff2gif/ executable.elf; exit;" Started... text data bss dec hex filename 3356 3216 12 6584 19b8 D:/design/m3d5/tiff2gif/executable.elf Done.

malloc/xil_malloc These calls are unimplemented for the Spartan-3 with this version of the EDK. There are Xilinx tech notes explaining that their usage does not properly release memory back to the embedded processor.

Figure 8: System.pbd
Table 1: Summary of Spartan-3 FPGA Attributes Device System Gates Equivalent Logic Cells CLB Array (One CLB = Four Slices) Distributed RAM (bits1) Block RAM (bits1) Dedicated

Multipliers DCMs Maximum User I/O Maximum Differential I/O Pairs XC3S4002 400K 8,064 32 28 896 56K 288K 16 4 264 1166

EDK Debugger

Fast Simplex Link


This part of the assignment is <<<TBD>>>, but can be accomplished via the On-chip Peripheral Bus Fast Simplex Link IP (opb_fsl). FSL provides a bootstrap device driver interface into the MicroBlaze processor, VHDL entity bus, and provisions for custom Verilog module integration.

LZW Compression Algorithm


Terry A. Welch describes the Lempel-Ziv Welch (LZW) algorithm in a paper titled, "A Technique for High-Performance Data Compression", in the June 1984 IEEE volume 17, issue 6 publication on page 15. The value of this compression algorithm lies in its fast runtime performance for compressing and decompressing data, which proved to be an evolutionary advancement in the development of compression algorithms from the known Huffman coding method. LZW utilizes a greedy graph coloring algorithm to populate the input string table. The serialized data stream is read into a prefix string table, and if the input does not match anything in the string table, a new code word is output, and added into the string table. Data compressed in this method produces higher entropy characteristics, making further compression inefficient.

Appendix A: Stand Alone Re/TIFF Sources


/* File: retiff.h Description : Re-TIFF header data types Compile line : gcc -ansi -g -o retiff retiff.c Written by : JSC 11/29/06 */ #define UBYTE unsigned char /* 1 byte */ #define USHORT unsigned short /* 2 bytes */ #define ULONG unsigned long /* 4 bytes */ /* */ #define IFD_OFFSET_L 4L #define IFD_SIZE (UBYTE) 12 /* Used to reset offsets */ #define TAG_STRIPOFFSETS 273 #define TAG_COLORMAP 320 /* Used to re-align image data */ #define TAG_SAMPLESPERPIXEL 277 #define TAG_ROWSPERSTRIP 278 #define TAG_STRIPBYTECOUNTS 279 #define TAG_IMAGEWIDTH 256 /* cols */ #define TAG_IMAGELENGTH 257 /* rows */ #define TAG_BITSPERSAMPLE 258 #define BITSPERBYTE 8 /* debug levels */ int DEBUG = 0; /* For storing TIFF data and interpreting

the values */ typedef union _udata { UBYTE b_val[4]; USHORT s_val[2]; ULONG l_val; } udata; /* unsigned data */ /* Image File Directory Entries */ typedef struct _ifd { USHORT tag_id; USHORT type; UBYTE n[4]; udata vo; /* value offset */ } ifd; /* RAW image format */ typedef struct _retiff { USHORT height, width; USHORT bps; /* bits per sample */ ULONG size; /* # of rows in image data array, * in byte counts array, & * in strip offsets array */ ifd *p_cmh; /* color map header */ USHORT *p_cm; /* color map palette */ ULONG *p_bytecounts; /* array of size of strip data */

ULONG *p_stripoffsets; /* TIFF file data strip offsets */ UBYTE **p_imagedata; /* [rows][columns] */ /* image data */ } retiff; typedef struct _lzwGIF { unsigned int height, width; unsigned int size; /* malloc size */ unsigned int length; /* used size (non-free)*/ unsigned char *data; /* compressed data */ unsigned int cm_size; /* color map size */ unsigned char *cm; /* color map */ } lzwGIF; #define MaxCode(number_bits) ((1UL << (number_bits))-1) /* Mystery: Why 5003 ?? 0001 0011 1000 1011 0x138b */ #define MaxHashTable /* 5003 */ /* 2051 */ 617 /* fits! */ #define MaxGIFBits /* 12UL */ /* 11UL */ 9UL /* fits! */ #define MaxGIFTable (1UL << MaxGIFBits) #define GIFOutputCode(code) \ { \ /* \ Emit a code. \ */ \ if (bits > 0) \ datum |= (code) << bits; \ else \ datum=code; \

bits+=number_bits; \ while (bits >= 8) \ { \ /* \ Add a character to current packet. \ */ \ if (code == clear_code) { \ printf("\nclear code %.2x\n", (unsigned char) (datum & 0xff)); \ } else { \ printf("%.2x ", (datum & 0xff)); \ } \ fflush(stdout); \ packet[length++]=(unsigned char) (datum & 0xff); \ if (length >= 254) \ { \ length &= 0xff; \ memcpy(&p_gif->data[p_gif->length], &length , 1); \ p_gif->length++; \ { \ int i; \ for (i=0; i < length; ++i, ++p_gif->length) { \ /* printf("%.2x ",packet[i]); */ \ p_gif->data[p_gif->length] = packet[i]; \ } \ } \ /* \ memcpy(&p_gif->data[p_gif->length], &packet[0], length); \ p_gif->length += length; \ */ \ /* \

{ \ int i; \ for (i = 0; i < length; ++i) { \ printf("%.2x ", packet[i]); \ } \ puts(""); \ } \ */ \ printf("\nlength %d\n\n",length); \ fflush(stdout); \ length=0; \ } \ datum>>=8; \ bits-=8; \ } \ if (free_code > max_code) \ { \ number_bits++; \ if (number_bits == MaxGIFBits) \ max_code=MaxGIFTable; \ else \ max_code=MaxCode(number_bits); \ } \ } int EncodeImage(retiff *p_retiff, lzwGIF *p_gif, const unsigned long data_size); /* File: retiff.c Description : Reads an input TIFF so that the Image File Directory (IFD)

entries are ordered first and the bitmap data last. Creates a GIF output. Compile line : gcc -ansi -g -o retiff retiff.c Written by : JSC 11/23/06 */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <assert.h> #include "retiff.h" int main(int argc, char *argv[]) { FILE *fh; UBYTE ifd_size; int i, j; udata *p_dat; ifd **p_ifd; unsigned int rows; unsigned int cols; unsigned int size; /* measured in bytes */ udata ssize; /* byte counts */ unsigned int bc_index; /* output */ ULONG s_offset; ULONG cm_offset; retiff *p_retiff; lzwGIF *p_gif; if (argc < 3) { printf("Usage: %s <in.tiff> <out.gif> [DEBUG]\n\n", argv[0]); puts("\tRewrites input TIFF IFD entries to top of file.\n");

exit(-1); } if (argc == 4) { DEBUG = 1; } else { DEBUG = 0; } p_dat = (udata *) calloc(1, sizeof(udata)); fh = fopen(argv[1],"rb"); fseek(fh, IFD_OFFSET_L, SEEK_CUR); /* assume little-endian */ /* Read in IFD offset val */ fread(&p_dat->b_val[0], 4*sizeof(UBYTE), 1, fh); if (DEBUG) printf("IFD offset %x\n", p_dat->l_val); /* Seek forward to IFD entries */ fseek(fh, (long) p_dat->l_val, SEEK_SET); /* Read number of IFD entries value */ fread(&p_dat->b_val[0], 2*sizeof(UBYTE), 1, fh); if (DEBUG) printf("IFD records %d\n", p_dat->s_val[0]); /* allocate ifd structure */ ifd_size = p_dat->s_val[0]; p_ifd = (ifd **) calloc(ifd_size, sizeof(ifd*)); for (i=0; i < ifd_size; ++i) { p_ifd[i] = (ifd *) calloc(1, sizeof(ifd)); } p_retiff = (retiff *) calloc(1, sizeof(retiff)); /* using calloc to initialize members to 0's */ p_gif = (lzwGIF *) calloc(1, sizeof(lzwGIF)); for (i=0; i < ifd_size && !feof(fh); ++i) {

fpos_t pos; fgetpos(fh, &pos); if (DEBUG) printf("%x\t", pos); if (!fread(p_ifd[i], sizeof(ifd), 1, fh)) { break; } if (DEBUG) printf("Tag %x\tType %x\n", p_ifd[i]->tag_id, p_ifd[i]->type); switch (p_ifd[i]->tag_id) { case TAG_ROWSPERSTRIP : { if (DEBUG) printf("\trows per strip %d\n", p_ifd[i]->vo.l_val); break; } case TAG_IMAGEWIDTH : { cols = p_ifd[i]->vo.l_val; p_gif->width = p_ifd[i]->vo.l_val; if (DEBUG) printf("\tcols %d\n", cols); break; } case TAG_IMAGELENGTH : { rows = p_ifd[i]->vo.l_val; p_gif->height = (unsigned short) p_ifd[i]->vo.l_val; if (DEBUG) printf("\trows %d\n", rows); break; } case TAG_BITSPERSAMPLE : {

size = (rows * cols * p_ifd[i]->vo.l_val) / BITSPERBYTE; p_retiff->bps = p_ifd[i]->vo.s_val[0]; /* higher order bits assumed to be 0 based on TIFF spec and sample file */ if (DEBUG) { printf("\tbps %d\n", p_ifd[i]->vo.l_val); printf("\tsize %d from row x cols\n", size); } break; } case TAG_STRIPOFFSETS : { ssize.b_val[0] = p_ifd[i]->n[0]; ssize.b_val[1] = p_ifd[i]->n[1]; ssize.b_val[2] = p_ifd[i]->n[2]; ssize.b_val[3] = p_ifd[i]->n[3]; s_offset = p_ifd[i]->vo.l_val; if (DEBUG) { printf("\tstrip count %d\n", ssize.l_val); printf("\tstrip offset %d\n", s_offset); } break; } case TAG_STRIPBYTECOUNTS : { bc_index = i; if (DEBUG) printf("\tstrip byte counts offset %x\n", p_ifd[i]->vo.l_val); break; } case TAG_COLORMAP : { udata csize; cm_offset = p_ifd[i]->vo.l_val;

csize.b_val[0] = p_ifd[i]->n[0]; csize.b_val[1] = p_ifd[i]->n[1]; csize.b_val[2] = p_ifd[i]->n[2]; csize.b_val[3] = p_ifd[i]->n[3]; if (DEBUG) { printf("\tcolormap size %d\n", csize.l_val); printf("\tcolormap offset %d\n", cm_offset); } /* assumption is 256 RGB tuplets */ /* assign color map structure */ p_retiff->p_cmh = p_ifd[i]; p_retiff->p_cm = (USHORT *) calloc(csize.l_val, sizeof(USHORT)); /* read color map data */ fseek(fh, (long) p_ifd[i]->vo.l_val, SEEK_SET); fread(p_retiff->p_cm, sizeof(USHORT), csize.l_val, fh); /* transfer to GIF */ p_gif->cm_size = csize.l_val; p_gif->cm = (unsigned char *) calloc(csize.l_val, sizeof(unsigned char)); for (i=0, j=0; i < p_gif->cm_size-2; ++j) { p_gif->cm[i] = (UBYTE) p_retiff->p_cm[j]; /* Red */ p_gif->cm[i+1] = (UBYTE) p_retiff->p_cm[j + 256]; /* Green */ p_gif->cm[i+2] = (UBYTE) p_retiff->p_cm[j + 512]; /* Blue */ i = i + 3; } break; } } } fflush(stdout); /*

Save/Print out the byte count values */ { unsigned int *p_offsets = NULL; udata size; memcpy(&size, p_ifd[bc_index]->n, sizeof(ULONG)); p_offsets = (unsigned int *) calloc(size.l_val, sizeof(unsigned int)); /* seek forward to the byte counts */ fseek(fh, (long) p_ifd[bc_index]->vo.l_val, SEEK_SET); fread(p_offsets, sizeof(unsigned int), size.l_val, fh); if (DEBUG) puts("\nStrip byte sizes:"); p_retiff->size = size.l_val; p_retiff->p_bytecounts = (ULONG *) calloc(size.l_val, sizeof(ULONG)); for (i=0; i < size.l_val; ++i) { if (DEBUG) printf("\toffset %d byte size %d\n", i, p_offsets[i]); p_retiff->p_bytecounts[i] = p_offsets[i]; p_gif->size += p_offsets[i]; } if (DEBUG) printf("\tTIFF image size %d from byte counts\n",p_gif->size); free(p_offsets); } /* Save/print out the strip offsets */ { unsigned int *p_offsets = NULL; p_offsets = (unsigned int *) calloc(ssize.l_val, sizeof(unsigned int));

p_retiff->p_stripoffsets = (ULONG *) calloc(ssize.l_val, sizeof(ULONG)); fseek(fh, (long) s_offset, SEEK_SET); fread(p_offsets, sizeof(unsigned int), ssize.l_val, fh); if (DEBUG) puts("\nStrip offsets:"); for (i=0; i < ssize.l_val; ++i) { p_retiff->p_stripoffsets[i] = p_offsets[i]; if (DEBUG) printf("\toffset %d is %x\n", i, p_offsets[i]); } free(p_offsets); p_offsets=NULL; } /* Read image data into retiff data struct */ { int b_read; /* bytes read */ p_retiff->p_imagedata = (UBYTE **) calloc(p_retiff->size, sizeof(UBYTE *)); puts("\nRead image data"); for (i=0; i < p_retiff->size; ++i) { b_read = 0; p_retiff->p_imagedata[i] = (UBYTE *) calloc(p_retiff->p_bytecounts[i], sizeof(UBYTE)); fseek(fh, (long) p_retiff->p_stripoffsets[i], SEEK_SET); b_read = fread(p_retiff->p_imagedata[i], sizeof(UBYTE), p_retiff->p_bytecounts[i], fh); if (feof(fh)) { if (DEBUG) puts("End of file encountered"); } if (DEBUG)

printf("%d.\tRead %.4x bytes of %.4x byte counts, offset %.6x\n", i, b_read, p_retiff->p_bytecounts[i], p_retiff->p_stripoffsets[i]); } } /* * LZW Compress to GIF structure */ { p_gif->data = (unsigned char *) calloc(p_gif->size, sizeof (unsigned char)); #define LZW_CODE_BIT_SIZE 9 EncodeImage(p_retiff, p_gif, LZW_CODE_BIT_SIZE); /* 9 */ if (DEBUG) printf("\n%x bytes of %x bytes compressed\n", p_gif->length, p_gif->size); } /* * Write the GIF file */ { unsigned char buf[256]; FILE *fh_gif; fh_gif = fopen(argv[2], "wb"); /* Header */ sprintf(buf, "%s", "GIF89a"); fwrite(buf, sizeof(unsigned char), 6, fh_gif); /* Logical Screen Descriptor */ fwrite(&p_gif->width, sizeof(unsigned short), 1, fh_gif); fwrite(&p_gif->height, sizeof(unsigned short), 1, fh_gif); buf[0]=0xf7; /* packed field */ fwrite(buf, sizeof(unsigned char), 1, fh_gif); buf[0]=0x00; /* background color index */

fwrite(buf, sizeof(unsigned char), 1, fh_gif); buf[0]=0x00; /* pixel aspect ratio */ fwrite(buf, sizeof(unsigned char), 1, fh_gif); /* Global Color Table */ fflush(fh_gif); fwrite(p_gif->cm, sizeof(unsigned char), p_gif->cm_size, fh_gif); fflush(fh_gif); /* Image Descriptor */ buf[0]=0x2c; /* Image Separator */ fwrite(buf, sizeof(unsigned char), 1, fh_gif); fflush(fh_gif); buf[0]=0x00; /* Image Left Position */ buf[1]=0x00; fwrite(buf, sizeof(unsigned char), 2, fh_gif); buf[0]=0x00; /* Image Top Position */ buf[1]=0x00; fwrite(buf, sizeof(unsigned char), 2, fh_gif); fwrite(&p_gif->width, sizeof(unsigned short), 1, fh_gif); fwrite(&p_gif->height, sizeof(unsigned short), 1, fh_gif); buf[0]=0x00; /* Packed Fields */ fwrite(buf, sizeof(unsigned char), 1, fh_gif); /* Table Based Image Data */ buf[0]=LZW_CODE_BIT_SIZE-1; /* LZW Minimum Code Size */ fwrite(buf, sizeof(unsigned char), 1, fh_gif); /* Image Data */ { unsigned char *p_data; p_data = &p_gif->data[0]; for (i=0 ; i < p_gif->length ; ++i) { fwrite(p_data++, sizeof(unsigned char), 1, fh_gif);

fflush(fh_gif); } } /* Trailers */ buf[0] = 0x00; buf[1] = 0x3b; fwrite(buf, sizeof(unsigned char), 2, fh_gif); fflush(fh_gif); fclose(fh_gif); fh_gif = NULL; } /* free memory used */ if (p_retiff->p_cm != NULL) { free(p_retiff->p_cm); p_retiff->p_cm = NULL; } if (p_retiff->p_bytecounts != NULL) { free(p_retiff->p_bytecounts); p_retiff->p_bytecounts = NULL; } if (p_retiff->p_stripoffsets != NULL) { free(p_retiff->p_stripoffsets); p_retiff->p_stripoffsets = NULL; } if (p_retiff->p_imagedata != NULL) { for (i=0; i<p_retiff->size; i++) { if (p_retiff->p_imagedata[i] != NULL) { free(p_retiff->p_imagedata[i]); p_retiff->p_imagedata[i] = NULL; }

} free(p_retiff->p_imagedata); p_retiff->p_imagedata = NULL; } free(p_retiff); p_retiff = NULL; if (p_gif->cm != NULL) { free(p_gif->cm); p_gif->cm = NULL; } { /* free gif lzw data */ if (p_gif->data != NULL) { free(p_gif->data); p_gif->data = NULL; } } free(p_gif); p_gif = NULL; for (j=0; j < ifd_size; ++j) { free(p_ifd[j]); p_ifd[j] = NULL; } free(p_ifd); p_ifd=NULL; fclose(fh); fh=NULL; free(p_dat); p_dat = NULL; if (DEBUG) puts("Done.");

exit(0); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % E n c o d e I m a g e % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % EncodeImage LZW compresses an image via GIF-coding. % % The format of the EncodeImage method is: % % int EncodeImage( % retiff *p_retiff, % lzwGIF *p_gif, % const unsigned long data_size) % % A description of each parameter follows: % % o p_retiff: The address of a structure defining the image data. % % o p_gif: output gif image block % % o data_size: The number of bits in the compressed packet. % % Comments: % % JSC 10/28/06 Modified from ImageMagick-6.2.8 coders/gif.c and adapted % for Re-TIFFing

% */ int EncodeImage(retiff *p_retiff, lzwGIF *p_gif, const unsigned long data_size) { unsigned char index; long displacement, k, y; register long i, x; size_t length; short *hash_code, *hash_prefix, waiting_code; unsigned char *packet, *hash_suffix; unsigned long bits, clear_code, datum, end_of_information_code, free_code, max_code, next_pixel, number_bits;

/* Allocate encoder tables. */ assert(p_retiff != (retiff *) NULL); packet=(unsigned char *) calloc(256, sizeof(*packet)); /* codes */ hash_code=(short *) calloc(MaxHashTable, sizeof(*hash_code)); /* omega */ hash_prefix=(short *) calloc(MaxHashTable, sizeof(*hash_prefix)); /* K */ hash_suffix=(unsigned char *) calloc(MaxHashTable, sizeof(*hash_suffix)); /* test for calloc failure e.g. OutOfMemory Exception */ if ((packet == (unsigned char *) NULL) || (hash_code == (short *) NULL) || (hash_prefix == (short *) NULL) || (hash_suffix == (unsigned char *) NULL)) { if (packet != (unsigned char *) NULL) free(packet); if (hash_code != (short *) NULL) free(hash_code); if (hash_prefix != (short *) NULL) free(hash_prefix); if (hash_suffix != (unsigned char *) NULL) free(hash_suffix); return (0); /* FALSE */ } /* Initialize GIF encoder. */ number_bits=data_size; max_code=MaxCode(number_bits);

clear_code=((short) 1UL << (data_size-1)); end_of_information_code=clear_code+1; if (DEBUG) { puts("\nEncodeGIF"); printf("\tclear code %x\n",clear_code); printf("\tend of information code %x\n",end_of_information_code); } free_code=clear_code+2; length=0; datum=0; bits=0; for (i=0; i < MaxHashTable; i++) hash_code[i]=0; GIFOutputCode(clear_code); /* Encode pixels. */ waiting_code=0; for (y=0; y < (long) p_retiff->size; y++) { if (y == 0) /* LZW algo: Initialize table to contain single-char strings. Read first input char -- prefix string w (omega) w == waiting_code or prefix */ waiting_code=(short) p_retiff->p_imagedata[0][0]; for (x=(y == 0) ? 1 : 0; x < (long) p_retiff->p_bytecounts[y]; x++) { index=p_retiff->p_imagedata[y][x] & 0xff; /* Probe hash table.

*/ /* LZW algo (continued) Step: Read next input character k if no such k (input exhausted): code(w) -> output : EXIT if wk exists in string table: wk -> w; repeat Step else wk not in string table : code(w) -> output; wk -> string table; k -> w; repeat Step */ k=(long) (index << (MaxGIFBits-8))+waiting_code; if (k >= MaxHashTable) k-=MaxHashTable; next_pixel=0; /* MagickFalse; */ displacement=1; /* if wk exists in string table ? */ if (hash_code[k] > 0) { if ((hash_prefix[k] == waiting_code) && (hash_suffix[k] == (unsigned char) index)) { /* yes -- repeat Step */ waiting_code=hash_code[k]; continue; } if (k != 0) displacement=MaxHashTable-k; for ( ; ; ) { k-=displacement; if (k < 0) k+=MaxHashTable; if (hash_code[k] == 0)

break; if ((hash_prefix[k] == waiting_code) && (hash_suffix[k] == (unsigned char) index)) { waiting_code=hash_code[k]; next_pixel=1; /* MagickTrue; */ break; } } if (next_pixel == 1) /* MagickTrue */ continue; } GIFOutputCode((unsigned long) waiting_code); if (free_code < MaxGIFTable) { hash_code[k]=(short) free_code++; hash_prefix[k]=waiting_code; hash_suffix[k]=(unsigned char) index; } else { /* Fill the hash table with empty entries. */ for (k=0; k < MaxHashTable; k++) { hash_code[k]=0; } /* Reset compressor and issue a clear code. */ free_code=clear_code+2; GIFOutputCode(clear_code); number_bits=data_size; max_code=MaxCode(number_bits);

} waiting_code=(short) index; } if (DEBUG) printf("\n%d. wrote 0x%.4x bytes\n", y + 1, p_retiff->p_bytecounts[y]); } /* Flush out the buffered code. */ GIFOutputCode((unsigned long) waiting_code); GIFOutputCode(end_of_information_code); if (bits > 0) { /* Add a character to current packet. */ packet[length++]=(unsigned char) (datum & 0xff); if (length >= 254) { memcpy(&p_gif->data[p_gif->length], &length, 1); p_gif->length++; memcpy(&p_gif->data[p_gif->length], &packet[0], length); p_gif->length += length; length=0; } } /* Flush accumulated data. */

if (length > 0) { printf("%.2x ",length); memcpy(&p_gif->data[p_gif->length], &length, 1); p_gif->length++; memcpy(&p_gif->data[p_gif->length], &packet[0], length); p_gif->length += length; { int i; for (i = 0; i < length; ++i) { printf("%.2x ", packet[i]); } puts(""); } } /* Free encoder memory. */ free(hash_suffix); free(hash_prefix); free(hash_code); free(packet); return (1); /* TRUE */ }

Appendix B: Microblaze Implementation Sources


mb_tg.h : Microblaze TIFF to GIF header file listing mb_tg.c : Microblaze TIFF to GIF source file listing retiff.h : Re/TIFF header file listing retiff.c : Re/TIFF source file listing
/*

File: mb_tg.h Description : MicroBlaze (uB) TIFF to GIF header data definitions Compile line : Xilinx EDK 6.3 EDK_Gmm.12.3 Written by : JSC 12/02/06 */ #define TRUE 1 #define FALSE 0 /* UART data input */ volatile Xuint8 d_buf; /* single byte data buffer */ volatile Xuint8 d_flag; /* signals data received from UART */ /* LED : */ /* 6543210 */ #define LED_ZERO 0x01 // 0 = 0000001 = 1 = 0x01 #define LED_ONE 0x4f /* 1 = 1001111 = 79 = 0x4f */ #define LED_TWO 0x12 // 2 = 0010010 = 18 = 0x12 #define LED_THREE 0x06 // 3 = 0000110 = 6 = 0x06 #define LED_FOUR 0x4c // 4 = 1001100 = 76 = 0x4c #define LED_FIVE 0x24 // 5 = 0100100 = 36 = 0x24 #define LED_SIX 0x20 // 6 = 0100000 = 32 = 0x20 #define LED_SEVEN 0x0f // 7 = 0001111 = 15 = 0x0f #define LED_EIGHT 0x00 // 8 = 0000000 = 0 = 0x00 #define LED_NINE 0x04 // 9 = 0000100 = 4 = 0x04 /* 6543210 */ #define LED_A 0x08 // A = 0001000 = 8 = 0x08 #define LED_C 0x31 // C = 0110001 = 49 = 0x31 #define LED_E 0x30 // E = 0110000 = 48 = 0x30 #define LED_a 0x02 // a = 0000010 #define LED_b 0x60 // b = 1100000

#define LED_c 0x72 // c = 1110010 #define LED_d 0x42 // d = 1000010 #define LED_e 0x10 // e = 0010000 #define LED_f 0x38 // f = 0111000 #define LED_SEG_ZERO 0x7f #define LED_SEG_ONE 0x7f - 0x01 #define LED_SEG_TWO 0x7f - 0x02 #define LED_SEG_THREE 0x7f - 0x04 #define LED_SEG_FOUR 0x7f - 0x08 #define LED_SEG_FIVE 0x7f - 0x10 #define LED_SEG_SIX 0x7f - 0x20 #define LED_SEG_SEVEN 0x7f - 0x40 #define CR 0x0d /* carriage return */ #define NL 0x0a /* new line (text mode) */ #define PAUSE(LEN) \ { \ int l; \ for (l=0; l < LEN; ++l) { \ /* wait */; \ } \ } #define UPDATE_LED(led, led_state) \ switch (led) { \ case 0: \ led++; led_state = LED_SEG_ZERO; break; \ case 1: \ led++; led_state = LED_SEG_ONE; break; \ case 2: \ led++; led_state = LED_SEG_TWO; break; \ case 3: \

led++; led_state = LED_SEG_THREE; break; \ case 4: \ led++; led_state = LED_SEG_FOUR; break; \ case 5: \ led++; led_state = LED_SEG_FIVE; break; \ case 6: \ led++; led_state = LED_SEG_SIX; break; \ default: \ led = 0; led_state = LED_SEG_SEVEN; break; \ } \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, led_state) #define LED_PRINT(val) \ switch (0x0f & val) { \ case 0: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_ZERO); \ break; \ case 1: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_ONE); \ break; \ case 2: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_TWO); \ break; \ case 3: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_THREE); \ break; \ case 4: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_FOUR); \ break; \ case 5: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_FIVE); \

break; \ case 6: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_SIX); \ break; \ case 7: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_SEVEN); \ break; \ case 8: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_EIGHT); \ break; \ case 9: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_NINE); \ break; \ case 0xa: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_a); \ break; \ case 0xb: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_b); \ break; \ case 0xc: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_c); \ break; \ case 0xd: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_d); \ break; \ case 0xe: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_e); \ break; \ case 0xf: \ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_f); \

} /* image dimensions */ #define X_SIZE 4 /* read from UART */ #define Y_SIZE 4 #define XY_SIZE 8 Xuint8 x_buf[4] = { 0, 0, 0, 0}; Xuint8 y_buf[4] = { 0, 0, 0, 0}; Xuint32 x_dim = 0; Xuint32 y_dim = 0; /* dc = dimension component (x or y) */ /* dc_buf = dc buffer for storing unsigned byte tuples * byte order is little endian */ /* dim_size = iterator counter (X_SIZE or Y_SIZE) */ #define GET_IMG_DIM(DC, DC_BUF, DIM_SIZE) \ for (zd_flag = 0; zd_flag < DIM_SIZE; ++zd_flag) { \ while (!d_flag); /* wait for data i/o */ \ d_flag = FALSE; /* lower flag */ \ \ /* capture image size */ \ DC_BUF[zd_flag] = d_buf; \ } \ DC = \ DC_BUF[0] + \ (DC_BUF[1] << 8) + \ (DC_BUF[2] << 16) + \ (DC_BUF[3] << 24); /* Q: Where does the number 5003 come from? A: When LZW max codeword size is 12 bits, aka the value spec by "MaxGIFBits" constant, then...

5003 = 2^12 + 2^12 * 20%, stepped up to nearest prime number for optimal hash table size */ #define MaxHashTable /* 5003 */ /* 2459 */ /* 1229 */ 617 /* fits! */ #define MaxGIFBits /* 12UL */ /* 11UL */ /* 10UL */ 9UL /* fits! */ #define MaxGIFTable ( 1UL << MaxGIFBits ) #define MaxCode(number_bits) (( 1UL << ( number_bits ))-1) #define LZW_CODE_BIT_SIZE 9 /* fr. EncodeImage, sets max LZW codeword size */ Xint16 hash_code[MaxHashTable] = { /* 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 11 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 12 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 13 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 14 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 15 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 17 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 18 */

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 19 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 21 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 22 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 23 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 25 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 26 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 27 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 28 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 29 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 31 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 33 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 34 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 35 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 37 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 38 */ 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 */ }; Xint16 hash_prefix[MaxHashTable] = { /* 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 11 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 12 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 13 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 14 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 15 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 17 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 18 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 19 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 21 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 22 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 23 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 25 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 26 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 27 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 28 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 29 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 31 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32 */

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 33 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 34 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 35 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 37 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 38 */ 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 */ }; Xuint8 hash_suffix[MaxHashTable] = { /* 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 11 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 12 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 13 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 14 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 15 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 */

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 17 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 18 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 19 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 21 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 22 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 23 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 25 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 26 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 27 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 28 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 29 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 31 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 33 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 34 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 35 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 37 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 38 */ 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 */ }; #define GIFOutputCode(code) { \ /* \ Emit a code. \ */ \

if (bits > 0) \ datum |= (code) << bits; \ else \ datum=code; \ bits+=number_bits; \ while (bits >= 8) { \ /* \ Add a character to current packet. \ */ \ XUartLite_SendByte \ (XPAR_RS232_BASEADDR, \ (datum & 0xff)); \ datum>>=8; \ bits-=8; \ } \ if (free_code > max_code) { \ number_bits++; \ if (number_bits == MaxGIFBits) \ max_code=MaxGIFTable; \ else \ max_code=MaxCode(number_bits); \ } \ } /* File: mb_tg.c Description : MicroBlaze (uB) TIFF to GIF UART interrupt data driven converter * These drivers will be generated in your * XPS project when you run the "Generate Libraries" menu item

* in XPS. * Your XPS project directory is at: * D:\design\memec_3slc_design3 Compile line : Xilinx EDK 6.3 EDK_Gmm.12.3 Written by : JSC 12/02/06 12/13/06 Updated to incorporate LZW */ #include <xuartlite_l.h> /* uartlite peripheral control functions */ #include <xintc_l.h> /* interrupt controller peripheral control functions */ // Located in: microblaze_0/include/xparameters.h #include "xparameters.h" #include "xutil.h" #include "xgpio_l.h" #include "mb_tg.h" void uart_int_handler(void *baseaddr_p) { /* While UART receive FIFO has data */ while (!XUartLite_mIsReceiveEmpty(baseaddr_p)) { /* Read character (s) */ d_flag = TRUE; d_buf = XUartLite_RecvByte((Xuint32) baseaddr_p); } } /* * Routine to write a pattern out to a GPIO * which is configured as an output * PARAMETER C_ALL_INPUTS = 0 */ void WriteToGPOutput(Xuint32 BaseAddress, int gpio_width) { int i=0, j=0, k=0; int numTimes = 5;

XGpio_mSetDataDirection(BaseAddress, 1, 0x00000000); /* Set as outputs */ while (numTimes > 0) { j = 1; for(i=0; i<(gpio_width-1); i++) { XGpio_mSetDataReg(BaseAddress, 1, j); j = j << 1; for (k=0; k<100000; k++) { ; //wait } } j = 1; j = ~j; for(i=0; i<(gpio_width-1); i++) { XGpio_mSetDataReg(BaseAddress, 1, j); j = j << 1; for (k=0; k<100000; k++) { ; //wait } } numTimes--; } } /* * Routine to read data from a GPIO * which is configured as an input * PARAMETER C_ALL_INPUTS = 1 */ Xuint32 ReadFromGPInput(Xuint32 BaseAddress) { Xuint32 data = XGpio_mGetDataReg(BaseAddress, 1); return data;

} //==================================================== int main (void) { Xuint8 /* unsigned 8-bit */ i, index; Xint16 /* signed short */ waiting_code; Xint32 /* long */ displacement, k; Xuint32 /* unsigned long */ x, y; Xuint32 /* unsigned long */ bits, clear_code, datum, end_of_information_code, free_code, max_code, next_pixel, number_bits; Xint8 led, led_state; Xuint8 zd_flag; /* zero data flag */ /* Initialize LZW encoder. */ for (k=0; k < MaxHashTable; k++) {

hash_code[k]=0; hash_prefix[k]=0; hash_suffix[k]=0; } number_bits = /* data_size */ LZW_CODE_BIT_SIZE; max_code = MaxCode(number_bits); clear_code = ((Xint16) 1UL << (/* data_size */ LZW_CODE_BIT_SIZE - 1)); end_of_information_code = clear_code + 1; free_code = clear_code+2; datum = 0; bits = 0; waiting_code = 0; index = 0; /* image data value */ /* interrupt state initialization */ led = 0; zd_flag = 0; /* zero data flag used to determine when to set prefix */ d_flag = FALSE; d_buf = 0; /* Sets up interrupts */ XGpio_mSetDataDirection(XPAR_LED_7SEGMENT_BASEADDR, 1, 0x0); XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_ONE); microblaze_enable_interrupts(); XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_TWO); /* Register UART interrupt handler */ XIntc_RegisterHandler ( XPAR_OPB_INTC_0_BASEADDR, XPAR_OPB_INTC_0_RS232_INTERRUPT_INTR, (XInterruptHandler) uart_int_handler, (void *) XPAR_RS232_BASEADDR);

/* Register External interrupt handler */ XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_THREE); XIntc_mMasterEnable(XPAR_OPB_INTC_0_BASEADDR); XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_FOUR); XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_FIVE); XIntc_mEnableIntr(XPAR_OPB_INTC_0_BASEADDR, XPAR_RS232_INTERRUPT_MASK); XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_SIX); XUartLite_mEnableIntr(XPAR_RS232_BASEADDR); //XUartLite_ResetFifos(XPAR_RS232_BASEADDR); XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_THREE); GET_IMG_DIM(y_dim, y_buf, Y_SIZE); UPDATE_LED(led, led_state); GIFOutputCode(clear_code); for (y = 0; y < y_dim; ++y) { GET_IMG_DIM(x_dim, x_buf, X_SIZE); if (y == 0) { /* * LZW algo: Initialize table to contain single-char strings. * Read first input char -- prefix string w (omega) * w == waiting_code aka "prefix" */ while (!d_flag); /* wait for data i/o */ d_flag = FALSE; /* lower flag */ /* assign waiting data */ waiting_code=(short) d_buf; } for (x=((y == 0) ? 1 : 0); x < x_dim; ++x) { while (!d_flag); /* wait for data i/o */ d_flag = FALSE; /* lower flag */ /* assign waiting data */

index = d_buf; /* Probe hash table. */ /* * LZW algo (continued) * Step: Read next input character k * if no such k (input exhausted): code(w) -> output : EXIT * if wk exists in string table: wk -> w; repeat Step * else wk not in string table : code(w) -> output; * wk -> string table; * k -> w; repeat Step */ k=(long) (index << (MaxGIFBits-8))+waiting_code; if (k >= MaxHashTable) k-=MaxHashTable; next_pixel=0; /* MagickFalse; */ displacement=1; /* if wk exists in string table ? */ if (hash_code[k] > 0) { if ((hash_prefix[k] == waiting_code) && (hash_suffix[k] == (unsigned char) index)) { /* yes -- repeat Step */ waiting_code=hash_code[k]; continue; } if (k != 0) displacement=MaxHashTable-k; for ( ; ; ) { k-=displacement;

if (k < 0) k+=MaxHashTable; if (hash_code[k] == 0) break; if ((hash_prefix[k] == waiting_code) && (hash_suffix[k] == (unsigned char) index)) { waiting_code=hash_code[k]; next_pixel=1; /* MagickTrue; */ break; } } if (next_pixel == 1) /* MagickTrue */ continue; } GIFOutputCode((unsigned long) waiting_code); if (free_code < MaxGIFTable) { hash_code[k]=(short) free_code++; hash_prefix[k]=waiting_code; hash_suffix[k]=(unsigned char) index; } else { /* Fill the hash table with empty entries. */ UPDATE_LED(led, led_state); for (k=0; k < MaxHashTable; k++) { hash_code[k]=0; } /* Reset compressor and issue a clear code. */

free_code=clear_code+2; GIFOutputCode(clear_code); number_bits= /* data_size */ LZW_CODE_BIT_SIZE; max_code=MaxCode(number_bits); } waiting_code=(short) index; } /* for (x...) */ } /* for (y...) */ END_OF_DATA: GIFOutputCode((unsigned long) waiting_code); GIFOutputCode(end_of_information_code); if (bits > 0) { /* Add a character to current packet. */ XUartLite_SendByte(XPAR_RS232_BASEADDR, (datum & 0xff)); } XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_ZERO); WriteToGPOutput(XPAR_LEDS_4BIT_BASEADDR, 4); WriteToGPOutput(XPAR_LED_7SEGMENT_BASEADDR, 7); XGpio_mSetDataReg(XPAR_LED_7SEGMENT_BASEADDR, 1, LED_ZERO); return 0; } /* File: retiff.h Description : Re-TIFF header data types Compile line : gcc -ansi -g -o retiff retiff.c Written by : JSC 11/29/06

Rev History : 01/04/07 JSC Updated for threaded FPGA LZW UART Tx/Rx data types and functions. */ #define UBYTE unsigned char /* 1 byte */ #define USHORT unsigned short /* 2 bytes */ #define ULONG unsigned long /* 4 bytes */ /* */ #define IFD_OFFSET_L 4L #define IFD_SIZE (UBYTE) 12 /* Used to reset offsets */ #define TAG_STRIPOFFSETS 273 #define TAG_COLORMAP 320 /* Used to re-align image data */ #define TAG_SAMPLESPERPIXEL 277 /* */ #define TAG_ROWSPERSTRIP 278 #define TAG_STRIPBYTECOUNTS 279 #define TAG_IMAGEWIDTH 256 /* cols */ #define TAG_IMAGELENGTH 257 /* rows */ #define TAG_BITSPERSAMPLE 258 /* */ #define BITSPERBYTE 8 /* Serial I/O COM */ #define BUF_SIZE 16 /* Serial I/O read buffer */ #define TIME_OUT 50 /* # times to check Rx buffer */ #define MAX_GIF_BLK_SIZE 0xff /* Max GIF image block size */ #define DIM_SIZE 4 /* Serial i/o writer */ /* Debug level */ int DEBUG = 0; /* For storing TIFF data and interpreting

the values */ typedef union _udata { UBYTE b_val[4]; USHORT s_val[2]; ULONG l_val; } udata; /* unsigned data */ /* Image File Directory Entries */ typedef struct _ifd { USHORT tag_id; USHORT type; UBYTE n[4]; udata vo; /* value offset */ } ifd; /* RAW image format */ typedef struct _retiff { USHORT height, width; USHORT bps; /* bits per sample */ ULONG size; /* # of rows in image data array, * in byte counts array, & * in strip offsets array */ ifd *p_cmh; /* color map header */ USHORT *p_cm; /* color map palette */ ULONG *p_bytecounts; /* array of size of strip data */

ULONG *p_stripoffsets; /* TIFF file data strip offsets */ UBYTE **p_imagedata; /* [rows][columns] */ /* image data */ } retiff; typedef struct _lzwGIF { unsigned int height, width; unsigned int size; /* malloc size */ unsigned int length; /* used size (non-free)*/ unsigned char *data; /* compressed data */ unsigned int cm_size; /* color map size */ unsigned char *cm; /* color map */ } lzwGIF; int fd; /* global file desciptor */ void serial_open(char *device); /* serial com i/o aka Tx/Rx */ void* serial_write(void *ptr); /* threaded writer Tx */ int EncodeImage(retiff *p_retiff, lzwGIF *p_gif, const unsigned long data_size); /* File: retiff.c Description : Reads an input TIFF so that the Image File Directory (IFD) entries are ordered first and the bitmap data last. Added threaded serial I/O. Parts derived from tsl.c, whose header is also included. Creates a GIF output. Compile line : gcc -ansi -g -o retiff retiff.c Written by : JSC 11/23/06 01/03/07 Added Multi-threaded, and FPGA Tx/Rx 12/13/06 Added FPGA UART Serial I/O. Moved LZW into FPGA. */

/* $Id: tsl.c,v 1.12 2004/01/26 06:58:50 james Exp james $ tsl, temperature sensor data logger Copyright (C) 2000 James Cameron (quozl@us.netrek.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <assert.h> #include <termios.h> #include <fcntl.h> #include <pthread.h> #include "retiff.h" int main(int argc, char *argv[]) { FILE *fh; UBYTE ifd_size; int i, j; udata *p_dat; ifd **p_ifd;

unsigned int rows; unsigned int cols; unsigned int size; /* measured in bytes */ udata ssize; /* byte counts */ unsigned int bc_index; /* output */ ULONG s_offset; ULONG cm_offset; retiff *p_retiff; lzwGIF *p_gif; if (argc < 3) { printf("Usage: %s <in.tiff> <out.gif> [DEBUG]\n\n", argv[0]); puts("\tRewrites input TIFF IFD entries to top of file.\n"); exit(-1); } if (argc == 4) { DEBUG = 1; } else { DEBUG = 0; } p_dat = (udata *) calloc(1, sizeof(udata)); fh = fopen(argv[1], "rb"); fseek(fh, IFD_OFFSET_L, SEEK_CUR); /* assume little-endian */ /* Read in IFD offset val */ fread(&p_dat->b_val[0], 4*sizeof(UBYTE), 1, fh); if (DEBUG) printf("IFD offset %x\n", p_dat->l_val); /* Seek forward to IFD entries */ fseek(fh, (long) p_dat->l_val, SEEK_SET);

/* Read number of IFD entries value */ fread(&p_dat->b_val[0], 2*sizeof(UBYTE), 1, fh); if (DEBUG) printf("IFD records %d\n", p_dat->s_val[0]); /* allocate ifd structure */ ifd_size = p_dat->s_val[0]; p_ifd = (ifd **) calloc(ifd_size, sizeof(ifd*)); for (i=0; i < ifd_size; ++i) { p_ifd[i] = (ifd *) calloc(1, sizeof(ifd)); } p_retiff = (retiff *) calloc(1, sizeof(retiff)); /* using calloc to initialize members to 0's */ p_gif = (lzwGIF *) calloc(1, sizeof(lzwGIF)); for (i=0; i < ifd_size && !feof(fh); ++i) { fpos_t pos; fgetpos(fh, &pos); if (DEBUG) printf("%x\t", pos); if (!fread(p_ifd[i], sizeof(ifd), 1, fh)) { break; } if (DEBUG) printf("Tag 0x%.4x (%d) \tType %x\n", p_ifd[i]->tag_id, p_ifd[i]->tag_id, p_ifd[i]->type); switch (p_ifd[i]->tag_id) { case TAG_ROWSPERSTRIP : { if (DEBUG) printf("\trows per strip %d\n", p_ifd[i]->vo.l_val); break; } case TAG_IMAGEWIDTH : {

cols = p_ifd[i]->vo.l_val; p_gif->width = p_ifd[i]->vo.l_val; if (DEBUG) printf("\tcols %d\n", cols); break; } case TAG_IMAGELENGTH : { rows = p_ifd[i]->vo.l_val; p_gif->height = (unsigned short) p_ifd[i]->vo.l_val; if (DEBUG) printf("\trows %d\n", rows); break; } case TAG_BITSPERSAMPLE : { size = (rows * cols * p_ifd[i]->vo.l_val) / BITSPERBYTE; p_retiff->bps = p_ifd[i]->vo.s_val[0]; /* higher order bits assumed to be 0 based on TIFF spec and sample file */ if (DEBUG) { printf("\tbps %d\n", p_ifd[i]->vo.l_val); printf("\tsize %d from row x cols\n", size); } break; } case TAG_STRIPOFFSETS : { ssize.b_val[0] = p_ifd[i]->n[0]; ssize.b_val[1] = p_ifd[i]->n[1]; ssize.b_val[2] = p_ifd[i]->n[2]; ssize.b_val[3] = p_ifd[i]->n[3]; s_offset = p_ifd[i]->vo.l_val; if (DEBUG) {

printf("\tstrip count %d\n", ssize.l_val); printf("\tstrip offset %d\n", s_offset); } break; } case TAG_STRIPBYTECOUNTS : { bc_index = i; if (DEBUG) printf("\tstrip byte counts 0x%.4x\n", p_ifd[i]->vo.l_val); break; } case TAG_COLORMAP : { udata csize; cm_offset = p_ifd[i]->vo.l_val; csize.b_val[0] = p_ifd[i]->n[0]; csize.b_val[1] = p_ifd[i]->n[1]; csize.b_val[2] = p_ifd[i]->n[2]; csize.b_val[3] = p_ifd[i]->n[3]; if (DEBUG) { printf("\tcolormap size %d\n", csize.l_val); printf("\tcolormap offset %d\n", cm_offset); } /* assumption is 256 RGB tuplets */ /* assign color map structure */ p_retiff->p_cmh = p_ifd[i]; p_retiff->p_cm = (USHORT *) calloc(csize.l_val, sizeof(USHORT)); /* read color map data */ fseek(fh, (long) p_ifd[i]->vo.l_val, SEEK_SET); fread(p_retiff->p_cm, sizeof(USHORT), csize.l_val, fh); /* transfer to GIF */

p_gif->cm_size = csize.l_val; p_gif->cm = (unsigned char *) calloc(csize.l_val, sizeof(unsigned char)); for (i=0, j=0; i < p_gif->cm_size-2; ++j) { p_gif->cm[i] = (UBYTE) p_retiff->p_cm[j]; /* Red */ p_gif->cm[i+1] = (UBYTE) p_retiff->p_cm[j + 256]; /* Green */ p_gif->cm[i+2] = (UBYTE) p_retiff->p_cm[j + 512]; /* Blue */ i = i + 3; } break; } } } fflush(stdout); /* Save/Print out the byte count values */ { unsigned int *p_offsets = NULL; udata size; memcpy(&size, p_ifd[bc_index]->n, sizeof(ULONG)); p_offsets = (unsigned int *) calloc(size.l_val, sizeof(unsigned int)); /* seek forward to the byte counts */ fseek(fh, (long) p_ifd[bc_index]->vo.l_val, SEEK_SET); fread(p_offsets, sizeof(unsigned int), size.l_val, fh); if (DEBUG) puts("\nStrip byte sizes:"); p_retiff->size = size.l_val; p_retiff->p_bytecounts = (ULONG *) calloc(size.l_val, sizeof(ULONG)); p_gif->size = 0; for (i=0; i < size.l_val; ++i) {

if (DEBUG) printf("\toffset %d byte size %d\n", i, p_offsets[i]); p_retiff->p_bytecounts[i] = p_offsets[i]; p_gif->size += p_offsets[i]; } if (DEBUG) printf("\tTIFF image size %d from byte counts\n",p_gif->size); free(p_offsets); } /* Save/print out the strip offsets */ { unsigned int *p_offsets = NULL; p_offsets = (unsigned int *) calloc(ssize.l_val, sizeof(unsigned int)); p_retiff->p_stripoffsets = (ULONG *) calloc(ssize.l_val, sizeof(ULONG)); fseek(fh, (long) s_offset, SEEK_SET); fread(p_offsets, sizeof(unsigned int), ssize.l_val, fh); if (DEBUG) puts("\nStrip offsets:"); for (i=0; i < ssize.l_val; ++i) { p_retiff->p_stripoffsets[i] = p_offsets[i]; if (DEBUG) printf("\toffset %d is %x\n", i, p_offsets[i]); } free(p_offsets); p_offsets=NULL; } /* * Read image data into retiff data struct

*/ { int b_read; /* bytes read */ p_retiff->p_imagedata = (UBYTE **) calloc(p_retiff->size, sizeof(UBYTE *)); if (DEBUG) puts("\nRead image data"); for (i=0; i < p_retiff->size; ++i) { b_read = 0; p_retiff->p_imagedata[i] = (UBYTE *) calloc(p_retiff->p_bytecounts[i], sizeof(UBYTE)); fseek(fh, (long) p_retiff->p_stripoffsets[i], SEEK_SET); b_read = fread(p_retiff->p_imagedata[i], sizeof(UBYTE), p_retiff->p_bytecounts[i], fh); if (feof(fh)) { if (DEBUG) puts("End of file encountered"); } if (DEBUG) printf("%d.\tRead %.4x bytes of %.4x byte counts, offset %.6x\n", i, b_read, p_retiff->p_bytecounts[i], p_retiff->p_stripoffsets[i]); } } /* * LZW Compress to GIF structure */ { /* thread */ int iret; pthread_t pth_uart_wrtr; /* fpga data uart writer thread */ /* com serial i/o */ char *device = "/dev/ttyS10"; /* for UNIX build */ int j; /* data uart i/o time counter */

int retval; unsigned char rdr_buf[BUF_SIZE]; unsigned char *p_wtr_buf; unsigned int wrt_buf_sz; int i; /* LZW data copy counter */ int quot, rmdr; /* To create valid GIF image data blocks */ /* set up thread data & com i/o */ p_wtr_buf = (unsigned char *) calloc(p_gif->size, sizeof (unsigned char)); serial_open(device); /* spawing thread invokes EncodeImage */ /* EncodeImage(p_retiff, p_gif, 9); */ iret = pthread_create( &pth_uart_wrtr, NULL, serial_write, (void *) p_retiff); pthread_detach( pth_uart_wrtr ); /* data is writing to UART */ if ( DEBUG ) puts("\nReceiving LZW data..."); for (j = 0, p_gif->length = 0; j < TIME_OUT ; ++j ) { retval = read(fd, &rdr_buf[0], BUF_SIZE); if (retval == -1) { /* no data this cycle */ /* time out counter increment */ continue; } for (i = 0; i < retval; ++i) { p_wtr_buf[p_gif->length++] = rdr_buf[i]; if (DEBUG) { printf("%.2x ", rdr_buf[i]); } } j = 0; }

if (DEBUG) printf("\nReceived 0x%.4x bytes.\n", p_gif->length); /* add size sentinals */ wrt_buf_sz = p_gif->length; quot = p_gif->length / MAX_GIF_BLK_SIZE; /* integer quotent after division */ rmdr = p_gif->length % MAX_GIF_BLK_SIZE; /* remainder after division */ p_gif->length = p_gif->length + quot + ((rmdr == 0) ? 0 : 1); /* extend gif data size */ if (DEBUG) { printf("div %d, rmdr %d\n", quot, rmdr); } /* copy LZW data into GIF image blocks */ p_gif->data = (unsigned char *) calloc(p_gif->length, sizeof (unsigned char)); for (i = 0, j = 0; i < quot + ((rmdr + quot) / MAX_GIF_BLK_SIZE); ++i) { p_gif->data[j++] = MAX_GIF_BLK_SIZE - 1; memcpy ( &p_gif->data[j], &p_wtr_buf[i * (MAX_GIF_BLK_SIZE - 1)], (MAX_GIF_BLK_SIZE - 1)); j += MAX_GIF_BLK_SIZE - 1; } { int rmdr2; rmdr2 = (rmdr + quot) % MAX_GIF_BLK_SIZE; if (DEBUG) printf("rmdr2 %d\n",rmdr2); p_gif->data[j++] = rmdr2; memcpy ( &p_gif->data[j],

&p_wtr_buf[(quot + ((rmdr + quot) / MAX_GIF_BLK_SIZE)) * (MAX_GIF_BLK_SIZE-1)], rmdr2); } free(p_wtr_buf); if (DEBUG) printf("\n%x bytes of %x bytes compressed\n", p_gif->length, p_gif->size); close(fd); /* op delayed in case uart_wrtr is still working */ } /* * Write the GIF file */ { unsigned char buf[256]; FILE *fh_gif; fh_gif = fopen(argv[2], "wb"); /* Header */ sprintf(buf, "%s", "GIF89a"); fwrite(buf, sizeof(unsigned char), 6, fh_gif); /* Logical Screen Descriptor */ fwrite(&p_gif->width, sizeof(unsigned short), 1, fh_gif); fwrite(&p_gif->height, sizeof(unsigned short), 1, fh_gif); buf[0]=0xf7; /* packed field */ fwrite(buf, sizeof(unsigned char), 1, fh_gif); buf[0]=0x00; /* background color index */ fwrite(buf, sizeof(unsigned char), 1, fh_gif); buf[0]=0x00; /* pixel aspect ratio */ fwrite(buf, sizeof(unsigned char), 1, fh_gif); /* Global Color Table */ fflush(fh_gif); fwrite(p_gif->cm, sizeof(unsigned char), p_gif->cm_size, fh_gif);

fflush(fh_gif); /* Image Descriptor */ buf[0]=0x2c; /* Image Separator */ fwrite(buf, sizeof(unsigned char), 1, fh_gif); fflush(fh_gif); buf[0]=0x00; /* Image Left Position */ buf[1]=0x00; fwrite(buf, sizeof(unsigned char), 2, fh_gif); buf[0]=0x00; /* Image Top Position */ buf[1]=0x00; fwrite(buf, sizeof(unsigned char), 2, fh_gif); fwrite(&p_gif->width, sizeof(unsigned short), 1, fh_gif); fwrite(&p_gif->height, sizeof(unsigned short), 1, fh_gif); buf[0]=0x00; /* Packed Fields */ fwrite(buf, sizeof(unsigned char), 1, fh_gif); /* Table Based Image Data */ buf[0]=0x08; /* LZW Minimum Code Size */ fwrite(buf, sizeof(unsigned char), 1, fh_gif); /* Image Data */ { unsigned char *p_data; p_data = &p_gif->data[0]; for (i=0 ; i < p_gif->length ; ++i) { fwrite(p_data++, sizeof(unsigned char), 1, fh_gif); fflush(fh_gif); } } /* Trailers */ buf[0] = 0x00; buf[1] = 0x3b;

fwrite(buf, sizeof(unsigned char), 2, fh_gif); fflush(fh_gif); fclose(fh_gif); fh_gif = NULL; } /* free memory used */ if (p_retiff->p_cm != NULL) { free(p_retiff->p_cm); p_retiff->p_cm = NULL; } if (p_retiff->p_bytecounts != NULL) { free(p_retiff->p_bytecounts); p_retiff->p_bytecounts = NULL; } if (p_retiff->p_stripoffsets != NULL) { free(p_retiff->p_stripoffsets); p_retiff->p_stripoffsets = NULL; } if (p_retiff->p_imagedata != NULL) { for (i=0; i<p_retiff->size; i++) { if (p_retiff->p_imagedata[i] != NULL) { free(p_retiff->p_imagedata[i]); p_retiff->p_imagedata[i] = NULL; } } free(p_retiff->p_imagedata); p_retiff->p_imagedata = NULL; } free(p_retiff); p_retiff = NULL;

if (p_gif->cm != NULL) { free(p_gif->cm); p_gif->cm = NULL; } { /* free gif lzw data */ if (p_gif->data != NULL) { free(p_gif->data); p_gif->data = NULL; } } free(p_gif); p_gif = NULL; for (j=0; j < ifd_size; ++j) { free(p_ifd[j]); p_ifd[j] = NULL; } free(p_ifd); p_ifd=NULL; fclose(fh); fh=NULL; free(p_dat); p_dat = NULL; if ( DEBUG ) puts("Done."); exit(0); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % E n c o d e I m a g e %

% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % EncodeImage LZW compresses an image via GIF-coding. % % The format of the EncodeImage method is: % % int EncodeImage( % retiff *p_retiff, % lzwGIF *p_gif, % const unsigned long data_size) % % A description of each parameter follows: % % o p_retiff: The address of a structure defining the image data. % % o p_gif: output gif image block % % o data_size: The number of bits in the compressed packet. % % Comments: % % JSC 01/03/07 Updated to send to FPGA via UART where LZW byte % stream is Tx/Rx % JSC 10/28/06 Modified from ImageMagick-6.2.8 coders/gif.c and adapted % for Re-TIFFing % */ int EncodeImage(retiff *p_retiff, lzwGIF *p_gif, const unsigned long data_size) { int x, y, i, retval;

union _sz { unsigned char b_size[4]; unsigned long l_size; } img = {0, 0, 0, 0}; #define DIM_SIZE 4 /* write y dimension */ img.l_size = (unsigned long) p_retiff->size; retval = write(fd, &img.b_size[0], DIM_SIZE); for (y = 0, i = 0; y < (long) p_retiff->size; y++) { /* write x dimension */ img.l_size = (unsigned long) p_retiff->p_bytecounts[y]; retval = write(fd, &img.b_size[0], DIM_SIZE); for (x=0; x < (long) p_retiff->p_bytecounts[y]; x++) { /* index=p_retiff->p_imagedata[y][x] & 0xff; */ /* img data val */ retval = write(fd, &p_retiff->p_imagedata[y][x], 1); } if (DEBUG) printf("\n%d. wrote 0x%.4x bytes\n", y + 1, img.l_size); i += img.l_size; } if (DEBUG) printf("\nEncodeImage exit. Wrote 0x%.4x bytes\n", i); } void* serial_write(void *ptr) { EncodeImage( (retiff *)ptr, NULL, 0); } void serial_open(char *device) { struct termios termios; fd = open(device, O_RDWR | O_NONBLOCK);

/* set the serial port characteristics */ if (tcgetattr(fd, &termios) < 0) { perror("tcgetattr"); exit(1); } if (cfsetospeed(&termios, B115200) < 0) { perror("cfsetospeed"); exit(1); } if (cfsetispeed(&termios, B115200) < 0) { perror("cfsetispeed"); exit(1); } // // c_cflag termios CS8 = 8 bits // termios.c_cflag = CS8 | CSTOPB; if (tcsetattr(fd, TCSANOW, &termios) < 0) { perror("tcsetattr"); exit(1); }

1 See http://www.em.avnet.com 2 TIFF. Revision 6.0 Final June 3, 1992. Adobe Developers Association. 3 spec-gif89a.txt 4 Platform Specification Format Reference Manual. Embedded Development Kit EDK 6.3i. UG131 (v1.0) August 20, 2004, pp 21. 5 Memec 3SLC MicroBlaze Hello World Reference Design. December 1, 2004 Version 6.3.d 6 Xilinx Spartan-3 FPGA Family: Introduction and Ordering Information. DS099-1 (v1.4) January 17, 2005.

Vous aimerez peut-être aussi