From 08c88e85d2eb110594511cc8f439dc94015efee1 Mon Sep 17 00:00:00 2001 From: Harald Oehlmann Date: Thu, 28 Jul 2016 20:58:33 +0200 Subject: [PATCH] Added gif output --- backend/CMakeLists.txt | 2 +- backend/gif.c | 509 ++++++++++++++++++++ backend/library.c | 6 + backend/raster.c | 4 + backend_qt4/backend_qt4.pro | 1 + win32/zint_cmdline_vc6/zint_cmdline_vc6.dsp | 6 +- 6 files changed, 526 insertions(+), 2 deletions(-) create mode 100644 backend/gif.c diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt index 191d50bf..79f25625 100644 --- a/backend/CMakeLists.txt +++ b/backend/CMakeLists.txt @@ -8,7 +8,7 @@ set(zint_COMMON_SRCS common.c library.c render.c large.c reedsol.c gs1.c) set(zint_ONEDIM_SRCS code.c code128.c 2of5.c upcean.c telepen.c medical.c plessey.c rss.c) set(zint_POSTAL_SRCS postal.c auspost.c imail.c) set(zint_TWODIM_SRCS code16k.c dmatrix.c pdf417.c qr.c maxicode.c composite.c aztec.c code49.c code1.c gridmtx.c hanxin.c) -set(zint_OUTPUT_SRCS render.c ps.c svg.c bmp.c pcx.c png.c raster.c) +set(zint_OUTPUT_SRCS render.c ps.c svg.c bmp.c pcx.c gif.c png.c raster.c) set(zint_SRCS ${zint_OUTPUT_SRCS} ${zint_COMMON_SRCS} ${zint_ONEDIM_SRCS} ${zint_POSTAL_SRCS} ${zint_TWODIM_SRCS}) if(PNG_FOUND) diff --git a/backend/gif.c b/backend/gif.c new file mode 100644 index 00000000..7ebd43d6 --- /dev/null +++ b/backend/gif.c @@ -0,0 +1,509 @@ +/* gif.c - Handles output to gif file */ + +/* + libzint - the open source barcode library + Copyright (C) 2009-2016 Robin Stuart + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + */ + +#include +#include +#include +#include "common.h" +#include "pcx.h" /* PCX header structure */ +#include +#ifdef _MSC_VER +#include +#include +#endif + +#define SSET "0123456789ABCDEF" + +/* Index of transparent color, -1 for no transparent color + * This might be set into a variable if transparency is activated as an option + */ +#define TRANSPARENT_INDEX (-1) + +/* Used bit depth, may be changed for bigger pallet in future */ +#define DESTINATION_IMAGE_BITS 1 +#include + +typedef struct s_statestruct { + unsigned char * pOut; + unsigned char *pIn; + unsigned int InLen; + unsigned int OutLength; + unsigned int OutPosCur; + unsigned int OutByteCountPos; + unsigned short ClearCode; + unsigned short FreeCode; + char fByteCountByteSet; + unsigned char OutBitsFree; + unsigned short NodeAxon[4096]; + unsigned short NodeNext[4096]; + unsigned char NodePix[4096]; +} statestruct; + +static char BufferNextByte(statestruct *pState) +{ + (pState->OutPosCur)++; + /* Check if this position is a byte count position + * fg_f_bytecountbyte_set indicates, if byte count position bytes should be + * inserted in general. + * If this is true, and the distance to the last byte count position is 256 + * (e.g. 255 bytes in between), a byte count byte is inserted, and the value + * of the last one is set to 255. + * */ + if ( pState->fByteCountByteSet && ( pState->OutByteCountPos + 256 == pState->OutPosCur ) ) + { + (pState->pOut)[pState->OutByteCountPos] = 255; + pState->OutByteCountPos = pState->OutPosCur; + (pState->OutPosCur)++; + } + if ( pState->OutPosCur >= pState->OutLength ) + return 1; + (pState->pOut)[pState->OutPosCur]=0x00; + return 0; +} + +static char AddCodeToBuffer(statestruct *pState, unsigned short CodeIn,unsigned char CodeBits) +{ + /* Check, if we may fill up the current byte completely */ + if (CodeBits >= pState->OutBitsFree) + { + (pState->pOut)[pState->OutPosCur] |= (unsigned char) + ( CodeIn << ( 8 - pState->OutBitsFree ) ); + if ( BufferNextByte(pState) ) + return -1; + CodeIn = (unsigned short) ( CodeIn >> pState->OutBitsFree ); + CodeBits -= pState->OutBitsFree; + pState->OutBitsFree = 8; + /* Write a full byte if there are at least 8 code bits left */ + if (CodeBits >= pState->OutBitsFree) + { + (pState->pOut)[pState->OutPosCur] = (unsigned char) CodeIn; + if ( BufferNextByte(pState) ) + return -1; + CodeIn = (unsigned short) ( CodeIn >> 8 ); + CodeBits -= 8; + } + } + /* The remaining bits of CodeIn fit in the current byte. */ + if( CodeBits > 0 ) + { + (pState->pOut)[pState->OutPosCur] |= (unsigned char) + ( CodeIn << ( 8 - pState->OutBitsFree ) ); + pState->OutBitsFree -= CodeBits; + } + return 0; +} + +static void FlushStringTable(statestruct *pState) +{ + unsigned short Pos; + for( Pos = 0; Pos < pState->ClearCode; Pos++ ) + { + (pState->NodeAxon)[Pos] = 0; + } +} + + +unsigned short FindPixelOutlet( statestruct *pState, unsigned short HeadNode, unsigned char Byte ) +{ + unsigned short Outlet; + + Outlet = (pState->NodeAxon)[HeadNode]; + while( Outlet ) + { + if ( (pState->NodePix)[Outlet] == Byte ) + return Outlet; + Outlet = (pState->NodeNext)[Outlet]; + } + return 0; +} + +static char NextCode ( statestruct *pState, unsigned char * pPixelValueCur, unsigned char CodeBits ) +{ + unsigned short UpNode; + unsigned short DownNode; + /* start with the root node for last pixel chain */ + UpNode = *pPixelValueCur; + if ( (pState->InLen) == 0 ) + return AddCodeToBuffer(pState, UpNode, CodeBits ); + + *pPixelValueCur = (*(pState->pIn))-'0'; + (pState->pIn)++; + (pState->InLen)--; + /* Follow the string table and the data stream to the end of the longest string that has a code */ + while( 0 != ( DownNode = FindPixelOutlet(pState, UpNode, *pPixelValueCur ) ) ) + { + UpNode = DownNode; + if ( (pState->InLen) == 0 ) + return AddCodeToBuffer(pState, UpNode, CodeBits); + + *pPixelValueCur = (*(pState->pIn)) - '0'; + (pState->pIn)++; + (pState->InLen)--; + } + /* Submit 'UpNode' which is the code of the longest string */ + if ( AddCodeToBuffer(pState, UpNode, CodeBits ) ) + return -1; + /* ... and extend the string by appending 'PixelValueCur' */ + /* Create a successor node for 'PixelValueCur' whose code is 'freecode' */ + (pState->NodePix)[pState->FreeCode] = *pPixelValueCur; + (pState->NodeAxon)[pState->FreeCode] = (pState->NodeNext)[pState->FreeCode]=0; + /* ...and link it to the end of the chain emanating from fg_axon[UpNode]. */ + DownNode = (pState->NodeAxon)[UpNode]; + if( ! DownNode ) + { + (pState->NodeAxon)[UpNode] = pState->FreeCode; + } else { + while( (pState->NodeNext)[DownNode] ) + { + DownNode = (pState->NodeNext)[DownNode]; + } + (pState->NodeNext)[DownNode] = pState->FreeCode; + } + return 1; +} + +int gif_lzw(unsigned char *pOut, int OutLength, unsigned char *pIn, int InLen) +{ + unsigned char PixelValueCur; + unsigned char CodeBits; + unsigned short Pos; + statestruct State; + + State.pIn = pIn; + State.InLen = InLen; + State.pOut = pOut; + State.OutLength = OutLength; + // > Get first data byte + if (State.InLen == 0) + return 0; + + PixelValueCur = (unsigned char) ((*(State.pIn)) - '0'); + (State.pIn)++; + (State.InLen)--; + CodeBits = 3; + State.ClearCode = 4; + State.FreeCode = 6; + State.OutBitsFree = 8; + State.OutPosCur = -1; + State.fByteCountByteSet = 0; + + if ( BufferNextByte(&State) ) + return 0; + + for ( Pos = 0; Pos < State.ClearCode; Pos++) + State.NodePix[Pos] = (unsigned char) Pos; + + FlushStringTable(&State); + + /* Write what the GIF specification calls the "code size". */ + (State.pOut)[State.OutPosCur] = 2; + /* Reserve first bytecount byte */ + if ( BufferNextByte(&State) ) + return 0; + State.OutByteCountPos = State.OutPosCur; + if ( BufferNextByte(&State) ) + return 0; + State.fByteCountByteSet = 1; + /* Submit one 'ClearCode' as the first code */ + if ( AddCodeToBuffer(&State, State.ClearCode, CodeBits) ) + return 0; + + for(;;) + { + char Res; + /* generate and save the next code, which may consist of multiple input pixels. */ + Res = NextCode(&State, &PixelValueCur, CodeBits); + if ( Res < 0) + return 0; + //* Check for end of data stream */ + if( ! Res ) + { + /* submit 'eoi' as the last item of the code stream */ + if ( AddCodeToBuffer(&State, (unsigned short)(State.ClearCode + 1), CodeBits ) ) + return 0; + State.fByteCountByteSet = 0; + if( State.OutBitsFree < 8 ) + { + if ( BufferNextByte(&State) ) + return 0; + } + // > Update last bytecount byte; + if ( State.OutByteCountPos < State.OutPosCur ) + { + (State.pOut)[State.OutByteCountPos] = (unsigned char) (State.OutPosCur - State.OutByteCountPos - 1); + } + State.OutPosCur++; + return State.OutPosCur; + } + /* Check for currently last code */ + if( State.FreeCode == ( 1U << CodeBits ) ) + CodeBits++; + State.FreeCode++; + /* Check for full stringtable */ + if( State.FreeCode == 0xfff ) + { + FlushStringTable(&State); + if ( AddCodeToBuffer(&State, State.ClearCode, CodeBits ) ) + return 0; + + CodeBits=(unsigned char)( 1 + 2 ); + State.FreeCode=(unsigned short)( State.ClearCode + 2 ); + } + } +} + +int gif_pixel_plot(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle) { + char outbuf[10]; + int errno; + int row, column; + FILE *gif_file; + unsigned short ImageWidth; + unsigned short ImageHeight; + unsigned short usTemp; + int byte_out; +#ifdef _MSC_VER + char* rotated_bitmap; + char * lzwoutbuf; +#endif + +#ifndef _MSC_VER + char rotated_bitmap[image_height * image_width]; + char lzwoutbuf[image_height * image_width]; +#else + rotated_bitmap = (char *) _alloca((image_height * image_width) * sizeof(char)); + lzwoutbuf = (char *) _alloca((image_height * image_width) * sizeof(char)); +#endif /* _MSC_VER */ + + switch (rotate_angle) { + case 0: + case 180: + ImageWidth = image_width; + ImageHeight = image_height; + symbol->bitmap_width = image_width; + symbol->bitmap_height = image_height; + break; + case 90: + case 270: + ImageWidth = image_height; + ImageHeight = image_width; + symbol->bitmap_width = image_height; + symbol->bitmap_height = image_width; + break; + } + + /* sort out colour options */ + to_upper((unsigned char*) symbol->fgcolour); + to_upper((unsigned char*) symbol->bgcolour); + + if (strlen(symbol->fgcolour) != 6) { + strcpy(symbol->errtxt, "Malformed foreground colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + if (strlen(symbol->bgcolour) != 6) { + strcpy(symbol->errtxt, "Malformed background colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + errno = is_sane(SSET, (unsigned char*) symbol->fgcolour, strlen(symbol->fgcolour)); + if (errno == ZINT_ERROR_INVALID_DATA) { + strcpy(symbol->errtxt, "Malformed foreground colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + errno = is_sane(SSET, (unsigned char*) symbol->bgcolour, strlen(symbol->fgcolour)); + if (errno == ZINT_ERROR_INVALID_DATA) { + strcpy(symbol->errtxt, "Malformed background colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + + /* Rotate image before plotting */ + switch (rotate_angle) { + case 0: /* Plot the right way up */ + for (row = 0; row < image_height; row++) { + for (column = 0; column < image_width; column++) { + rotated_bitmap[(row * image_width) + column] = + *(pixelbuf + (image_width * row) + column); + } + } + break; + case 90: /* Plot 90 degrees clockwise */ + for (row = 0; row < image_width; row++) { + for (column = 0; column < image_height; column++) { + rotated_bitmap[(row * image_height) + column] = + *(pixelbuf + (image_width * (image_height - column - 1)) + row); + } + } + break; + case 180: /* Plot upside down */ + for (row = 0; row < image_height; row++) { + for (column = 0; column < image_width; column++) { + rotated_bitmap[(row * image_width) + column] = + *(pixelbuf + (image_width * (image_height - row - 1)) + (image_width - column - 1)); + } + } + break; + case 270: /* Plot 90 degrees anti-clockwise */ + for (row = 0; row < image_width; row++) { + for (column = 0; column < image_height; column++) { + rotated_bitmap[(row * image_height) + column] = + *(pixelbuf + (image_width * column) + (image_width - row - 1)); + } + } + break; + } + + + + /* Open output file in binary mode */ + if ((symbol->output_options & BARCODE_STDOUT) != 0) { +#ifdef _MSC_VER + if (-1 == _setmode(_fileno(stdout), _O_BINARY)) { + strcpy(symbol->errtxt, "Can't open output file"); + return ZINT_ERROR_FILE_ACCESS; + } +#endif + gif_file = stdout; + } else { + if (!(gif_file = fopen(symbol->outfile, "wb"))) { + strcpy(symbol->errtxt, "Can't open output file"); + return ZINT_ERROR_FILE_ACCESS; + } + } + /*ImageWidth = 2; + ImageHeight = 2; + rotated_bitmap[0] = 1; + rotated_bitmap[1] = 1; + rotated_bitmap[2] = 0; + rotated_bitmap[3] = 0; + */ + + /* GIF signature (6) */ + memcpy(outbuf,"GIF87a",6); + if ( TRANSPARENT_INDEX != -1 ) + outbuf[4]='9'; + fwrite(outbuf, 6, 1, gif_file); + /* Screen Descriptor (7) */ + /* Screen Width */ + usTemp=(unsigned short)ImageWidth; + outbuf[0] = (unsigned char)(0xff & usTemp); + outbuf[1] = (unsigned char)( (0xff00 & usTemp) / 0x100 ); + /* Screen Height */ + usTemp=(unsigned short)ImageHeight; + outbuf[2] = (unsigned char)( 0xff & usTemp ); + outbuf[3] = (unsigned char)( (0xff00 & usTemp) / 0x100 ); + /* write ImageBits-1 to the three least significant bits of byte 5 of + * the Screen Descriptor + */ + outbuf[4] = (unsigned char)( 0xf0 | (0x7&(DESTINATION_IMAGE_BITS-1)) ); + /* Background color = colortable index 0 */ + outbuf[5] = 0x00; + /* Byte 7 must be 0x00 */ + outbuf[6] = 0x00; + fwrite(outbuf, 7, 1, gif_file); + /* Global Color Table (6) */ + /* RGB 0 color */ + outbuf[0] = (unsigned char)(16 * ctoi(symbol->bgcolour[0])) + ctoi(symbol->bgcolour[1]); + outbuf[1] = (unsigned char)(16 * ctoi(symbol->bgcolour[2])) + ctoi(symbol->bgcolour[3]); + outbuf[2] = (unsigned char)(16 * ctoi(symbol->bgcolour[4])) + ctoi(symbol->bgcolour[5]); + /* RGB 1 color */ + outbuf[3] = (unsigned char)(16 * ctoi(symbol->fgcolour[0])) + ctoi(symbol->fgcolour[1]); + outbuf[4] = (unsigned char)(16 * ctoi(symbol->fgcolour[2])) + ctoi(symbol->fgcolour[3]); + outbuf[5] = (unsigned char)(16 * ctoi(symbol->fgcolour[4])) + ctoi(symbol->fgcolour[5]); + fwrite(outbuf, 6, 1, gif_file); + + /* Graphic control extension (8) */ + /* A graphic control extension block is used for overlay gifs. + * This is necessary to define a transparent color. + */ + if (TRANSPARENT_INDEX != -1) + { + /* Extension Introducer = '!' */ + outbuf[0] = '\x21'; + /* Graphic Control Label */ + outbuf[1] = '\xf9'; + /* Block Size */ + outbuf[2] = 4; + /* Packet fields: + * 3 Reserved + * 3 Disposal Method: 0 No Action, 1 No Dispose, 2: Background, 3: Prev. + * 1 User Input Flag: 0: no user input, 1: user input + * 1 Transparent Color Flag: 0: No Transparency, 1: Transparency index + */ + outbuf[3] = 1; + /* Delay Time */ + outbuf[4] = 0; + outbuf[5] = 0; + /* Transparent Color Index */ + outbuf[6] = (unsigned char)TRANSPARENT_INDEX; + /* Block Terminator */ + outbuf[7] = 0; + fwrite(outbuf, 8, 1, gif_file); + } + /* Image Descriptor */ + /* Image separator character = ',' */ + outbuf[0] = 0x2c; + /* "Image Left" */ + outbuf[1] = 0x00; + outbuf[2] = 0x00; + /* "Image Top" */ + outbuf[3] = 0x00; + outbuf[4] = 0x00; + /* Image Width (low byte first) */ + outbuf[5] = (unsigned char)(0xff & ImageWidth); + outbuf[6] = (unsigned char)((0xff00 & ImageWidth) / 0x100); + /* Image Height */ + outbuf[7] = (unsigned char)(0xff & ImageHeight); + outbuf[8] = (unsigned char)((0xff00 & ImageHeight) / 0x100); + + /* Byte 10 contains the interlaced flag and + * information on the local color table. + * There is no local color table if its most significant bit is reset. + */ + outbuf[9] = (unsigned char)(0|(0x7 & (DESTINATION_IMAGE_BITS-1))); + fwrite(outbuf, 10, 1, gif_file); + + /* call lzw encoding */ + byte_out = gif_lzw( + lzwoutbuf, + image_height * image_width, + rotated_bitmap, + image_height * image_width); + if (byte_out <= 0) + { + return ZINT_ERROR_MEMORY; + } + fwrite(lzwoutbuf, byte_out, 1, gif_file); + + /* GIF terminator */ + fputc('\x3b', gif_file); + fclose(gif_file); + + return 0; +} \ No newline at end of file diff --git a/backend/library.c b/backend/library.c index 0a5e3634..379179de 100644 --- a/backend/library.c +++ b/backend/library.c @@ -955,6 +955,12 @@ int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle) { symbol->text[0] = '\0'; } error_number = plot_raster(symbol, rotate_angle, OUT_PCX_FILE); + } else + if (!(strcmp(output, "GIF"))) { + if (symbol->scale < 1.0) { + symbol->text[0] = '\0'; + } + error_number = plot_raster(symbol, rotate_angle, OUT_GIF_FILE); } else if (!(strcmp(output, "TXT"))) { error_number = dump_plot(symbol); diff --git a/backend/raster.c b/backend/raster.c index 4da49b10..e0687db0 100644 --- a/backend/raster.c +++ b/backend/raster.c @@ -51,6 +51,7 @@ extern int png_pixel_plot(struct zint_symbol *symbol, int image_height, int imag #endif /* NO_PNG */ extern int bmp_pixel_plot(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle); extern int pcx_pixel_plot(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle); +extern int gif_pixel_plot(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle); int save_raster_image_to_file(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle, int image_type) { int error_number; @@ -92,6 +93,9 @@ int save_raster_image_to_file(struct zint_symbol *symbol, int image_height, int case OUT_PCX_FILE: error_number = pcx_pixel_plot(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle); break; + case OUT_GIF_FILE: + error_number = gif_pixel_plot(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle); + break; default: error_number = bmp_pixel_plot(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle); break; diff --git a/backend_qt4/backend_qt4.pro b/backend_qt4/backend_qt4.pro index e3c9971e..d3aa0c0e 100644 --- a/backend_qt4/backend_qt4.pro +++ b/backend_qt4/backend_qt4.pro @@ -85,6 +85,7 @@ SOURCES += ../backend/2of5.c \ ../backend/common.c \ ../backend/composite.c \ ../backend/dmatrix.c \ + ../backend/gif.c \ ../backend/gridmtx.c \ ../backend/gs1.c \ ../backend/hanxin.c \ diff --git a/win32/zint_cmdline_vc6/zint_cmdline_vc6.dsp b/win32/zint_cmdline_vc6/zint_cmdline_vc6.dsp index b4b19b5a..2fb3291d 100644 --- a/win32/zint_cmdline_vc6/zint_cmdline_vc6.dsp +++ b/win32/zint_cmdline_vc6/zint_cmdline_vc6.dsp @@ -66,7 +66,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\..\backend" /I "..\..\..\lpng" /I "..\..\..\zlib" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /D /D /D /D /D /D /D /GZ ZINT_VERSION="\"2.7.4\"" /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\..\backend" /I "..\..\..\lpng" /I "..\..\..\zlib" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "NO_PNG" /YX /FD /GZ /D ZINT_VERSION="\"2.7.4\"" /c # ADD BASE RSC /l 0x407 /d "_DEBUG" # ADD RSC /l 0x407 /d "_DEBUG" BSC32=bscmake.exe @@ -144,6 +144,10 @@ SOURCE=..\..\frontend\getopt1.c # End Source File # Begin Source File +SOURCE=..\..\backend\gif.c +# End Source File +# Begin Source File + SOURCE=..\..\backend\gridmtx.c # End Source File # Begin Source File