tiff to gif converter & lzw compression algorithm fpga implementation.pdf
DESCRIPTION
Uploaded from Google DocsTRANSCRIPT
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 .................................................................................................................................................. 3Development Platform Configuration .................................................................................................. 3
TIFF to GIF Conversion ........................................................................................................................... 4Reference TIFF to GIF Converter Design ............................................................................................4TIFF File Format2 ................................................................................................................................ 4GIF File Format ....................................................................................................................................4
Embedded LZW ........................................................................................................................................ 8Device Driver ...................................................................................................................................9DataFlow: ........................................................................................................................................ 9malloc/xil_malloc .......................................................................................................................... 11EDK Debugger .............................................................................................................................. 13
Fast Simplex Link ................................................................................................................................... 13LZW Compression Algorithm..................................................................................................................13Appendix A: Stand Alone Re/TIFF Sources ........................................................................................... 14Appendix 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 5c 9c 53 cb 5a f5 f8 f2 c3 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 55 16 57 37 7e 05 7c 18 31 60 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 b3 38 57 90 5d 91 19 a3 89 0d 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 80 83 87 8e fc d4 e8 64 15 64 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 1e e7 0a 17 32 6c e8 f0 21 c4 88 12 17 c6 80 91 c2 84 09 12 26 4e a4 48 a1 62 05 0b 18 2f 26 4a cc 18 21 82 04 0a 16 32 54 10 38 e1 41 04 0a 19 32 5c c0 b0 21 03 07 0e 24 77 f2 ec c9 d3 85 8b 13 27 36 ae f8 18 63 a4 4f 87 2c 48 6c 38 b9 92 c3 87 0f 19 2c 50 a8 80 61 e6 06 a8 22 3e ac 48 ea f5 6b d2 17 2e 5e 90 85 11 03 ac c3 0f 24 38 08 dc e0 f6 e6 4c 9c 1c b2 72 20 41 02 21 da bc 7a f7 f6 5c 7a 22 ea cc 0b 71 39 64 a0 ab 96 c4 89 b3 7c 17 33 6e 4c 83 05 0a 15 76 37 54 10 9c 33 67 54 c4 27 60 38 ee ec 19 ac 8b 8e 29 a2 42 1d 41 22 aa 08 8c 2c 14 7f 6e ed 7a 22 d9 14 1c 3f 60 14 8a 51 c5 0b d6 af 77 f3 66 28 b6 e3 c7 e0 64 7b 13 2f ae 70 ac c8 e4 c6 97 33 6f ee fc 39 f4 e8 d2 a7 53 5f 1e 10
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 HW Ver Instance
microblaze 3.00.a Microblaze_0
opb_mdm 2.00.a debug_module
lmb_bram_if_cntlr 1.00.b dlmb_cntlr
lmb_bram_if_cntlr 1.00.b ilmb_cntlr
bram_block 1.00.a lmb_bram
opb_uartlite 1.00.b RS232
opb_gpio 3.01.b LEDs_4Bit
opb_gpio 3.01.b LED_7Segment
opb_gpio 3.01.b Push_Buttons_1Bit
opb_gpio 3.01.b DIP_Switches_4Bit
opb_intc 1.00.c 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 AlgorithmTerry 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 ([email protected])
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.