Texture * LoadGIF(FILE *fp, char *fname ) { Texture *texture; int filesize, numcols; register unsigned char ch, ch1; register byte *ptr, *ptr1; register int i; BitOffset=0; XC=0; YC=0; Pass=0; /* find the size of the file */ fseek(fp, 0L, 2); filesize = ftell(fp); fseek(fp, 0L, 0); if (!(ptr = RawGIF = (byte *) malloc(filesize))) fatal_error("not enough memory to read gif file"); if (!(Raster = (byte *) malloc(filesize))) { free( ptr ); fatal_error("not enough memory to read gif file"); } if (fread(ptr, filesize, 1, fp) != 1) fatal_error("GIF data read failed"); if (strncmp(ptr, id, 6)) fatal_error("not a GIF file"); ptr += 6; /* Get variables from the GIF screen descriptor */ ch = NEXTBYTE; RWidth = ch + 0x100 * NEXTBYTE; /* screen dimensions... not used. */ ch = NEXTBYTE; RHeight = ch + 0x100 * NEXTBYTE; if (Verbose) fprintf(stderr, "screen dims: %dx%d.\n", RWidth, RHeight); ch = NEXTBYTE; HasColormap = ((ch & COLORMAPMASK) ? True : False); BitsPerPixel = (ch & 7) + 1; numcols = ColorMapSize = 1 << BitsPerPixel; BitMask = ColorMapSize - 1; printf("ColorMapSize = %d\n",ColorMapSize); Background = NEXTBYTE; /* background color... not used. */ if (NEXTBYTE) /* supposed to be NULL */ fatal_error("corrupt GIF file (bad screen descriptor)"); /* Read in global colormap. */ if (HasColormap) { if (Verbose) fprintf(stderr, "%s is %dx%d, %d bits per pixel, (%d colors).\n", fname, RWidth,RHeight,BitsPerPixel, ColorMapSize); for (i = 0; i < ColorMapSize; i++) { Red[i] = NEXTBYTE; Green[i] = NEXTBYTE; Blue[i] = NEXTBYTE; used[i] = 0; } numused = 0; } /* else no colormap in GIF file */ /* Check for image seperator */ if (NEXTBYTE != IMAGESEP) fatal_error("corrupt GIF file (no image separator)"); /* Now read in values from the image descriptor */ ch = NEXTBYTE; LeftOfs = ch + 0x100 * NEXTBYTE; ch = NEXTBYTE; TopOfs = ch + 0x100 * NEXTBYTE; ch = NEXTBYTE; Width = ch + 0x100 * NEXTBYTE; ch = NEXTBYTE; Height = ch + 0x100 * NEXTBYTE; Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False); if (Verbose) fprintf(stderr, "Reading a %d by %d %sinterlaced image...", Width, Height, (Interlace) ? "" : "non-"); texture = new_texture( Width, Height ); /* Note that I ignore the possible existence of a local color map. * I'm told there aren't many files around that use them, and the spec * says it's defined for future use. This could lead to an error * reading some files. */ /* Start reading the raster data. First we get the intial code size * and compute decompressor constant values, based on this code size. */ CodeSize = NEXTBYTE; ClearCode = (1 << CodeSize); EOFCode = ClearCode + 1; FreeCode = FirstFree = ClearCode + 2; /* The GIF spec has it that the code size is the code size used to * compute the above values is the code size given in the file, but the * code size used in compression/decompression is the code size given in * the file plus one. (thus the ++). */ CodeSize++; InitCodeSize = CodeSize; MaxCode = (1 << CodeSize); ReadMask = MaxCode - 1; /* Read the raster data. Here we just transpose it from the GIF array * to the Raster array, turning it from a series of blocks into one long * data stream, which makes life much easier for ReadCode(). */ ptr1 = Raster; do { ch = ch1 = NEXTBYTE; while (ch--) *ptr1++ = NEXTBYTE; if ((ptr - Raster) > filesize) fatal_error("corrupt GIF file (unblock)"); } while(ch1); free(RawGIF); /* We're done with the raw data now... */ if (Verbose) { fprintf(stderr, "done.\n"); fprintf(stderr, "Decompressing..."); } Image = texture->texels; BytesPerScanline = Width; /* Decompress the file, continuing until you see the GIF EOF code. * One obvious enhancement is to add checking for corrupt files here. */ Code = ReadCode(); while (Code != EOFCode) { /* Clear code sets everything back to its initial value, then reads the * immediately subsequent code as uncompressed data. */ if (Code == ClearCode) { CodeSize = InitCodeSize; MaxCode = (1 << CodeSize); ReadMask = MaxCode - 1; FreeCode = FirstFree; CurCode = OldCode = Code = ReadCode(); FinChar = CurCode & BitMask; AddToPixel(FinChar); } else { /* If not a clear code, then must be data: save same as CurCode and InCode */ CurCode = InCode = Code; /* If greater or equal to FreeCode, not in the hash table yet; * repeat the last character decoded */ if (CurCode >= FreeCode) { CurCode = OldCode; OutCode[OutCount++] = FinChar; } /* Unless this code is raw data, pursue the chain pointed to by CurCode * through the hash table to its end; each code in the chain puts its * associated output code on the output queue. */ while (CurCode > BitMask) { if (OutCount > 1024) { fprintf(stderr,"\nCorrupt GIF file (OutCount)!\n"); exit(1); /* calling 'exit(-1)' dumps core, so I don't */ } OutCode[OutCount++] = Suffix[CurCode]; CurCode = Prefix[CurCode]; } /* The last code in the chain is treated as raw data. */ FinChar = CurCode & BitMask; OutCode[OutCount++] = FinChar; /* Now we put the data out to the Output routine. * It's been stacked LIFO, so deal with it that way... */ for (i = OutCount - 1; i >= 0; i--) AddToPixel(OutCode[i]); OutCount = 0; /* Build the hash table on-the-fly. No table is stored in the file. */ Prefix[FreeCode] = OldCode; Suffix[FreeCode] = FinChar; OldCode = InCode; /* Point to the next slot in the table. If we exceed the current * MaxCode value, increment the code size unless it's already 12. If it * is, do nothing: the next code decompressed better be CLEAR */ FreeCode++; if (FreeCode >= MaxCode) { if (CodeSize < 12) { CodeSize++; MaxCode *= 2; ReadMask = (1 << CodeSize) - 1; } } } Code = ReadCode(); } free(Raster); if (Verbose) fprintf(stderr, "done.\n"); else fprintf(stderr,"(of which %d are used)\n",numused); remap(texture); return texture; }
int CCDSim::DrawImageStar(CCDChip *targetChip, float mag,float x,float y) { //float d; //float r; int sx,sy; int drew=0; int boxsizex=5; int boxsizey=5; float flux; float ExposureTime; if (targetChip->getXRes() == 500) ExposureTime = GuideExposureRequest*4; else ExposureTime = ExposureRequest; if((x<0)||(x>targetChip->getXRes()/targetChip->getBinX())||(y<0)||(y>targetChip->getYRes()/targetChip->getBinY())) { // this star is not on the ccd frame anyways return 0; } // calculate flux from our zero point and gain values flux=pow(10,((mag-z)*k/-2.5)); // ok, flux represents one second now // scale up linearly for exposure time flux=flux*ExposureTime; float qx; // we need a box size that gives a radius at least 3 times fwhm qx=seeing/ImageScalex; qx=qx*3; boxsizex=(int)qx; boxsizex++; qx=seeing/ImageScaley; qx=qx*3; boxsizey=(int)qx; boxsizey++; //IDLog("BoxSize %d %d\n",boxsizex,boxsizey); for(sy=-boxsizey; sy<=boxsizey; sy++) { for(sx=-boxsizey; sx<=boxsizey; sx++) { int rc; float dc; // distance from center float fp; // flux this pixel; // need to make this account for actual pixel size dc=sqrt(sx*sx*ImageScalex*ImageScalex+sy*sy*ImageScaley*ImageScaley); // now we have the distance from center, in arcseconds // This should be gaussian, but, for now we'll just go with // a simple linear function float fa; fa=exp(-2.0*0.7*(dc*dc)/seeing/seeing); fp=fa*flux*targetChip->getBinX()*targetChip->getBinY(); if(fp < 0) fp=0; /* if(dc < boxsize) { dc=boxsize-dc; dc=dc/boxsize; fp=dc*flux; } else { fp=0; } */ rc=AddToPixel(targetChip, x+sx,y+sy,fp); if(rc != 0) drew=1; } } return drew; }
BYTE * Decompress(GIFIMAGEDESC *GifImageDesc, GIFHEAD *GifHead) { int i; XC = 0; YC = 0; Pass = 0; OutCount = 0; BitOffset = 0; DataMask = (1 << ((GifHead->PackedField & 0x07) +1)) -1; Raster = GifImageDesc->GIFImage; /* Check for image seperator */ /* Now read in values from the image descriptor */ IWidth = GifImageDesc->ImageWidth; IHeight = GifImageDesc->ImageHeight; Interlace = GifImageDesc->PackedField & 0x40; /* * Note that I ignore the possible existence of a local color map. I'm * told there aren't many files around that use them, and the spec says * it's defined for future use. This could lead to an error reading some * files. */ /* * Start reading the raster data. First we get the WORDial code size and * compute decompressor constant values, based on this code size. */ CodeSize = GifImageDesc->CodeSize; ClearCode = (1 << CodeSize); EOFCode = ClearCode + 1; FreeCode = FirstFree = ClearCode + 2; /* * The GIF spec has it that the code size is the code size used to compute * the above values is the code size given in the file, but the code size * used in compression/decompression is the code size given in the file * plus one. (thus the ++). */ CodeSize++; InitCodeSize = CodeSize; MaxCode = (1 << CodeSize); ReadMask = MaxCode - 1; /* * Read the raster data. Here we just transpose it from the GIF array to * the Raster array, turning it from a series of blocks WORDo one long * data stream, which makes life much easier for ReadCode(). */ /* Allocate the Image */ if (!(Image = (BYTE *)malloc((size_t)IWidth*(size_t)IHeight))) { printf("Out of memory"); exit(EXIT_FAILURE); } BytesPerScanline = IWidth; /* * Decompress the file, continuing until you see the GIF EOF code. One * obvious enhancement is to add checking for corrupt files here. */ Code = ReadCode(); while (Code != EOFCode) { /* * Clear code sets everything back to its initial value, then reads * the immediately subsequent code as uncompressed data. */ if (Code == ClearCode) { CodeSize = InitCodeSize; MaxCode = (1 << CodeSize); ReadMask = MaxCode - 1; FreeCode = FirstFree; CurCode = OldCode = Code = ReadCode(); FinChar = CurCode & DataMask; AddToPixel((BYTE)FinChar); } else { /* * If not a clear code, then must be data: save same as CurCode * and InCode */ CurCode = InCode = Code; /* * If greater or equal to FreeCode, not in the hash table yet; * repeat the last character decoded */ if (CurCode >= FreeCode) { CurCode = OldCode; OutCode[OutCount++] = FinChar; } /* * Unless this code is raw data, pursue the chain poWORDed to by * CurCode through the hash table to its end; each code in the * chain puts its associated output code on the output queue. */ while (CurCode > DataMask) { if (OutCount > 1024) { /*return error message*/ } OutCode[OutCount++] = Suffix[CurCode]; CurCode = Prefix[CurCode]; } /* The last code in the chain is treated as raw data. */ FinChar = CurCode & DataMask; OutCode[OutCount++] = FinChar; /* * Now we put the data out to the Output routine. It's been * stacked LIFO, so deal with it that way... */ for (i = OutCount - 1; i >= 0; i--) AddToPixel((BYTE)OutCode[i]); OutCount = 0; /* * Build the hash table on-the-fly. No table is stored in the * file. */ Prefix[FreeCode] = OldCode; Suffix[FreeCode] = FinChar; OldCode = InCode; /* * PoWORD to the next slot in the table. If we exceed the current * MaxCode value, increment the code size unless it's already 12. * If it is, do nothing: the next code decompressed better be * CLEAR */ FreeCode++; if (FreeCode >= MaxCode) if (CodeSize < 12) { CodeSize++; MaxCode *= 2; ReadMask = (1 << CodeSize) - 1; } } Code = ReadCode(); } return Image; }
int CCDSim::DrawCcdFrame(CCDChip *targetChip) { // Ok, lets just put a silly pattern into this // CCd frame is 16 bit data unsigned short int *ptr; unsigned short int val; float ExposureTime; float targetFocalLength; ptr=(unsigned short int *) targetChip->getFrameBuffer(); if (targetChip->getXRes() == 500) { targetFocalLength = guider_focallength; ExposureTime = GuideExposureRequest*4; } else { targetFocalLength = focallength; ExposureTime = ExposureRequest; } if(ShowStarField) { char gsccmd[250]; FILE *pp; int stars=0; int lines=0; int drawn=0; int x,y; float PEOffset; float PESpot; double rad; // telescope ra in degrees double rar; // telescope ra in radians double decr; // telescope dec in radians; double timesince; time_t now; time(&now); // Lets figure out where we are on the pe curve timesince=difftime(now,RunStart); // This is our spot in the curve PESpot=timesince/PEPeriod; // Now convert to radians PESpot=PESpot*2.0*3.14159; PEOffset=PEMax*sin(PESpot); //fprintf(stderr,"PEOffset = %4.2f arcseconds timesince %4.2f\n",PEOffset,timesince); PEOffset=PEOffset/3600; // convert to degrees //PeOffset=PeOffset/15; // ra is in h:mm // Start by clearing the frame buffer memset(targetChip->getFrameBuffer(),0,targetChip->getFrameBufferSize()); // Spin up a set of plate constants that will relate // ra/dec of stars, to our fictitious ccd layout // to account for various rotations etc // we should spin up some plate constants here // then we can use these constants to rotate and offset // the standard co-ordinates on each star for drawing // a ccd frame; double pa,pb,pc,pd,pe,pf; // Since this is a simple ccd, correctly aligned // for now we cheat // no offset or rotation for and y axis means pb=0.0; pc=targetChip->getXRes()/2/targetChip->getBinX(); pd=0.0; pf=targetChip->getYRes()/2/targetChip->getBinY(); // and we do a simple scale for x and y locations // based on the focal length and pixel size // focal length in mm, pixels in microns pa=targetFocalLength/targetChip->getPixelSizeX()*1000/targetChip->getBinX(); pe=targetFocalLength/targetChip->getPixelSizeY()*1000/targetChip->getBinY(); //IDLog("Pixels are %4.2f %4.2f pa %6.4f pe %6.4f\n",PixelSizex,PixelSizey,pa,pe); // these numbers are now pixels per radian float Scalex; float Scaley; Scalex=pa*0.0174532925; // pixels per degree Scalex=Scalex/3600.0; // pixels per arcsecond Scalex=1.0/Scalex; // arcseconds per pixel Scaley=pe*0.0174532925; // pixels per degree Scaley=Scaley/3600.0; // pixels per arcsecond Scaley=1.0/Scaley; // arcseconds per pixel //qq=qq/3600; // arcseconds per pixel //IDLog("Pixel scale is %4.2f x %4.2f\n",Scalex,Scaley); ImageScalex=Scalex; ImageScaley=Scaley; // calc this now, we will use it a lot later rad=raPEC*15.0; rar=rad*0.0174532925; // offsetting the dec by the guide head offset float cameradec; cameradec=decPEC+OAGoffset/60; decr=cameradec*0.0174532925; //fprintf(stderr,"decPEC %7.5f cameradec %7.5f CenterOffsetDec %4.4f\n",decPEC,cameradec,CenterOffsetDec); // now lets calculate the radius we need to fetch float radius; radius=sqrt((Scalex*Scalex*targetChip->getXRes()/2.0*targetChip->getXRes()/2.0)+(Scaley*Scaley*targetChip->getYRes()/2.0*targetChip->getYRes()/2.0)); // we have radius in arcseconds now radius=radius/60; // convert to arcminutes //fprintf(stderr,"Lookup radius %4.2f\n",radius); //radius=radius*2; // A saturationmag star saturates in one second // and a limitingmag produces a one adu level in one second // solve for zero point and system gain k=(saturationmag-limitingmag)/((-2.5*log(maxval))-(-2.5*log(1.0/2.0))); z=saturationmag-k*(-2.5*log(maxval)); //z=z+saturationmag; //IDLog("K=%4.2f Z=%4.2f\n",k,z); // Should probably do some math here to figure out the dimmest // star we can see on this exposure // and only fetch to that magnitude // for now, just use the limiting mag number with some room to spare float lookuplimit; lookuplimit=limitingmag; lookuplimit=lookuplimit; if(radius > 60) lookuplimit=11; // if this is a light frame, we need a star field drawn if(targetChip->getFrameType()==CCDChip::LIGHT_FRAME) { //sprintf(gsccmd,"gsc -c %8.6f %+8.6f -r 120 -m 0 9.1",rad+PEOffset,decPEC); sprintf(gsccmd,"gsc -c %8.6f %+8.6f -r %4.1f -m 0 %4.2f -n 3000",rad+PEOffset,cameradec,radius,lookuplimit); //fprintf(stderr,"gsccmd %s\n",gsccmd); pp=popen(gsccmd,"r"); if(pp != NULL) { char line[256]; while(fgets(line,256,pp)!=NULL) { //fprintf(stderr,"%s",line); // ok, lets parse this line for specifcs we want char id[20]; char plate[6]; char ob[6]; float mag; float mage; float ra; float dec; float pose; int band; float dist; int dir; int c; int rc; rc=sscanf(line,"%10s %f %f %f %f %f %d %d %4s %2s %f %d", id,&ra,&dec,&pose,&mag,&mage,&band,&c,plate,ob,&dist,&dir); //fprintf(stderr,"Parsed %d items\n",rc); if(rc==12) { lines++; //if(c==0) { stars++; //fprintf(stderr,"%s %8.4f %8.4f %5.2f %5.2f %d\n",id,ra,dec,mag,dist,dir); // Convert the ra/dec to standard co-ordinates double sx; // standard co-ords double sy; // double srar; // star ra in radians double sdecr; // star dec in radians; double ccdx; double ccdy; //fprintf(stderr,"line %s",line); //fprintf(stderr,"parsed %6.5f %6.5f\n",ra,dec); srar=ra*0.0174532925; sdecr=dec*0.0174532925; // Handbook of astronomical image processing // page 253 // equations 9.1 and 9.2 // convert ra/dec to standard co-ordinates sx=cos(decr)*sin(srar-rar)/( cos(decr)*cos(sdecr)*cos(srar-rar)+sin(decr)*sin(sdecr) ); sy=(sin(decr)*cos(sdecr)*cos(srar-rar)-cos(decr)*sin(sdecr))/( cos(decr)*cos(sdecr)*cos(srar-rar)+sin(decr)*sin(sdecr) ); // now convert to microns ccdx=pa*sx+pb*sy+pc; ccdy=pd*sx+pe*sy+pf; rc=DrawImageStar(targetChip, mag,ccdx,ccdy); drawn+=rc; if(rc==1) { //fprintf(stderr,"star %s scope %6.4f %6.4f star %6.4f %6.4f ccd %6.2f %6.2f\n",id,rad,decPEC,ra,dec,ccdx,ccdy); //fprintf(stderr,"star %s ccd %6.2f %6.2f\n",id,ccdx,ccdy); } } } pclose(pp); } else { IDMessage(getDeviceName(),"Error looking up stars, is gsc installed with appropriate environment variables set ??"); //fprintf(stderr,"Error doing gsc lookup\n"); } if(drawn==0) { IDMessage(getDeviceName(),"Got no stars, is gsc installed with appropriate environment variables set ??"); } } //fprintf(stderr,"Got %d stars from %d lines drew %d\n",stars,lines,drawn); // now we need to add background sky glow, with vignetting // this is essentially the same math as drawing a dim star with // fwhm equivalent to the full field of view CCDChip::CCD_FRAME ftype = targetChip->getFrameType(); if((ftype==CCDChip::LIGHT_FRAME)||(ftype==CCDChip::FLAT_FRAME)) { float skyflux; float glow; // calculate flux from our zero point and gain values glow=skyglow; if(ftype==CCDChip::FLAT_FRAME) { // Assume flats are done with a diffuser // in broad daylight, so, the sky magnitude // is much brighter than at night glow=skyglow/10; } //fprintf(stderr,"Using glow %4.2f\n",glow); skyflux=pow(10,((glow-z)*k/-2.5)); // ok, flux represents one second now // scale up linearly for exposure time skyflux=skyflux*ExposureTime*targetChip->getBinX()*targetChip->getBinY(); //IDLog("SkyFlux = %g ExposureRequest %g\n",skyflux,ExposureTime); unsigned short *pt; int nwidth = targetChip->getXRes()/targetChip->getBinX(); int nheight = targetChip->getYRes()/targetChip->getBinY(); pt=(unsigned short int *)targetChip->getFrameBuffer(); for(int y=0; y< nheight; y++) { for(int x=0; x< nwidth; x++) { float dc; // distance from center float fp; // flux this pixel; float sx,sy; float vig; sx=targetChip->getXRes()/2/targetChip->getBinX(); sx=sx-x; sy=targetChip->getYRes()/2/targetChip->getBinY(); sy=sy-y; vig=targetChip->getXRes()/targetChip->getBinX(); vig=vig*ImageScalex; // need to make this account for actual pixel size dc=sqrt(sx*sx*ImageScalex*ImageScalex+sy*sy*ImageScaley*ImageScaley); // now we have the distance from center, in arcseconds // now lets plot a gaussian falloff to the edges // float fa; fa=exp(-2.0*0.7*(dc*dc)/vig/vig); // get the current value fp=pt[0]; // Add the sky glow fp+=skyflux; // now scale it for the vignetting fp=fa*fp; // clamp to limits if(fp > maxval) fp=maxval; if (fp > maxpix) maxpix = fp; if (fp < minpix) minpix = fp; // and put it back pt[0]=fp; pt++; } } } // Now we add some bias and read noise for(x=0; x<targetChip->getXRes(); x++) { for(y=0; y<targetChip->getYRes(); y++) { int noise; noise=random(); noise=noise%maxnoise; // //IDLog("noise is %d\n", noise); AddToPixel(targetChip, x,y,bias+noise); } } } else { testvalue++; if(testvalue > 255) testvalue=0; val=testvalue; int nbuf = targetChip->getXRes()*targetChip->getYRes(); for(int x=0; x<nbuf; x++) { *ptr=val++; ptr++; } } return 0; }