summaryrefslogtreecommitdiffstats
path: root/tkagif/tkagif.C
diff options
context:
space:
mode:
Diffstat (limited to 'tkagif/tkagif.C')
-rw-r--r--tkagif/tkagif.C730
1 files changed, 0 insertions, 730 deletions
diff --git a/tkagif/tkagif.C b/tkagif/tkagif.C
deleted file mode 100644
index 2429426..0000000
--- a/tkagif/tkagif.C
+++ /dev/null
@@ -1,730 +0,0 @@
-// Copyright (C) 2019
-// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
-// For conditions of distribution and use, see copyright notice in "copyright"
-
-#include <math.h>
-#include <float.h>
-
-#include <iostream>
-#include <sstream>
-#include <fstream>
-using namespace std;
-
-#include <stdlib.h>
-#include <string.h>
-#include <tk.h>
-
-#include "tkagif.h"
-
-#define MAXCOLORS 256
-
-extern "C" {
- int Tkagif_Init(Tcl_Interp* interp);
- int TkagifCmd(ClientData data, Tcl_Interp *interp, int argc,
- const char* argv[]);
-}
-
-TkAGIF* tkagif=NULL;
-
-int Tkagif_Init(Tcl_Interp* interp) {
-
- if (Tcl_InitStubs(interp, TCL_PATCH_LEVEL, 0) == NULL)
- return TCL_ERROR;
-
- if (Tk_InitStubs(interp, TK_PATCH_LEVEL, 0) == NULL)
- return TCL_ERROR;
-
- Tcl_CreateCommand(interp, "agif", TkagifCmd,
- (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
-
- if (Tcl_PkgProvide(interp, PACKAGE_NAME, PACKAGE_VERSION) != TCL_OK)
- return TCL_ERROR;
-
- tkagif = new TkAGIF(interp);
-
- if (tkagif)
- return TCL_OK;
- else
- return TCL_ERROR;
-}
-
-int TkagifCmd(ClientData data,Tcl_Interp *interp,int argc,const char* argv[])
-{
- if (argc>=2) {
- if (!strncmp(argv[1], "create", 3))
- return tkagif->create(argc, argv);
- else if (!strncmp(argv[1], "add", 3))
- return tkagif->add(argc, argv);
- else if (!strncmp(argv[1], "close", 3))
- return tkagif->close(argc, argv);
- else {
- Tcl_AppendResult(interp, "tkagif: unknown command: ", argv[1], NULL);
- return TCL_ERROR;
- }
- }
- else {
- Tcl_AppendResult(interp, "usage: tkagif ?create?add?close?", NULL);
- return TCL_ERROR;
- }
-}
-
-TkAGIF::TkAGIF(Tcl_Interp* interp)
-{
- interp_ = interp;
- out_ =NULL;
- width_ = 512;
- height_ = 512;
- resolution_ =0;
-
- pict_ =NULL;
- colorTable_ =NULL;
-
- // Actual size of colortable to be saved
- colorTableSize_ =0;
-
- // Compress
- pictCount_ =0;
-
- initialBits_ =0;
- numBits_ =0;
- currentBits_ =0;
-
- maxCode_ =0;
- clearCode_ =0;
- eofCode_ =0;
-
- clearFlag_ =0;
- freeEntry_ =0;
-
- accumulatedByteCount_ =0;
- currentAccumulated_ =0;
-}
-
-int TkAGIF::create(int argc, const char* argv[])
-{
- if (argc == 5) {
- if (*argv[2] == '\0') {
- Tcl_AppendResult(interp_, "bad filename", NULL);
- return TCL_ERROR;
- }
- }
- else {
- Tcl_AppendResult(interp_, "usage: tkagif create <filename> <width> <height>", NULL);
- return TCL_ERROR;
- }
-
- // open fn
- out_ = new ofstream(argv[2], std::ios::binary);
- if (!out_) {
- Tcl_AppendResult(interp_, "Error: unable to open filename ", NULL);
- if (*argv[2])
- Tcl_AppendResult(interp_, argv[2], NULL);
- return TCL_ERROR;
- }
-
- {
- string s(argv[3]);
- istringstream str(s);
- str >> width_;
- }
- {
- string s(argv[4]);
- istringstream str(s);
- str >> height_;
- }
-
- // *** Header ***
- {
- char header[] = "GIF89a";
- out_->write(header,6);
- }
-
- // *** Logical Screen Descriptor ***
- {
- // width
- unsigned short ww = width_;
- out_->write((char*)&ww,2);
- // height
- unsigned short hh = height_;
- out_->write((char*)&hh,2);
-
- // Packed Field: msb to lsb
- // global color table flag (1): 0 no gct, 1: gct
- // color resolution (3): number bits-1
- // sort flag (1): 0 not ordered, 1 ordered decreasing importance
- // size of global color table (3): size 2^(x+1)
- union qq {
- struct pp {
- unsigned int size: 3;
- unsigned int sort: 1;
- unsigned int resolution: 3;
- unsigned int gt: 1;
- } tt;
- unsigned char cc;
- };
- union qq pkg;
-
- pkg.tt.gt = 0;
- pkg.tt.resolution = 0;
- pkg.tt.sort = 0;
- pkg.tt.size = 0;
-
- out_->write((char*)&pkg.cc,1);
-
- // BG Color
- unsigned char bg=0x00;
- out_->write((char*)&bg,1);
-
- // Pixel Aspect Ratio
- unsigned char ar=0x00;
- out_->write((char*)&ar,1);
- }
-
- // *** Global Color Table ***
- // not present
-
- // *** Comment Extension
- // not present
-
- // *** Application Extension Block ***
- {
- // Extention Introducer
- unsigned char ext = 0x21;
- out_->write((char*)&ext,1);
- // Extention Lable
- unsigned char lable = 0xFF;
- out_->write((char*)&lable,1);
- // Block Size
- unsigned char ss= 0x0B;
- out_->write((char*)&ss,1);
- // Applcation Identifier
- unsigned char id[] = "NETSCAPE";
- out_->write((char*)id,8);
- // Authentication Code
- unsigned char code[] = "2.0";
- out_->write((char*)code,3);
- // Application Data Size
- unsigned char dd=0x03;
- out_->write((char*)&dd,1);
- // Application Data
- unsigned char rep[] = {0x01,0x00,0x00};
- out_->write((char*)rep,3);
- // Block Terminator
- unsigned char end=0x00;
- out_->write((char*)&end,1);
- }
-
- // *** Graphic Control Extension ***
- {
- // Extention Introducer
- unsigned char ext = 0x21;
- out_->write((char*)&ext,1);
- // Extention Lable
- unsigned char lable = 0xF9;
- out_->write((char*)&lable,1);
- // Block Size
- unsigned char ss= 0x04;
- out_->write((char*)&ss,1);
-
- // Packed Field msb to lsb
- // Reserved (3)
- // Displosal Method (3): 0 none, 1 do not dispose, 2 restore bg, 3 restore
- // User Input Flag (1): 0 none, 1 expected
- // Transparent Color Flag (1): 0 not given, 1 color index
- union qq {
- struct pp {
- unsigned int transparent: 1;
- unsigned int input: 1;
- unsigned int dispose: 3;
- unsigned int reserve: 3;
- } tt;
- unsigned char cc;
- };
- union qq pkg;
-
- pkg.tt.reserve =0;
- pkg.tt.dispose =0;
- pkg.tt.input =0;
- pkg.tt.transparent =0;
- out_->write((char*)&pkg.cc,1);
-
- // Delay Time
- unsigned short delay = 0x00;
- out_->write((char*)&delay,2);
- // Transparent Color Index
- unsigned char trans= 0x00;
- out_->write((char*)&trans,1);
- // Block Terminator
- unsigned char end= 0x00;
- out_->write((char*)&end,1);
- }
-
- return TCL_OK;
-}
-
-int TkAGIF::add(int argc, const char* argv[])
-{
- if (argc == 3) {
- if (*argv[2] == '\0') {
- Tcl_AppendResult(interp_, "bad filename", NULL);
- return TCL_ERROR;
- }
- }
- else {
- Tcl_AppendResult(interp_, "usage: tkagif add <image>", NULL);
- return TCL_ERROR;
- }
-
- // RGB img
- Pixel* pixels = new Pixel[width_*height_];
- memset(pixels,0,sizeof(Pixel)*width_*height_);
- {
- Tk_PhotoHandle photo = Tk_FindPhoto(interp_, argv[2]);
- if (!photo) {
- Tcl_AppendResult(interp_, "bad image handle", NULL);
- return TCL_ERROR;
- }
- Tk_PhotoImageBlock block;
- if (!Tk_PhotoGetImage(photo,&block)) {
- Tcl_AppendResult(interp_, "bad image block", NULL);
- return TCL_ERROR;
- }
-
- unsigned char* src = block.pixelPtr;
- Pixel* dst = pixels;
- for (int jj=0; jj<height_; jj++) {
- for (int ii=0; ii<width_; ii++, dst++) {
- dst->red = src[(jj*width_+ii)*block.pixelSize+block.offset[0]];
- dst->green = src[(jj*width_+ii)*block.pixelSize+block.offset[1]];
- dst->blue = src[(jj*width_+ii)*block.pixelSize+block.offset[2]];
- }
- }
- }
-
- // Indexed img
- if (pict_)
- delete [] pict_;
- pict_ = new unsigned char[width_*height_];
- memset(pict_,0,width_*height_);
-
- if (colorTable_)
- delete [] colorTable_;
- colorTable_ = new Color[MAXCOLORS];
-
- scanImage(pixels);
-
- // *** Local Image Descriptor ***
- {
- // Image Separator
- unsigned char img= 0x2C;
- out_->write((char*)&img,1);
-
- // Image Left Position
- unsigned short left = 0;
- out_->write((char*)&left,2);
-
- // Image Top Position
- unsigned short top = 0;
- out_->write((char*)&top,2);
-
- // Image Width
- unsigned short ww = width_;
- out_->write((char*)&ww,2);
-
- // Image Heght
- unsigned short hh = height_;
- out_->write((char*)&hh,2);
-
- // Packed Field msb to lsb
- // Local Table Flag (1): 1 local table, 0 no
- // Interlace Flag (1): 1 interlaced, 0 no
- // Sort Flag (1): 1 sorted, 0 no
- // Reserved (2):
- // Size of Local Table (3): size 2^(x+1)
- union qq {
- struct pp {
- unsigned int size: 3;
- unsigned int reserve: 2;
- unsigned int sort: 1;
- unsigned int interlace: 1;
- unsigned int ct: 1;
- } tt;
- unsigned char cc;
- };
- union qq pkg;
-
- pkg.tt.ct = 1;
- pkg.tt.interlace =0;
- pkg.tt.sort = 0;
- pkg.tt.reserve = 0;
- pkg.tt.size = resolution_-1;
-
- out_->write((char*)&pkg.cc,1);
- }
-
- // *** Local Color Table ***
- for (int ii=0; ii<colorTableSize_; ii++) {
- out_->write((char*)&colorTable_[ii].red,1);
- out_->write((char*)&colorTable_[ii].green,1);
- out_->write((char*)&colorTable_[ii].blue,1);
- }
-
- // *** Image Data ***
- compress();
-
- // end of Image Data
- unsigned char end= 0x00;
- out_->write((char*)&end,1);
-
- // cleanup
- if (pict_)
- delete [] pict_;
- pict_ =NULL;
-
- if (colorTable_)
- delete [] colorTable_;
- colorTable_ =NULL;
-
- return TCL_OK;
-}
-
-int TkAGIF::close(int argc, const char* argv[])
-{
- // *** Trailer ***
- unsigned char end = 0x3B;
- out_->write((char*)&end,1);
-
- out_->close();
- delete out_;
-
- return TCL_OK;
-}
-
-void TkAGIF::initColorTable()
-{
- memset(colorTable_,0,sizeof(Color)*MAXCOLORS);
-
- // Base Colors
- // 0: black
- // 1: white
- colorTable_[1].red = colorTable_[1].green = colorTable_[1].blue = 255;
- colorTable_[1].count++;
- // 2: red
- colorTable_[2].red = 255;
- colorTable_[2].count++;
- // 3: green
- colorTable_[3].green = 255;
- colorTable_[3].count++;
- // 4: blue
- colorTable_[4].blue = 255;
- colorTable_[4].count++;
- // 5: cyan
- colorTable_[5].green = colorTable_[5].blue = 255;
- colorTable_[5].count++;
- // 6: magenta
- colorTable_[6].red = colorTable_[6].blue = 255;
- colorTable_[6].count++;
- // 7: yellow
- colorTable_[7].red = colorTable_[7].green = 255;
- colorTable_[7].count++;
-
- // some Greys for numerics
- // 8: 1/4 grey
- colorTable_[8].red = colorTable_[8].green = colorTable_[8].blue = 64;
- colorTable_[8].count++;
- // 9: 1/2 grey
- colorTable_[9].red = colorTable_[9].green = colorTable_[9].blue = 128;
- colorTable_[9].count++;
- // 10: 3/4 grey
- colorTable_[10].red = colorTable_[10].green = colorTable_[10].blue = 192;
- colorTable_[10].count++;
-}
-
-#define ALMOST2(aa,bb) (abs(aa-bb) <= iter)
-
-void TkAGIF::scanImage(Pixel* pixels)
-{
- int finished =0;
- int iter = 1;
- int totalColors =11;
-
- do {
- initColorTable();
- totalColors =11;
-
- Pixel* src = pixels;
- unsigned char* dst = pict_;
- for (int jj=0; jj<height_; jj++) {
- for (int ii=0; ii<width_; ii++, src++, dst++) {
- // first try all known colors
- int done =0;
- for (int kk=0; kk<totalColors; kk++) {
- if (ALMOST2(src->red, colorTable_[kk].red) &&
- ALMOST2(src->green, colorTable_[kk].green) &&
- ALMOST2(src->blue, colorTable_[kk].blue)) {
- colorTable_[kk].count++;
- *dst = kk;
- done =1;
- break;
- }
- }
-
- // add color
- if (!done) {
- if (totalColors<MAXCOLORS) {
- colorTable_[totalColors].red = src->red;
- colorTable_[totalColors].green = src->green;
- colorTable_[totalColors].blue = src->blue;
- colorTable_[totalColors].count++;
- *dst = totalColors;
- totalColors++;
- }
- else {
- // abort, try again
- iter ++;
- goto end;
- }
- }
- }
- }
- finished =1;
-
- end:
- ;
- } while (!finished);
-
- resolution_ =0;
- while (totalColors >> resolution_)
- resolution_++;
- if (resolution_>8)
- resolution_ =8;
- colorTableSize_ = 1 << resolution_;
-
- if (0) {
- cerr << "Iteration: " << iter << endl;
- cerr << "Total Colors: " << totalColors << endl;
- cerr << "Resolution: " << resolution_ << endl;
- cerr << "ColorTableSize: " << colorTableSize_ << endl;
- for (int ii=0; ii<totalColors; ii++) {
- cerr << ii << ' '
- << colorTable_[ii].count << ' '
- << (unsigned short)(colorTable_[ii].red) << ' '
- << (unsigned short)colorTable_[ii].green << ' '
- << (unsigned short)colorTable_[ii].blue << endl;
- }
- }
-}
-
-#define GIFBITS 12
-#define MAXCODE(numBits) (((long)1 << (numBits))-1)
-#define U(x) ((unsigned)(x))
-
-void TkAGIF::compress()
-{
- // LZW minium code size
- out_->write((char*)&resolution_,1);
-
- unsigned int codeTable[HSIZE];
- unsigned int outCount = 0;
- unsigned int inCount = 1;
-
- // init
- pictCount_ =0;
-
- initialBits_ = resolution_+1;
- numBits_ = initialBits_;
- currentBits_ = 0;
-
- maxCode_ = MAXCODE(numBits_);
- clearCode_ = 1 << (initialBits_ - 1);
- eofCode_ = clearCode_ + 1;
-
- clearFlag_ = 0;
- freeEntry_ = clearCode_ + 2;
-
- accumulatedByteCount_ = 0;
- currentAccumulated_ = 0;
-
- long ent = input();
-
- int hshift =0;
- long fcode =0;
- for (fcode = (long)HSIZE; fcode < 65536L; fcode *= 2L)
- hshift++;
-
- // Set hash code range bound
- hshift = 8 - hshift;
-
- long hSize = HSIZE;
- clearHashTable();
-
- output((long)clearCode_);
-
- long disp =0;
- long i =0;
- int c =0;
- while (U(c = input()) != U(EOF)) {
- inCount++;
-
- fcode = (long)(((long) c << GIFBITS) + ent);
- i = ((long)c << hshift) ^ ent; // XOR hashing
-
- if (hashTable_[i] == fcode) {
- ent = codeTable[i];
- continue;
- }
- else if ((long) hashTable_[i] < 0)
- goto nomatch; // Empty slot
-
- // Secondary hash (after G. Knott)
- disp = hSize - i;
- if (i == 0)
- disp = 1;
-
- probe:
- if ((i -= disp) < 0)
- i += hSize;
-
- if (hashTable_[i] == fcode) {
- ent = codeTable[i];
- continue;
- }
- if ((long)hashTable_[i] > 0)
- goto probe;
-
- nomatch:
- output((long)ent);
- outCount++;
- ent = c;
- if (U(freeEntry_) < U((long)1 << GIFBITS)) {
- // code -> hashtable
- codeTable[i] = freeEntry_++;
- hashTable_[i] = fcode;
- }
- else
- clearForBlock();
- }
-
- // Put out the final code.
- output((long)ent);
- outCount++;
- output((long)eofCode_);
-}
-
-int TkAGIF::input()
-{
- if (pictCount_ < width_*height_) {
- int rr = pict_[pictCount_];
- pictCount_++;
- return rr;
- }
- else
- return EOF;
-}
-
-void TkAGIF::output(long code)
-{
- static const unsigned long masks[] = {
- 0x0000,
- 0x0001, 0x0003, 0x0007, 0x000F,
- 0x001F, 0x003F, 0x007F, 0x00FF,
- 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
- 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF
- };
-
- currentAccumulated_ &= masks[currentBits_];
- if (currentBits_ > 0) {
- currentAccumulated_ |= ((long) code << currentBits_);
- } else {
- currentAccumulated_ = code;
- }
- currentBits_ += numBits_;
-
- while (currentBits_ >= 8) {
- charOut((unsigned)(currentAccumulated_ & 0xff));
- currentAccumulated_ >>= 8;
- currentBits_ -= 8;
- }
-
- // If the next entry is going to be too big for the code size, then
- // increase it, if possible.
- if ((freeEntry_ > maxCode_) || clearFlag_) {
- if (clearFlag_) {
- maxCode_ = MAXCODE(numBits_ = initialBits_);
- clearFlag_ = 0;
- }
- else {
- numBits_++;
- if (numBits_ == GIFBITS)
- maxCode_ = (long)1 << GIFBITS;
- else
- maxCode_ = MAXCODE(numBits_);
- }
- }
-
- if (code == eofCode_) {
- // At EOF, write the rest of the buffer.
- while (currentBits_ > 0) {
- charOut((unsigned)(currentAccumulated_ & 0xff));
- currentAccumulated_ >>= 8;
- currentBits_ -= 8;
- }
- flushChar();
- }
-}
-
-void TkAGIF::clearForBlock()
-{
- clearHashTable();
- freeEntry_ = clearCode_ + 2;
- clearFlag_ = 1;
-
- output((long)clearCode_);
-}
-
-void TkAGIF::clearHashTable()
-{
- int *hashTablePtr = hashTable_ + int(HSIZE);
- long m1 = -1;
- long ii = HSIZE - 16;
-
- do {
- *(hashTablePtr-16) = m1;
- *(hashTablePtr-15) = m1;
- *(hashTablePtr-14) = m1;
- *(hashTablePtr-13) = m1;
- *(hashTablePtr-12) = m1;
- *(hashTablePtr-11) = m1;
- *(hashTablePtr-10) = m1;
- *(hashTablePtr-9) = m1;
- *(hashTablePtr-8) = m1;
- *(hashTablePtr-7) = m1;
- *(hashTablePtr-6) = m1;
- *(hashTablePtr-5) = m1;
- *(hashTablePtr-4) = m1;
- *(hashTablePtr-3) = m1;
- *(hashTablePtr-2) = m1;
- *(hashTablePtr-1) = m1;
- hashTablePtr -= 16;
- } while ((ii -= 16) >= 0);
-
- for (ii += 16; ii > 0; ii--)
- *--hashTablePtr = m1;
-}
-
-void TkAGIF::charOut(int cc)
-{
- packetAccumulator_[accumulatedByteCount_++] = cc;
- if (accumulatedByteCount_ >= 254)
- flushChar();
-}
-
-void TkAGIF::flushChar()
-{
- if (accumulatedByteCount_ > 0) {
- unsigned char cc = accumulatedByteCount_;
- out_->write((char*)&cc,1);
- out_->write((char*)packetAccumulator_, accumulatedByteCount_);
- accumulatedByteCount_ = 0;
- }
-}