#include #include #include #include #include "paulslib.h" #include "bitmaplib.h" //#define TGA_READ_USE_FREAD TRUE /* Create a bitmap structure */ BITMAP4 *Create_Bitmap(int nx,int ny) { return((BITMAP4 *)malloc(nx*ny*sizeof(BITMAP4))); } /* Destroy the bitmap structure */ void Destroy_Bitmap(BITMAP4 *bm) { free(bm); } /* Compare two pixels */ int Same_BitmapPixel(BITMAP4 p1,BITMAP4 p2) { if (p1.r != p2.r) return(FALSE); if (p1.g != p2.g) return(FALSE); if (p1.b != p2.b) return(FALSE); if (p1.a != p2.a) return(FALSE); return(TRUE); } /* Write a bitmap to a file The format is as follows 1 == tga 11 == tga with alpha 12 == compressed tga 13 == compressed tga with alpha 2 == ppm 3 == rgb 4 == raw grey scale 5 == tiff 6 == EPS colour (Encapsulated PostScript) 7 == EPS black and white 8 == raw 9 == BMP A negative format indicates a vertical flip */ void Write_Bitmap(FILE *fptr,BITMAP4 *bm,int nx,int ny,int format) { int i,j,offset; long index,rowindex; int linelength = 0,size; char buffer[1024]; /* Write the header */ switch (ABS(format)) { case 1: case 11: case 12: case 13: putc(0,fptr); /* Length of ID */ putc(0,fptr); /* No colour map */ if (ABS(format) == 12 || ABS(format) == 13) putc(10,fptr); /* compressed RGB */ else putc(2,fptr); /* uncompressed RGB */ putc(0,fptr); /* Index of colour map entry */ putc(0,fptr); putc(0,fptr); /* Colour map length */ putc(0,fptr); putc(0,fptr); /* Colour map size */ putc(0,fptr); /* X origin */ putc(0,fptr); putc(0,fptr); /* Y origin */ putc(0,fptr); putc((nx & 0x00ff),fptr); /* X width */ putc((nx & 0xff00) / 256,fptr); putc((ny & 0x00ff),fptr); /* Y width */ putc((ny & 0xff00) / 256,fptr); if (ABS(format) == 11 || ABS(format) == 13) { putc(32,fptr); /* 32 bit bitmap */ putc(0x08,fptr); } else { putc(24,fptr); /* 24 bit bitmap */ putc(0x00,fptr); } break; case 2: fprintf(fptr,"P6\n%d %d\n255\n",nx,ny); break; case 3: putc(0x01,fptr); putc(0xda,fptr); putc(0x00,fptr); putc(0x01,fptr); putc(0x00,fptr); putc(0x03,fptr); putc((nx & 0xFF00) / 256,fptr); putc((nx & 0x00FF),fptr); putc((ny & 0xFF00) / 256,fptr); putc((ny & 0x00FF),fptr); BM_WriteHexString(fptr,"000300000000000000ff00000000"); fprintf(fptr,"WriteBitmap, pdb"); putc(0x00,fptr); putc(0x00,fptr); putc(0x00,fptr); putc(0x00,fptr); putc(0x00,fptr); putc(0x00,fptr); putc(0x00,fptr); putc(0x00,fptr); break; case 4: break; case 5: BM_WriteHexString(fptr,"4d4d002a"); /* Little endian & TIFF identifier */ offset = nx * ny * 3 + 8; BM_WriteLongInt(fptr,buffer,offset); break; case 6: fprintf(fptr,"%%!PS-Adobe-3.0 EPSF-3.0\n"); fprintf(fptr,"%%%%Creator: Created from bitmaplib by Paul Bourke\n"); fprintf(fptr,"%%%%BoundingBox: %d %d %d %d\n",0,0,nx,ny); fprintf(fptr,"%%%%LanguageLevel: 2\n"); fprintf(fptr,"%%%%Pages: 1\n"); fprintf(fptr,"%%%%DocumentData: Clean7Bit\n"); fprintf(fptr,"%d %d scale\n",nx,ny); fprintf(fptr,"%d %d 8 [%d 0 0 -%d 0 %d]\n",nx,ny,nx,ny,ny); fprintf(fptr,"{currentfile 3 %d mul string readhexstring pop} bind\n",nx); fprintf(fptr,"false 3 colorimage\n"); break; case 7: fprintf(fptr,"%%!PS-Adobe-3.0 EPSF-3.0\n"); fprintf(fptr,"%%%%Creator: Created from bitmaplib by Paul Bourke\n"); fprintf(fptr,"%%%%BoundingBox: %d %d %d %d\n",0,0,nx,ny); fprintf(fptr,"%%%%LanguageLevel: 2\n"); fprintf(fptr,"%%%%Pages: 1\n"); fprintf(fptr,"%%%%DocumentData: Clean7Bit\n"); fprintf(fptr,"%d %d scale\n",nx,ny); fprintf(fptr,"%d %d 8 [%d 0 0 -%d 0 %d]\n",nx,ny,nx,ny,ny); fprintf(fptr,"{currentfile %d string readhexstring pop} bind\n",nx); fprintf(fptr,"false 1 colorimage\n"); break; case 8: break; case 9: /* Header 10 bytes */ putc('B',fptr); putc('M',fptr); size = nx * ny * 3 + 14 + 40; putc((size) % 256,fptr); putc((size / 256) % 256,fptr); putc((size / 65536) % 256,fptr); putc((size / 16777216),fptr); putc(0,fptr); putc(0,fptr); putc(0,fptr); putc(0,fptr); /* Offset to image data */ putc(14+40,fptr); putc(0,fptr); putc(0,fptr); putc(0,fptr); /* Information header 40 bytes */ putc(0x28,fptr); putc(0,fptr); putc(0,fptr); putc(0,fptr); putc((nx) % 256,fptr); putc((nx / 256) % 256,fptr); putc((nx / 65536) % 256,fptr); putc((nx / 16777216),fptr); putc((ny) % 256,fptr); putc((ny / 256) % 256,fptr); putc((ny / 65536) % 256,fptr); putc((ny / 16777216),fptr); putc(1,fptr); putc(0,fptr); /* One plane */ putc(24,fptr); putc(0,fptr); /* 24 bits */ /* Compression type == 0 */ putc(0,fptr); putc(0,fptr); putc(0,fptr); putc(0,fptr); size = nx * ny * 3; putc((size) % 256,fptr); putc((size / 256) % 256,fptr); putc((size / 65536) % 256,fptr); putc((size / 16777216),fptr); putc(1,fptr); putc(0,fptr); putc(0,fptr); putc(0,fptr); putc(1,fptr); putc(0,fptr); putc(0,fptr); putc(0,fptr); putc(0,fptr); putc(0,fptr); putc(0,fptr); putc(0,fptr); /* No palette */ putc(0,fptr); putc(0,fptr); putc(0,fptr); putc(0,fptr); break; } /* Write the binary data */ for (j=0;j 0) rowindex = j * nx; else rowindex = (ny - 1 - j) * nx; switch (ABS(format)) { case 12: WriteTGACompressedRow(fptr,&(bm[rowindex]),nx,3); break; case 13: WriteTGACompressedRow(fptr,&(bm[rowindex]),nx,4); break; } for (i=0;i 0) index = rowindex + i; else index = rowindex + i; switch (ABS(format)) { case 1: case 11: case 9: putc(bm[index].b,fptr); putc(bm[index].g,fptr); putc(bm[index].r,fptr); if (ABS(format) == 11) putc(bm[index].a,fptr); break; case 2: case 3: case 5: case 8: putc(bm[index].r,fptr); putc(bm[index].g,fptr); putc(bm[index].b,fptr); break; case 4: putc((bm[index].r+bm[index].g+bm[index].b)/3,fptr); break; case 6: fprintf(fptr,"%02x%02x%02x",bm[index].r,bm[index].g,bm[index].b); linelength += 6; if (linelength >= 72 || linelength >= nx) { fprintf(fptr,"\n"); linelength = 0; } break; case 7: fprintf(fptr,"%02x",(bm[index].r+bm[index].g+bm[index].b)/3); linelength += 2; if (linelength >= 72 || linelength >= nx) { fprintf(fptr,"\n"); linelength = 0; } break; } } } /* Write the footer */ switch (ABS(format)) { case 1: case 11: case 12: case 13: case 2: case 3: case 4: break; case 5: putc(0x00,fptr); /* The number of directory entries (14) */ putc(0x0e,fptr); /* Width tag, short int */ BM_WriteHexString(fptr,"0100000300000001"); putc((nx & 0xff00) / 256,fptr); /* Image width */ putc((nx & 0x00ff),fptr); putc(0x00,fptr); putc(0x00,fptr); /* Height tag, short int */ BM_WriteHexString(fptr,"0101000300000001"); putc((ny & 0xff00) / 256,fptr); /* Image height */ putc((ny & 0x00ff),fptr); putc(0x00,fptr); putc(0x00,fptr); /* bits per sample tag, short int */ BM_WriteHexString(fptr,"0102000300000003"); offset = nx * ny * 3 + 182; BM_WriteLongInt(fptr,buffer,offset); /* Compression flag, short int */ BM_WriteHexString(fptr,"010300030000000100010000"); /* Photometric interpolation tag, short int */ BM_WriteHexString(fptr,"010600030000000100020000"); /* Strip offset tag, long int */ BM_WriteHexString(fptr,"011100040000000100000008"); /* Orientation flag, short int */ BM_WriteHexString(fptr,"011200030000000100010000"); /* Sample per pixel tag, short int */ BM_WriteHexString(fptr,"011500030000000100030000"); /* Rows per strip tag, short int */ BM_WriteHexString(fptr,"0116000300000001"); putc((ny & 0xff00) / 256,fptr); putc((ny & 0x00ff),fptr); putc(0x00,fptr); putc(0x00,fptr); /* Strip byte count flag, long int */ BM_WriteHexString(fptr,"0117000400000001"); offset = nx * ny * 3; BM_WriteLongInt(fptr,buffer,offset); /* Minimum sample value flag, short int */ BM_WriteHexString(fptr,"0118000300000003"); offset = nx * ny * 3 + 188; BM_WriteLongInt(fptr,buffer,offset); /* Maximum sample value tag, short int */ BM_WriteHexString(fptr,"0119000300000003"); offset = nx * ny * 3 + 194; BM_WriteLongInt(fptr,buffer,offset); /* Planar configuration tag, short int */ BM_WriteHexString(fptr,"011c00030000000100010000"); /* Sample format tag, short int */ BM_WriteHexString(fptr,"0153000300000003"); offset = nx * ny * 3 + 200; BM_WriteLongInt(fptr,buffer,offset); /* End of the directory entry */ BM_WriteHexString(fptr,"00000000"); /* Bits for each colour channel */ BM_WriteHexString(fptr,"000800080008"); /* Minimum value for each component */ BM_WriteHexString(fptr,"000000000000"); /* Maximum value per channel */ BM_WriteHexString(fptr,"00ff00ff00ff"); /* Samples per pixel for each channel */ BM_WriteHexString(fptr,"000100010001"); break; case 6: case 7: fprintf(fptr,"\n%%%%EOF\n"); break; case 8: case 9: break; } } /* Write a compressed TGA row Depth is either 3 or 4 */ void WriteTGACompressedRow(FILE *fptr,BITMAP4 *bm,int width,int depth) { int i; int counter = 1; int pixelstart = 0; int packettype = 0; int readytowrite = FALSE; BITMAP4 currentpixel,nextpixel = {0,0,0,0}; currentpixel = bm[0]; for (;;) { if (pixelstart+counter >= width) // Added April to fix strange bug readytowrite = TRUE; else nextpixel = bm[pixelstart+counter]; if (!readytowrite) { if (Same_BitmapPixel(currentpixel,nextpixel)) { if (packettype == 0) { counter++; if (counter >= 128 || (pixelstart + counter) >= width) readytowrite = TRUE; } else { counter--; readytowrite = TRUE; } } else { if (packettype == 1 || counter <= 1) { packettype = 1; currentpixel = nextpixel; counter++; if (counter >= 128 || (pixelstart + counter) >= width) readytowrite = TRUE; } else { readytowrite = TRUE; } } } if (readytowrite) { if (pixelstart + counter > width) counter = width - pixelstart; if (packettype == 0) { putc(((counter-1) | 0x80),fptr); putc(currentpixel.b,fptr); putc(currentpixel.g,fptr); putc(currentpixel.r,fptr); if (depth == 4) putc(currentpixel.a,fptr); currentpixel = nextpixel; } else { putc(counter-1,fptr); for (i=0;i= width) break; /* From for (;;) */ readytowrite = FALSE; packettype = 0; counter = 1; } } } void BM_WriteLongInt(FILE *fptr,char *s,long n) { int i; s[0] = (n & 0xff000000) / 16777216; s[1] = (n & 0x00ff0000) / 65536; s[2] = (n & 0x0000ff00) / 256; s[3] = (n & 0x000000ff); for (i=0;i<4;i++) putc(s[i],fptr); } void BM_WriteHexString(FILE *fptr,char *s) { unsigned int i; int c; char hex[3]; for (i=0;i= nx) ii = nx-1; if (jj < 0) jj = 0; if (jj >= ny) jj = ny-1; index = jj * nx + ii; weight = BiCubicR(m-dx) * BiCubicR(n-dy); // weight = BiCubicR(m-dx) * BiCubicR(dy-n); red += weight * bm_in[index].r; green += weight * bm_in[index].g; blue += weight * bm_in[index].b; alpha += weight * bm_in[index].a; } } col.r = (int)red; col.g = (int)green; col.b = (int)blue; col.a = (int)alpha; bm_out[j_out * nnx + i_out] = col; } } } double BiCubicR(double x) { double xp2,xp1,xm1; double r = 0; xp2 = x + 2; xp1 = x + 1; xm1 = x - 1; if (xp2 > 0) r += xp2 * xp2 * xp2; if (xp1 > 0) r -= 4 * xp1 * xp1 * xp1; if (x > 0) r += 6 * x * x * x; if (xm1 > 0) r -= 4 * xm1 * xm1 * xm1; return(r / 6.0); } /* Scale a bitmap Apply a gaussian radial average if r > 0 r is in units of the input image */ void GaussianScale( BITMAP4 *bm_in,int nx,int ny, BITMAP4 *bm_out,int nnx,int nny,double r) { int i,j,ii,jj,ci,cj; long index; double x,y,cx,cy,red,green,blue,alpha,dist2,r2,weight,sum; BITMAP4 col,black = {0,0,0,255}; r2 = r*r; for (i=0;i= nx) ii = nx-1;; if (jj < 0) jj = 0; if (jj >= ny) jj = ny-1; dist2 = (cx-x)*(cx-x) + (cy-y)*(cy-y); weight = exp(-0.5*dist2/r2) / (r2*TWOPI); index = jj * nx + ii; red += weight * bm_in[index].r; green += weight * bm_in[index].g; blue += weight * bm_in[index].b; alpha += weight * bm_in[index].a; sum += weight; } } col.r = (int)red; col.g = (int)green; col.b = (int)blue; col.a = (int)alpha; } bm_out[j * nnx + i] = col; } } } /* Turn on a pixel of a bitmap */ int Draw_Pixel(BITMAP4 *bm, int nx, int ny, int x, int y, BITMAP4 col) { long index; if (x < 0 || y < 0 || x >= nx || y >= ny) return(FALSE); index = y * nx + x; bm[index] = col; return(TRUE); } /* Return the value of a pixel */ BITMAP4 Get_Pixel(BITMAP4 *bm, int nx, int ny, int x, int y) { long index; BITMAP4 black = {0,0,0,255}; if (x < 0 || y < 0 || x >= nx || y >= ny) return(black); index = y * nx + x; return(bm[index]); } /* Draw a line from (x1,y1) to (x2,y2) Use colour col */ void Draw_Line(BITMAP4 *bm,int nx,int ny,int x1,int y1,int x2,int y2,BITMAP4 col) { int i,j; long index; double mu,dx,dy,dxy; dx = x2 - x1; dy = y2 - y1; dxy = sqrt(dx*dx + dy*dy); if (dxy <= 0) { Draw_Pixel(bm,nx,ny,x1,y1,col); return; } for (mu=0;mu<=2*dxy;mu++) { i = (int)(x1 + 0.5 * mu * dx / dxy); j = (int)(y1 + 0.5 * mu * dy / dxy); if (i < 0 || j < 0 || i >= nx || j >= ny) continue; index = j * nx + i; bm[index] = col; } } /* Scale a RGB value, dealing with clipping issues */ BITMAP4 Scale_Pixel(BITMAP4 pixelin,double scale) { BITMAP4 pixelout; double r,g,b,a=0; r = pixelin.r * scale; g = pixelin.g * scale; b = pixelin.b * scale; a = pixelin.a * scale; if (r < 000) r = 0; if (r > 255) r = 255; if (g < 000) g = 0; if (g > 255) g = 255; if (b < 000) b = 0; if (b > 255) b = 255; if (a < 000) a = 0; if (a > 255) a = 255; pixelout.r = (int)r; pixelout.g = (int)g; pixelout.b = (int)b; pixelout.a = (int)a; return(pixelout); } /* Flip an image about an axis mode == 0 for horizontal mode == 1 for vertical This library assumes the (0,0) coordinate is top left */ void Flip_Bitmap(BITMAP4 *image,int width,int height,int mode) { int i,j; long index1,index2; BITMAP4 p; switch (mode) { case 0: for (j=0;j= header.colourmaplength) index = header.colourmaplength-1; image[n] = ctable[index]; n++; } else if (header.datatypecode == 2) { /* RGB Uncompressed */ #ifdef TGA_READ_USE_FREAD for (k=0;kr = p[2]; pixel->g = p[1]; pixel->b = p[0]; pixel->a = p[3]; } else if (bytes == 3) { pixel->r = p[2]; pixel->g = p[1]; pixel->b = p[0]; pixel->a = 255; } else if (bytes == 2) { pixel->r = (p[1] & 0x7c) << 1; pixel->g = ((p[1] & 0x03) << 6) | ((p[0] & 0xe0) >> 2); pixel->b = (p[0] & 0x1f) << 3; pixel->a = (p[1] & 0x80); } else if (bytes == 1) { pixel->r = p[0]; pixel->g = p[0]; pixel->b = p[0]; pixel->a = 255; } } BITMAP4 YUV_to_Bitmap(int y,int u,int v) { int r,g,b; BITMAP4 bm = {0,0,0,0}; // u and v are +-0.5 u -= 128; v -= 128; r = y + 1.370705 * v; g = y - 0.698001 * v - 0.337633 * u; b = y + 1.732446 * u; /* r = y + 1.402 * v; g = y - 0.344 * u - 0.714 * v; b = y + 1.772 * u; */ /* y -= 16; r = 1.164 * y + 1.596 * v; g = 1.164 * y - 0.392 * u - 0.813 * v; b = 1.164 * y + 2.017 * u; */ if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0; if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; bm.r = r; bm.g = g; bm.b = b; bm.a = 0; return(bm); }