1 // ----------------------------------------------------------------------------
3 // ----------------------------------------------------------------------------
5 #include "BitMapObject.h"
7 // static void ConvertToVBPalette();
8 static long Get_ByteWidth();
9 static long Get_LineLength();
10 static void ReDimArrays();
12 // --- VERSION 1.0 CLASS
14 // --- MultiUse = -1 'True // True
15 // --- Persistable = 0 'NotPersistable // NotPersistable
16 // --- DataBindingBehavior = 0 'vbNone // vbNone
17 // --- DataSourceBehavior = 0 'vbNone // vbNone
18 // --- MTSTransactionMode = 0 'NotAnMTSObject // NotAnMTSObject
21 // static char *VB_Name = "BitMapObject";
22 // static boolean VB_GlobalNameSpace = False;
23 // static boolean VB_Creatable = True;
24 // static boolean VB_PredeclaredId = False;
25 // static boolean VB_Exposed = False;
27 // --- Option Explicit
29 // info von http://web.usxchange.net/elmo/bmp.htm
31 // A BMP file consists of the four following parts:
35 // 3.A color table of RGBQUAD structures (1, 4 & 8 bit only)
36 // 4.An array of bytes for the actual image data
40 // Declared an unsigned integer. But, this is just to reserve space for 2 bytes.
41 // The 2 bytes must be the 2 characters BM to indicate a BitMap file.
43 // Total size of file in bytes.
45 // Always zero (ignore).
47 // Always zero (ignore).
49 // Specifies the byte offset from the BITMAPFILEHEADER structure to the actual bitmap data in the file.
50 // ::: #ifndef HAS_BitmapFileHeaderType
51 // ::: typedef struct // { /* bmfh */
56 // ::: int bfReserved1;
57 // ::: int bfReserved2;
58 // ::: long bfOffBits;
59 // ::: } BitmapFileHeaderType;
60 // ::: #define HAS_BitmapFileHeaderType
65 // Size of BITMAPINFOHEADER structure (should always be 40).
67 // Width of image in pixels.
69 // Height of image in pixels.
71 // Always one (ignore).
73 // Specifies the number of bits per pixel. This value must be 1, 4, 8, or 24.
75 // Specifies the type of compression.
76 // 1.BI_RGB No compression.
77 // 2.BI_RLE8 8 bit RLE
78 // 3.BI_RLE4 4 bit RLE
80 // Specifies the size, in bytes, of the image data. May be zero if the bitmap is in the BI_RGB format.
86 // Specifies the number of color indices in the color table. Zero indicaes the bitmap uses the maximum number of colors corresponding to the value of the
87 // biBitCount member e.g. 8 bit -> 256 colors.
89 // The maximum number of colors = 2N. Where N = biBitCount. 2N is the same as 1 << N. The same as you can get powers of 10 by shifting the decimal point
90 // in a decimal number, only it is binary.
93 // ::: #ifndef HAS_BitmapInfoHeaderType
94 // ::: typedef struct // { /* bmih */
100 // ::: int biBitCount;
101 // ::: long biCompression;
102 // ::: long biSizeImage;
103 // ::: long biXPelsPerMeter;
104 // ::: long biYPelsPerMeter;
105 // ::: long biClrUsed;
106 // ::: long biClrImportant;
107 // ::: } BitmapInfoHeaderType;
108 // ::: #define HAS_BitmapInfoHeaderType
111 // 3.A color table of RGBQUAD structures (1, 4 & 8 bit only)
112 // RGBQUAD structure is self explanatory.
113 // ::: #ifndef HAS_RGBQUADType
114 // ::: typedef struct // { /* rgbq */
117 // ::: byte rgbGreen;
119 // ::: byte rgbReserved;
120 // ::: } RGBQUADType;
121 // ::: #define HAS_RGBQUADType
124 RGBQUADType *ColorTable;
127 // 4.An array of bytes for the actual image data
128 // Bits per pixel & compression determined by biBitCount & biCompression.
130 byte *ImageDataBytes;
132 // ######################################################################################################
134 BitmapFileHeaderType BMFH;
135 BitmapInfoHeaderType BMIH;
137 static long Get_LineLength()
139 static long LineLength;
141 LineLength = 4 * (((Get_ByteWidth() - 1) / 4) + 1);
146 static long Get_ByteWidth()
148 static long ByteWidth;
150 ByteWidth = BMIH.biWidth * BMIH.biBitCount / 8;
155 void BitMapObject_CreateAtSize(long XPixels, long YPixels, long BitsPerPixel)
158 BMIH.biWidth = XPixels;
159 BMIH.biHeight = YPixels;
161 BMIH.biBitCount = BitsPerPixel;
162 BMIH.biClrUsed = (1 << BMIH.biBitCount);
164 BMIH.biClrImportant = BMIH.biClrUsed;
165 BMIH.biCompression = 0;
168 BMFH.bfTypeB = 0x42; // B'
169 BMFH.bfTypeM = 0x4D; // M'
176 void BitMapObject_CreateFromFile(char *Path)
181 if (! FileExists(Path))
184 if (FileLen(Path) < (Len(BMFH) + Len(BMIH)))
187 FNum = fopen(Path, "rb");
188 FILE_GET(FNum, -1, &BMFH, sizeof(BMFH));
189 FILE_GET(FNum, -1, &BMIH, sizeof(BMIH));
192 if (BMIH.biCompression != 0)
194 Err.Raise(600, "BitMapObject", "Cannot read compressed BMP files");
199 if (BMIH.biBitCount < 9)
201 FILE_GET(FNum, -1, &ColorTable, sizeof(ColorTable));
205 FILE_GET(FNum, 1 + BMFH.bfOffBits, &ImageDataBytes, sizeof(ImageDataBytes));
207 if (BMIH.biBitCount < 9)
208 ConvertToVBPalette();
211 void BitMapObject_SaveToFile(char *Path)
215 BMFH.bfOffBits = Len(BMFH) + Len(BMIH);
216 if (BMIH.biBitCount < 9)
217 BMFH.bfOffBits = BMFH.bfOffBits + ((1 << BMIH.biBitCount)) * Len(ColorTable[0]);
219 BMIH.biSizeImage = Get_LineLength() * BMIH.biHeight;
220 BMFH.bfSize = BMFH.bfOffBits + BMIH.biSizeImage;
221 // FNum = FreeFile();
222 FNum = fopen(Path, "wb");
223 FILE_PUT(FNum, -1, &BMFH, sizeof(BMFH));
224 FILE_PUT(FNum, -1, &BMIH, sizeof(BMIH));
225 if (BMIH.biBitCount < 9)
227 FILE_PUT(FNum, -1, &ColorTable, sizeof(ColorTable));
230 FILE_PUT(FNum, -1, &ImageDataBytes, sizeof(ImageDataBytes));
234 static void ConvertToVBPalette()
238 ColMax = UBound(ColorTable);
239 for (i = 0; i <= ColMax; i++)
242 VBPalette[i] = RGB(ColorTable[i].rgbRed, ColorTable[i].rgbGreen, ColorTable[i].rgbBlue);
249 static void ReDimArrays()
252 if (BMIH.biBitCount < 9)
254 BMIH.biClrUsed = (1 << BMIH.biBitCount);
255 ColorTable = REDIM_1D(sizeof(RGBQUADType), 0, BMIH.biClrUsed - 1);
256 VBPalette = REDIM_1D(sizeof(long), 0, BMIH.biClrUsed - 1);
259 if (0 < Get_LineLength() && 0 < BMIH.biHeight)
261 ImageDataBytes = REDIM_2D(sizeof(byte), 0, Get_LineLength() - 1, 0, BMIH.biHeight - 1);
267 long BitMapObject_Get_Palette(long Index)
271 Palette = VBPalette[Index];
276 void BitMapObject_Let_Palette(long Index, long NewVal)
278 VBPalette[Index] = NewVal & 0xFFFFFF;
280 ColorTable[Index].rgbRed = (NewVal & 0xFF) / 0x1;
281 ColorTable[Index].rgbGreen = (NewVal & 0xFF00) / 0x100;
282 ColorTable[Index].rgbBlue = (NewVal & 0xFF0000) / 0x10000;
286 long BitMapObject_Get_ColorsUsed()
290 if (BMIH.biBitCount < 9)
292 ColorsUsed = (1 << BMIH.biBitCount);
304 long BitMapObject_Get_ColorIndex(long X, long Y)
308 long ColIndex, NewX, BitPos, nY;
310 if (8 < BMIH.biBitCount)
312 Err.Raise(600, "BitmapObject", "I have ! Palette in this ColorDepthMode");
317 nY = BMIH.biHeight - 1 - Y;
318 switch (BMIH.biBitCount)
321 ColIndex = ImageDataBytes[X / 8, nY];
322 BitPos = 7 - (X % 8);
323 NewX = (1 << BitPos);
324 if ((NewX && ColIndex) == 0)
336 ColIndex = ImageDataBytes[X / 2, nY];
339 ColorIndex = (ColIndex & 0xF0) / 0x10;
343 ColorIndex = (ColIndex & 0xF);
349 ColorIndex = ImageDataBytes[X, nY];
353 Err.Raise(600, "BitmapObject", "Invalid bpx value");
360 void BitMapObject_Let_ColorIndex(long X, long Y, long ColorIndex)
362 long ColIndex, ByteVal, NewX, BitPos, nY;
364 if (8 < BMIH.biBitCount)
366 Err.Raise(600, "BitmapObject", "I have ! Palette in this ColorDepthMode");
370 nY = BMIH.biHeight - 1 - Y;
371 switch (BMIH.biBitCount)
374 ByteVal = ImageDataBytes[X / 8, nY];
375 BitPos = 7 - (X % 8);
376 NewX = (1 << BitPos);
377 ColIndex = ColorIndex * NewX;
380 ByteVal = (ByteVal & (! NewX));
384 ByteVal = (ByteVal | NewX);
387 ImageDataBytes[X / 8, nY] = ByteVal;
391 ByteVal = ImageDataBytes[X / 2, nY];
394 ByteVal = (ByteVal & 0xF) + ColorIndex * 0x10;
398 ByteVal = (ByteVal & 0xF0) + ColorIndex;
401 ImageDataBytes[X / 2, nY] = ByteVal;
405 ImageDataBytes[X, nY] = ColorIndex;
409 Err.Raise(600, "BitmapObject", "Invalid bpx value");
414 long BitMapObject_Get_Point(long X, long Y)
418 long ColIndex, NewX, BitPos, nY;
420 nY = BMIH.biHeight - 1 - Y;
421 switch (BMIH.biBitCount)
424 ColIndex = ImageDataBytes[X / 8, nY];
425 BitPos = 7 - (X % 8);
426 NewX = (1 << BitPos);
427 if ((NewX && ColIndex) == 0)
436 Point = VBPalette[ColIndex];
440 ColIndex = ImageDataBytes[X / 2, nY];
443 ColIndex = (ColIndex & 0xF0) / 0x10;
447 ColIndex = (ColIndex & 0xF);
450 Point = VBPalette[ColIndex];
454 ColIndex = ImageDataBytes[X, nY];
455 Point = VBPalette[ColIndex];
460 Point = ImageDataBytes[NewX, nY] * 0x10000;
461 Point = Point + ImageDataBytes[NewX + 1, nY] * 0x100;
462 Point = Point + ImageDataBytes[NewX + 2, nY];
466 Err.Raise(600, "BitmapObject", "Invalid bpx value");
473 void BitMapObject_Let_Point(long X, long Y, long NewColor)
475 long ColIndex, ByteVal, NewX, BitPos, nY;
477 nY = BMIH.biHeight - 1 - Y;
478 switch (BMIH.biBitCount)
481 ColIndex = GetPaletteIndex(NewColor);
482 ByteVal = ImageDataBytes[X / 8][nY];
483 BitPos = 7 - (X % 8);
484 NewX = (1 << BitPos);
485 ColIndex = ColIndex * NewX;
488 ByteVal = (ByteVal & (! NewX));
492 ByteVal = (ByteVal | NewX);
495 ImageDataBytes[X / 8][nY] = ByteVal;
499 ColIndex = GetPaletteIndex(NewColor);
500 ByteVal = ImageDataBytes[X / 2][nY];
503 ByteVal = (ByteVal & 0xF) + ColIndex * 0x10;
507 ByteVal = (ByteVal & 0xF0) + ColIndex;
510 ImageDataBytes[X / 2][nY] = ByteVal;
514 ImageDataBytes[X][nY] = GetPaletteIndex(NewColor);
519 ImageDataBytes[NewX][nY] = (NewColor & 0xFF0000) / 0x10000; // B
520 ImageDataBytes[NewX + 1][nY] = (NewColor & 0xFF00) / 0x100; // G
521 ImageDataBytes[NewX + 2][nY] = (NewColor & 0xFF); // R
525 Err.Raise(600, "BitmapObject", "Invalid bpx value");
530 int BitMapObject_GetPaletteIndex(long Color)
536 ColMax = UBound(VBPalette);
537 for (i = 0; i <= ColMax; i++)
539 if (VBPalette[i] == Color)
543 if (ColMax < i) // Error - Color not in Palette!
548 return GetPaletteIndex;
553 long BitMapObject_Get_Width()
557 Width = BMIH.biWidth;
562 long BitMapObject_Get_Height()
566 Height = BMIH.biHeight;
573 BitMapObject BitMapObject_GetStretchCopy(float StretchVal)
575 BitMapObject GetStretchCopy;
577 long nWidth, nHeight, iX, iY;
579 // GetStretchCopy = New BitMapObject; // (handle this later, if needed)
580 nWidth = StretchVal * BMIH.biWidth;
581 nHeight = StretchVal * BMIH.biHeight;
582 GetStretchCopy.CreateAtSize(nWidth, nHeight, CLng(BMIH.biBitCount));
584 nHeight = nHeight - 1;
585 for (iX = 0; iX <= BMIH.biClrUsed - 1; iX++)
587 GetStretchCopy.Let_Palette(iX, Palette(iX));
590 for (iY = 0; iY <= nHeight; iY++)
592 for (iX = 0; iX <= nWidth; iX++)
594 GetStretchCopy.Let_ColorIndex(iX, iY, ColorIndex((int)(iX / StretchVal), (int)(iY / StretchVal)));
598 return GetStretchCopy;