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;
26 // --- Option Explicit
28 // info von http://web.usxchange.net/elmo/bmp.htm
30 // A BMP file consists of the four following parts:
34 // 3.A color table of RGBQUAD structures (1, 4 & 8 bit only)
35 // 4.An array of bytes for the actual image data
39 // Declared an unsigned integer. But, this is just to reserve space for 2 bytes.
40 // The 2 bytes must be the 2 characters BM to indicate a BitMap file.
42 // Total size of file in bytes.
44 // Always zero (ignore).
46 // Always zero (ignore).
48 // Specifies the byte offset from the BITMAPFILEHEADER structure to the actual bitmap data in the file.
49 // ::: #ifndef HAS_BitmapFileHeaderType
50 // ::: typedef struct // { /* bmfh */
55 // ::: int bfReserved1;
56 // ::: int bfReserved2;
57 // ::: long bfOffBits;
58 // ::: } BitmapFileHeaderType;
59 // ::: #define HAS_BitmapFileHeaderType
64 // Size of BITMAPINFOHEADER structure (should always be 40).
66 // Width of image in pixels.
68 // Height of image in pixels.
70 // Always one (ignore).
72 // Specifies the number of bits per pixel. This value must be 1, 4, 8, or 24.
74 // Specifies the type of compression.
75 // 1.BI_RGB No compression.
76 // 2.BI_RLE8 8 bit RLE
77 // 3.BI_RLE4 4 bit RLE
79 // Specifies the size, in bytes, of the image data. May be zero if the bitmap is in the BI_RGB format.
85 // 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
86 // biBitCount member e.g. 8 bit -> 256 colors.
88 // 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
89 // in a decimal number, only it is binary.
92 // ::: #ifndef HAS_BitmapInfoHeaderType
93 // ::: typedef struct // { /* bmih */
99 // ::: int biBitCount;
100 // ::: long biCompression;
101 // ::: long biSizeImage;
102 // ::: long biXPelsPerMeter;
103 // ::: long biYPelsPerMeter;
104 // ::: long biClrUsed;
105 // ::: long biClrImportant;
106 // ::: } BitmapInfoHeaderType;
107 // ::: #define HAS_BitmapInfoHeaderType
110 // 3.A color table of RGBQUAD structures (1, 4 & 8 bit only)
111 // RGBQUAD structure is self explanatory.
112 // ::: #ifndef HAS_RGBQUADType
113 // ::: typedef struct // { /* rgbq */
116 // ::: byte rgbGreen;
118 // ::: byte rgbReserved;
119 // ::: } RGBQUADType;
120 // ::: #define HAS_RGBQUADType
123 RGBQUADType *ColorTable;
126 // 4.An array of bytes for the actual image data
127 // Bits per pixel & compression determined by biBitCount & biCompression.
129 byte *ImageDataBytes;
131 // ######################################################################################################
133 BitmapFileHeaderType BMFH;
134 BitmapInfoHeaderType BMIH;
136 static long Get_LineLength()
138 static long LineLength;
140 LineLength = 4 * (((Get_ByteWidth() - 1) / 4) + 1);
145 static long Get_ByteWidth()
147 static long ByteWidth;
149 ByteWidth = BMIH.biWidth * BMIH.biBitCount / 8;
154 void BitMapObject_CreateAtSize(long XPixels, long YPixels, long BitsPerPixel)
157 BMIH.biWidth = XPixels;
158 BMIH.biHeight = YPixels;
160 BMIH.biBitCount = BitsPerPixel;
161 BMIH.biClrUsed = (1 << BMIH.biBitCount);
163 BMIH.biClrImportant = BMIH.biClrUsed;
164 BMIH.biCompression = 0;
167 BMFH.bfTypeB = 0x42; // B'
168 BMFH.bfTypeM = 0x4D; // M'
173 void BitMapObject_CreateFromFile(char *Path)
178 if (! FileExists(Path))
181 if (FileLen(Path) < (Len(BMFH) + Len(BMIH)))
184 FNum = fopen(Path, "rb");
185 FILE_GET(FNum, -1, &BMFH, sizeof(BMFH));
186 FILE_GET(FNum, -1, &BMIH, sizeof(BMIH));
189 if (BMIH.biCompression != 0)
191 Err.Raise(600, "BitMapObject", "Cannot read compressed BMP files");
196 if (BMIH.biBitCount < 9)
198 FILE_GET(FNum, -1, &ColorTable, sizeof(ColorTable));
202 FILE_GET(FNum, 1 + BMFH.bfOffBits, &ImageDataBytes, sizeof(ImageDataBytes));
204 if (BMIH.biBitCount < 9)
205 ConvertToVBPalette();
208 void BitMapObject_SaveToFile(char *Path)
212 BMFH.bfOffBits = Len(BMFH) + Len(BMIH);
213 if (BMIH.biBitCount < 9)
214 BMFH.bfOffBits = BMFH.bfOffBits + ((1 << BMIH.biBitCount)) * Len(ColorTable[0]);
216 BMIH.biSizeImage = Get_LineLength() * BMIH.biHeight;
217 BMFH.bfSize = BMFH.bfOffBits + BMIH.biSizeImage;
219 FNum = fopen(Path, "wb");
220 FILE_PUT(FNum, -1, &BMFH, sizeof(BMFH));
221 FILE_PUT(FNum, -1, &BMIH, sizeof(BMIH));
222 if (BMIH.biBitCount < 9)
224 FILE_PUT(FNum, -1, &ColorTable, sizeof(ColorTable));
227 FILE_PUT(FNum, -1, &ImageDataBytes, sizeof(ImageDataBytes));
231 static void ConvertToVBPalette()
235 ColMax = UBound(ColorTable);
236 for (i = 0; i <= ColMax; i++)
239 VBPalette[i] = RGB(ColorTable[i].rgbRed, ColorTable[i].rgbGreen, ColorTable[i].rgbBlue);
244 static void ReDimArrays()
247 if (BMIH.biBitCount < 9)
249 BMIH.biClrUsed = (1 << BMIH.biBitCount);
250 ColorTable = REDIM_1D(sizeof(RGBQUADType), 0, BMIH.biClrUsed - 1);
251 VBPalette = REDIM_1D(sizeof(long), 0, BMIH.biClrUsed - 1);
254 if (0 < Get_LineLength() && 0 < BMIH.biHeight)
256 ImageDataBytes = REDIM_2D(sizeof(byte), 0, Get_LineLength() - 1, 0, BMIH.biHeight - 1);
262 long BitMapObject_Get_Palette(long Index)
266 Palette = VBPalette[Index];
271 void BitMapObject_Let_Palette(long Index, long NewVal)
273 VBPalette[Index] = NewVal & 0xFFFFFF;
275 ColorTable[Index].rgbRed = (NewVal & 0xFF) / 0x1;
276 ColorTable[Index].rgbGreen = (NewVal & 0xFF00) / 0x100;
277 ColorTable[Index].rgbBlue = (NewVal & 0xFF0000) / 0x10000;
281 long BitMapObject_Get_ColorsUsed()
285 if (BMIH.biBitCount < 9)
287 ColorsUsed = (1 << BMIH.biBitCount);
297 long BitMapObject_Get_ColorIndex(long X, long Y)
301 long ColIndex, NewX, BitPos, nY;
303 if (8 < BMIH.biBitCount)
305 Err.Raise(600, "BitmapObject", "I have ! Palette in this ColorDepthMode");
310 nY = BMIH.biHeight - 1 - Y;
311 switch (BMIH.biBitCount)
314 ColIndex = ImageDataBytes[X / 8, nY];
315 BitPos = 7 - (X % 8);
316 NewX = (1 << BitPos);
317 if ((NewX && ColIndex) == 0)
329 ColIndex = ImageDataBytes[X / 2, nY];
332 ColorIndex = (ColIndex & 0xF0) / 0x10;
336 ColorIndex = (ColIndex & 0xF);
342 ColorIndex = ImageDataBytes[X, nY];
346 Err.Raise(600, "BitmapObject", "Invalid bpx value");
353 void BitMapObject_Let_ColorIndex(long X, long Y, long ColorIndex)
355 long ColIndex, ByteVal, NewX, BitPos, nY;
357 if (8 < BMIH.biBitCount)
359 Err.Raise(600, "BitmapObject", "I have ! Palette in this ColorDepthMode");
363 nY = BMIH.biHeight - 1 - Y;
364 switch (BMIH.biBitCount)
367 ByteVal = ImageDataBytes[X / 8, nY];
368 BitPos = 7 - (X % 8);
369 NewX = (1 << BitPos);
370 ColIndex = ColorIndex * NewX;
373 ByteVal = (ByteVal & (! NewX));
377 ByteVal = (ByteVal | NewX);
380 ImageDataBytes[X / 8, nY] = ByteVal;
384 ByteVal = ImageDataBytes[X / 2, nY];
387 ByteVal = (ByteVal & 0xF) + ColorIndex * 0x10;
391 ByteVal = (ByteVal & 0xF0) + ColorIndex;
394 ImageDataBytes[X / 2, nY] = ByteVal;
398 ImageDataBytes[X, nY] = ColorIndex;
402 Err.Raise(600, "BitmapObject", "Invalid bpx value");
407 long BitMapObject_Get_Point(long X, long Y)
411 long ColIndex, NewX, BitPos, nY;
413 nY = BMIH.biHeight - 1 - Y;
414 switch (BMIH.biBitCount)
417 ColIndex = ImageDataBytes[X / 8, nY];
418 BitPos = 7 - (X % 8);
419 NewX = (1 << BitPos);
420 if ((NewX && ColIndex) == 0)
429 Point = VBPalette[ColIndex];
433 ColIndex = ImageDataBytes[X / 2, nY];
436 ColIndex = (ColIndex & 0xF0) / 0x10;
440 ColIndex = (ColIndex & 0xF);
443 Point = VBPalette[ColIndex];
447 ColIndex = ImageDataBytes[X, nY];
448 Point = VBPalette[ColIndex];
453 Point = ImageDataBytes[NewX, nY] * 0x10000;
454 Point = Point + ImageDataBytes[NewX + 1, nY] * 0x100;
455 Point = Point + ImageDataBytes[NewX + 2, nY];
459 Err.Raise(600, "BitmapObject", "Invalid bpx value");
466 void BitMapObject_Let_Point(long X, long Y, long NewColor)
468 long ColIndex, ByteVal, NewX, BitPos, nY;
470 nY = BMIH.biHeight - 1 - Y;
471 switch (BMIH.biBitCount)
474 ColIndex = GetPaletteIndex(NewColor);
475 ByteVal = ImageDataBytes[X / 8, nY];
476 BitPos = 7 - (X % 8);
477 NewX = (1 << BitPos);
478 ColIndex = ColIndex * NewX;
481 ByteVal = (ByteVal & (! NewX));
485 ByteVal = (ByteVal | NewX);
488 ImageDataBytes[X / 8, nY] = ByteVal;
492 ColIndex = GetPaletteIndex(NewColor);
493 ByteVal = ImageDataBytes[X / 2, nY];
496 ByteVal = (ByteVal & 0xF) + ColIndex * 0x10;
500 ByteVal = (ByteVal & 0xF0) + ColIndex;
503 ImageDataBytes[X / 2, nY] = ByteVal;
507 ImageDataBytes[X, nY] = GetPaletteIndex(NewColor);
512 ImageDataBytes[NewX, nY] = (NewColor & 0xFF0000) / 0x10000; // B
513 ImageDataBytes[NewX + 1, nY] = (NewColor & 0xFF00) / 0x100; // G
514 ImageDataBytes[NewX + 2, nY] = (NewColor & 0xFF); // R
518 Err.Raise(600, "BitmapObject", "Invalid bpx value");
523 int BitMapObject_GetPaletteIndex(long Color)
529 ColMax = UBound(VBPalette);
530 for (i = 0; i <= ColMax; i++)
532 if (VBPalette[i] == Color)
536 if (ColMax < i) // Error - Color not in Palette!
541 return GetPaletteIndex;
544 long BitMapObject_Get_Width()
548 Width = BMIH.biWidth;
553 long BitMapObject_Get_Height()
557 Height = BMIH.biHeight;
562 BitMapObject BitMapObject_GetStretchCopy(float StretchVal)
564 BitMapObject GetStretchCopy;
566 long nWidth, nHeight, iX, iY;
568 // GetStretchCopy = New BitMapObject; // (handle this later, if needed)
569 nWidth = StretchVal * BMIH.biWidth;
570 nHeight = StretchVal * BMIH.biHeight;
571 GetStretchCopy.CreateAtSize(nWidth, nHeight, CLng(BMIH.biBitCount));
573 nHeight = nHeight - 1;
574 for (iX = 0; iX <= BMIH.biClrUsed - 1; iX++)
576 GetStretchCopy.Let_Palette(iX, Palette(iX));
579 for (iY = 0; iY <= nHeight; iY++)
581 for (iX = 0; iX <= nWidth; iX++)
583 GetStretchCopy.Let_ColorIndex(iX, iY, ColorIndex(Int(iX / StretchVal), Int(iY / StretchVal)));
587 return GetStretchCopy;