2 // source code for the BMGLib Utility functions
4 // Copyright (C) 2001 M. Scott Heiman
7 // You may use the software for any purpose you see fit. You may modify
8 // it, incorporate it in a commercial application, use it for school,
9 // even turn it in as homework. You must keep the Copyright in the
10 // header and source files. This software is not in the "Public Domain".
11 // You may use this software at your own risk. I have made a reasonable
12 // effort to verify that this software works in the manner I expect it to;
15 // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND
16 // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING
17 // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A
18 // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO
19 // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR
20 // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING
21 // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE,
22 // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS
23 // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
24 // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
25 // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
35 /* error strings for all BMG errors */
36 static char BMGErrorStrings[17][128] = {
38 "Corrupted file or invalid file format",
39 "Invalid bits per pixel for this file format",
40 "Memory allocation error",
41 "Invalid requested image size",
42 "Invalid bitmap handle",
43 "Windows API Error", /* this will be overwritten */
44 "Unable to open file",
45 "Unsupported file format option",
46 "Invalid pointer to a BMG image",
47 "Unsupported file extension",
49 "Error writing to the output file",
50 "Invalid pointer to a GeoTIFF structure",
51 "The background image is undefined",
52 "The background image is too small",
56 /* stores last BMG error */
57 static BMGError LastBMGError;
59 /* sets the last BMG error */
60 void SetLastBMGError( BMGError err )
65 /* returns the last error state */
66 BMGError GetLastBMGError(void)
70 /* gets the error message */
71 void GetLastBMGErrorMessage( const char **msg )
73 if ( LastBMGError == errWindowsAPI )
75 char* lpMsgBuf = "Erreur BMG\n";
77 /* copy the string. */
78 strcpy( BMGErrorStrings[(int)LastBMGError], (char *)lpMsgBuf );
81 *msg = BMGErrorStrings[(int)LastBMGError];
84 /* Global background color variables */
85 static unsigned char BackgroundColor[4];
86 static struct BMGImageStruct BackgroundImage;
88 /* this function simply initializes the background info. It is called from
89 the DllEntryPoint function */
90 void InitBackground(void)
92 memset( (void *)BackgroundColor, 0xFF, 3 ); /* white */
93 BackgroundColor[3] = 0; /* ignored */
94 InitBMGImage( &BackgroundImage );
97 unsigned char *GetBackgroundColor(void)
99 return &BackgroundColor[0];
102 struct BMGImageStruct *GetBackgroundImage(void)
104 return &BackgroundImage;
107 /* converts an array of 1-bit scanlines to 8-bit scanlines */
108 void Convert1to8( struct BMGImageStruct img,
111 unsigned char *p, *q, *r, *s, *end;
116 for ( s = img.bits; s < img.bits + img.scan_width * img.height;
117 s += img.scan_width, q += img.width )
120 end = q + img.width - i;
122 for ( r = q; r < end; p++ )
124 *r++ = (unsigned char)((*p & 0x80) ? 1 : 0);
125 *r++ = (unsigned char)((*p & 0x40) ? 1 : 0);
126 *r++ = (unsigned char)((*p & 0x20) ? 1 : 0);
127 *r++ = (unsigned char)((*p & 0x10) ? 1 : 0);
128 *r++ = (unsigned char)((*p & 0x08) ? 1 : 0);
129 *r++ = (unsigned char)((*p & 0x04) ? 1 : 0);
130 *r++ = (unsigned char)((*p & 0x02) ? 1 : 0);
131 *r++ = (unsigned char)(*p & 0x01);
136 *r++ = (unsigned char)((*p & 0x80) ? 1 : 0);
139 *r++ = (unsigned char)((*p & 0x40) ? 1 : 0);
142 *r++ = (unsigned char)((*p & 0x20) ? 1 : 0);
145 *r++ = (unsigned char)((*p & 0x10) ? 1 : 0);
148 *r++ = (unsigned char)((*p & 0x08) ? 1 : 0);
151 *r++ = (unsigned char)((*p & 0x04) ? 1 : 0);
153 *r = (unsigned char)((*p & 0x02) ? 1:0);
163 /* converts an array of 4-bit scanlines to 8-bit scanlines */
164 void Convert4to8( struct BMGImageStruct img,
167 unsigned char *p, *q, *r, *s, *end;
172 for ( s = img.bits; s < img.bits + img.scan_width * img.height;
173 s += img.scan_width, q += img.width )
176 end = q + img.width - i;
178 for ( r = q; r < end; p++ )
180 *r++ = (unsigned char)((*p >> 4) & 0x0F);
181 *r++ = (unsigned char)(*p & 0x0F);
185 *r = (unsigned char)((*p >> 4) & 0x0F);
189 /****************************************************************************/
190 /* this function performs alpha blending. It is a variation of a function
191 that I found in the PNG example code */
192 unsigned char AlphaComp( unsigned char fg,
208 temp = ((unsigned short)(fg)*(unsigned short)(alpha) +
209 (unsigned short)(bg)*(unsigned short)(255 -
210 (unsigned short)(alpha)) + (unsigned short)128);
211 out = (unsigned char)((temp + (temp >> 8)) >> 8);
217 /****************************************************************************
218 // Converts a 16 BPP image to a 24 BPP image
219 // returns 1 if successfull, 0 otherwise */
220 BMGError Convert16to24( struct BMGImageStruct *img )
223 unsigned int new_scan_width;
224 unsigned char *new_bits;
226 /* this function will only work with 16 BBP images */
227 if ( img->bits_per_pixel != 16 )
228 return errInvalidPixelFormat;
230 /* calculate the new scan width */
231 new_scan_width = 3 * img->width;
232 if ( new_scan_width % 4 && img->opt_for_bmp )
233 new_scan_width += 4 - new_scan_width % 4;
235 /* allocate memory for the new pixel values */
236 new_bits = (unsigned char *)calloc( new_scan_width * img->height, sizeof(unsigned char) );
237 if ( new_bits == NULL )
238 return errMemoryAllocation;
240 /* convert the 16 BPP pixel values to the equivalent 24 BPP values */
241 for ( i = 0; i < img->height; i++ )
244 unsigned short *p16 = (unsigned short *)(img->bits + i * img->scan_width);
245 unsigned char *start = new_bits + i * new_scan_width;
246 unsigned char *end = start + new_scan_width;
247 for ( p24 = start; p24 < end; p24 += 3, p16++ )
249 p24[0] = (unsigned char)( (*p16 & 0x001F) << 3 );
250 p24[1] = (unsigned char)( (*p16 & 0x03E0) >> 2 );
251 p24[2] = (unsigned char)( (*p16 & 0x7C00) >> 7 );
256 img->bits = new_bits;
257 img->scan_width = new_scan_width;
258 img->bits_per_pixel = 24;
263 /****************************************************************************/
264 /* this function undoes alpha blending - kind-a-sort-of ;-) */
265 unsigned char InverseAlphaComp( unsigned char fg, unsigned char alpha,
280 temp = (255*fg - bg*(255-alpha))/alpha;
283 out = (unsigned char)temp;
289 /****************************************************************************/
291 // Creates a BITMAPINFOHEADER for the given width, height, bit count, and
292 // compression. Compression must = BI_RGB, BI_BITFIELDS, BI_RLE4, or BI_RLE8.
294 BITMAPINFO InternalCreateBMI( unsigned int dwWidth, /* width */
295 unsigned int dwHeight, /* height */
296 unsigned short wBitCount, /* bit count */
297 int compression ) /* compression type */
299 BITMAPINFO bi; /* bitmap header */
300 unsigned int dwBytesPerLine; /* Number of bytes per scanline */
302 /* clear the bitmapinfo structure */
303 memset(&bi, 0, sizeof(BITMAPINFO));
305 /* Make sure bits per pixel is valid */
308 else if (wBitCount <= 4)
310 else if (wBitCount <= 8)
312 else if (wBitCount <= 16)
314 else if (wBitCount <= 24)
316 else if (wBitCount <= 32)
319 wBitCount = 8; /* set default value to 8 if parameter is bogus */
321 dwBytesPerLine = (((wBitCount * dwWidth) + 31) / 32 * 4);
323 /* initialize BITMAPINFO */
324 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
325 bi.bmiHeader.biWidth = dwWidth;
326 bi.bmiHeader.biHeight = dwHeight;
327 bi.bmiHeader.biPlanes = 1; /* must be 1 */
328 bi.bmiHeader.biBitCount = wBitCount;
329 bi.bmiHeader.biCompression = compression;
330 bi.bmiHeader.biSizeImage = dwBytesPerLine*dwHeight;
331 bi.bmiHeader.biXPelsPerMeter = 0;
332 bi.bmiHeader.biYPelsPerMeter = 0;
333 bi.bmiHeader.biClrUsed = wBitCount <= 8 ? 1U << wBitCount : 0;
334 bi.bmiHeader.biClrImportant = bi.bmiHeader.biClrUsed;
339 short SwapShort( short in )
344 memcpy( (char *)sin, (char *)&in, 2 );
349 return *((short *)sout);
352 unsigned short SwapUShort( unsigned short in )
357 memcpy( (char *)sin, (char *)&in, 2 );
362 return *((unsigned short *)sout);
365 int SwapLong( int in )
370 memcpy( (char *)sin, (char *)&in, 4 );
377 return *((int *)sout);
380 unsigned int SwapULong( unsigned int in )
385 memcpy( (char *)sin, (char *)&in, 4 );
392 return *((unsigned int *)sout);