Added support for standard 16-bit images.
[AROS.git] / workbench / classes / datatypes / bmp / bmpclass.c
blobf63665dc345b88796fcadd5a70b1db1aa068c469
1 /*
2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 /**********************************************************************/
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
12 #include <exec/types.h>
13 #include <exec/memory.h>
14 #include <dos/dostags.h>
15 #include <graphics/gfxbase.h>
16 #include <graphics/rpattr.h>
17 #include <cybergraphx/cybergraphics.h>
18 #include <intuition/imageclass.h>
19 #include <intuition/icclass.h>
20 #include <intuition/gadgetclass.h>
21 #include <intuition/cghooks.h>
22 #include <datatypes/datatypesclass.h>
23 #include <datatypes/pictureclass.h>
25 #include <clib/alib_protos.h>
26 #include <proto/exec.h>
27 #include <proto/dos.h>
28 #include <proto/intuition.h>
29 #include <proto/graphics.h>
30 #include <proto/utility.h>
31 #include <proto/iffparse.h>
32 #include <proto/datatypes.h>
34 #include <aros/symbolsets.h>
36 #include "debug.h"
38 #include "methods.h"
40 /* Open superclass */
41 ADD2LIBS("datatypes/picture.datatype", 0, struct Library *, PictureBase);
43 /**************************************************************************************************/
45 #define FILEBUFSIZE 65536
46 #define MAXCOLORS 256
48 typedef struct {
49 union {
50 struct IFFHandle *iff;
51 BPTR bptr;
52 } filehandle;
54 UBYTE *filebuf;
55 UBYTE *filebufpos;
56 long filebufbytes;
57 long filebufsize;
58 UBYTE *linebuf;
59 UBYTE *linebufpos;
60 long linebufsize;
62 APTR codecvars;
63 } BmpHandleType;
66 typedef struct
68 WORD bfType; // 0 ASCII "BM"
69 ULONG bfSize; // 2 Size in bytes of the file
70 WORD bfReserved1; // 6 Zero
71 WORD bfReserved2; // 8 Zero
72 ULONG bfOffBits; // 10 Byte offset in files where image begins
73 } __attribute__((packed)) FileBitMapHeader; // 14
75 typedef struct
77 ULONG biSize; // 0 Size of this header, 40 bytes
78 LONG biWidth; // 4 Image width in pixels
79 LONG biHeight; // 8 Image height in pixels
80 WORD biPlanes; // 12 Number of image planes, must be 1
81 WORD biBitCount; // 14 Bits per pixel, 1, 4, 8, 24, or 32
82 ULONG biCompression; // 16 Compression type, below
83 ULONG biSizeImage; // 20 Size in bytes of compressed image, or zero
84 LONG biXPelsPerMeter; // 24 Horizontal resolution, in pixels/meter
85 LONG biYPelsPerMeter; // 28 Vertical resolution, in pixels/meter
86 ULONG biClrUsed; // 32 Number of colors used, below
87 ULONG biClrImportant; // 36 Number of "important" colors
88 } __attribute__((packed)) BitmapInfoHeader; // 40
90 /* "BM" backwards, due to LE byte order */
91 #define BITMAP_ID "MB"
93 /**************************************************************************************************/
95 static void BMP_Exit(BmpHandleType *bmphandle, LONG errorcode)
97 D(if (errorcode) bug("bmp.datatype/BMP_Exit() --- IoErr %ld\n", errorcode));
98 if (bmphandle->filebuf)
100 FreeMem(bmphandle->filebuf, bmphandle->filebufsize);
102 if (bmphandle->linebuf)
104 FreeMem(bmphandle->linebuf, bmphandle->linebufsize);
106 if (bmphandle->codecvars)
108 FreeVec(bmphandle->codecvars);
110 SetIoErr(errorcode);
113 /**************************************************************************************************/
115 /* buffered file access, useful for RLE */
116 BOOL SaveBMP_EmptyBuf(BmpHandleType *bmphandle, long minbytes)
118 long bytes, bytestowrite;
120 bytestowrite = bmphandle->filebufsize - (bmphandle->filebufbytes + minbytes);
121 D(bug("bmp.datatype/SaveBMP_EmptyBuf() --- minimum %ld bytes, %ld bytes to write\n", (long)minbytes, (long)bytestowrite));
122 bytes = Write(bmphandle->filehandle.bptr, bmphandle->filebuf, bytestowrite);
123 if ( bytes < bytestowrite )
125 D(bug("bmp.datatype/SaveBMP_EmptyBuf() --- writing failed, wrote %ld bytes\n", (long)bytes));
126 return FALSE;
128 bmphandle->filebufpos = bmphandle->filebuf;
129 bmphandle->filebufbytes = bmphandle->filebufsize - minbytes;
130 D(bug("bmp.datatype/SaveBMP_EmptyBuf() --- wrote %ld bytes\n", (long)bytes));
131 return TRUE;
134 /* buffered file access, useful for RLE */
135 BOOL LoadBMP_FillBuf(BmpHandleType *bmphandle, long minbytes)
137 long i, bytes;
139 //D(bug("bmp.datatype/LoadBMP_FillBuf() --- minimum %ld bytes of %ld (%ld) bytes\n", (long)minbytes, (long)bmphandle->filebufbytes, (long)(bmphandle->filebufsize-(bmphandle->filebufpos-bmphandle->filebuf)) ));
140 if ( bmphandle->filebufbytes >= 0 )
141 return TRUE;
142 bytes = bmphandle->filebufbytes + minbytes;
143 //D(bug("bmp.datatype/LoadBMP_FillBuf() --- %ld bytes requested, %ld bytes left\n", (long)minbytes, (long)bytes));
144 if (bytes > 0)
146 //D(bug("bmp.datatype/LoadBMP_FillBuf() --- existing %ld old bytes\n", (long)bytes));
147 for (i=0; i<bytes; i++) /* copy existing bytes to start of buffer */
148 bmphandle->filebuf[i] = bmphandle->filebufpos[i];
150 bmphandle->filebufpos = bmphandle->filebuf;
151 bytes = Read(bmphandle->filehandle.bptr, bmphandle->filebuf + bytes, bmphandle->filebufsize - bytes);
152 if (bytes < 0 ) bytes = 0;
153 bmphandle->filebufbytes += bytes;
154 //D(bug("bmp.datatype/LoadBMP_FillBuf() --- read %ld bytes, remaining new %ld bytes\n", (long)bytes, (long)bmphandle->filebufbytes));
155 //D(bug("bmp.datatype/LoadBMP_FillBuf() --- >minimum %ld bytes of %ld (%ld) bytes\n", (long)minbytes, (long)bmphandle->filebufbytes, (long)(bmphandle->filebufsize-(bmphandle->filebufpos-bmphandle->filebuf)) ));
156 if (bmphandle->filebufbytes >= 0)
157 return TRUE;
158 return FALSE;
161 static BOOL LoadBMP_Colormap(BmpHandleType *bmphandle, int numcolors,
162 struct ColorRegister *colormap, ULONG *colregs)
164 unsigned int i, j;
166 if (numcolors && numcolors <= MAXCOLORS)
168 j = 0;
169 for (i = 0; i < numcolors; i++)
171 if ( (bmphandle->filebufbytes -= 4) < 0 && !LoadBMP_FillBuf(bmphandle, 4) )
173 D(bug("bmp.datatype/LoadBMP_Colormap() --- colormap loading failed\n"));
174 return FALSE;
176 /* BGR0 format for MS Win files, BGR format for OS/2 files */
177 colormap[i].blue = *(bmphandle->filebufpos)++;
178 colormap[i].green = *(bmphandle->filebufpos)++;
179 colormap[i].red = *(bmphandle->filebufpos)++;
180 bmphandle->filebufpos++;
181 colregs[j++] = ((ULONG)colormap[i].red)<<24;
182 colregs[j++] = ((ULONG)colormap[i].green)<<24;
183 colregs[j++] = ((ULONG)colormap[i].blue)<<24;
184 // D(if (i<5) bug("gif r %02lx g %02lx b %02lx\n", colormap[i].red, colormap[i].green, colormap[i].blue));
186 D(bug("bmp.datatype/LoadBMP_Colormap() --- %d colors loaded\n", numcolors));
188 return TRUE;
191 /**************************************************************************************************/
192 static BOOL LoadBMP(struct IClass *cl, Object *o)
194 BmpHandleType *bmphandle;
195 UBYTE *filebuf;
196 IPTR sourcetype;
197 ULONG D(bfSize,) bfOffBits;
198 ULONG biSize, biWidth, biHeight, biCompression;
199 ULONG biClrUsed D(, biClrImportant);
200 UWORD biPlanes, biBitCount;
201 ULONG alignwidth, alignbytes, pixelfmt;
202 long x = 0, y;
203 int cont, byte;
204 struct BitMapHeader *bmhd;
205 struct ColorRegister *colormap;
206 ULONG *colorregs;
207 STRPTR name;
209 D(bug("bmp.datatype/LoadBMP()\n"));
211 if( !(bmphandle = AllocMem(sizeof(BmpHandleType), MEMF_ANY)) )
213 SetIoErr(ERROR_NO_FREE_STORE);
214 return FALSE;
216 bmphandle->filebuf = NULL;
217 bmphandle->linebuf = NULL;
218 bmphandle->codecvars = NULL;
221 if( GetDTAttrs(o, DTA_SourceType , (IPTR)&sourcetype ,
222 DTA_Handle , (IPTR)&(bmphandle->filehandle),
223 PDTA_BitMapHeader , (IPTR)&bmhd,
224 TAG_DONE) != 3 )
226 BMP_Exit(bmphandle, ERROR_OBJECT_NOT_FOUND);
227 return FALSE;
230 if ( sourcetype == DTST_RAM && bmphandle->filehandle.iff == NULL && bmhd )
232 D(bug("bmp.datatype/LoadBMP() --- Creating an empty object\n"));
233 BMP_Exit(bmphandle, 0);
234 return TRUE;
236 if ( sourcetype != DTST_FILE || !bmphandle->filehandle.bptr || !bmhd )
238 D(bug("bmp.datatype/LoadBMP() --- unsupported mode\n"));
239 BMP_Exit(bmphandle, ERROR_NOT_IMPLEMENTED);
240 return FALSE;
243 /* initialize buffered file reads */
244 bmphandle->filebufbytes = 0;
245 bmphandle->filebufsize = FILEBUFSIZE;
246 if( !(bmphandle->filebuf = bmphandle->filebufpos = AllocMem(bmphandle->filebufsize, MEMF_ANY)) )
248 BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
249 return FALSE;
252 /* load FileBitmapHeader from file, make sure, there are at least 14 bytes in buffer */
253 if ( (bmphandle->filebufbytes -= 14) < 0 && !LoadBMP_FillBuf(bmphandle, 14) )
255 D(bug("bmp.datatype/LoadBMP() --- filling buffer with header failed\n"));
256 BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
257 return FALSE;
259 filebuf = bmphandle->filebufpos; /* this makes things easier */
260 bmphandle->filebufpos += 14;
261 if( filebuf[0] != 'B' && filebuf[1] != 'M' )
263 D(bug("bmp.datatype/LoadBMP() --- header type mismatch\n"));
264 BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
265 return FALSE;
267 /* byte-wise access isn't elegant, but it is endianess-safe */
268 D(bfSize = (filebuf[5]<<24) | (filebuf[4]<<16) | (filebuf[3]<<8) | filebuf[2]);
269 bfOffBits = (filebuf[13]<<24) | (filebuf[12]<<16) | (filebuf[11]<<8) | filebuf[10];
270 D(bug("bmp.datatype/LoadBMP() --- bfSize %ld bfOffBits %ld\n", bfSize, bfOffBits));
272 /* load BitmapInfoHeader from file, make sure, there are at least 40 bytes in buffer */
273 if ( (bmphandle->filebufbytes -= 40) < 0 && !LoadBMP_FillBuf(bmphandle, 40) )
275 D(bug("bmp.datatype/LoadBMP() --- filling buffer with header 2 failed\n"));
276 BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
277 return FALSE;
279 filebuf = bmphandle->filebufpos; /* this makes things easier */
280 bmphandle->filebufpos += 40;
282 /* get image size attributes */
283 biSize = (filebuf[3]<<24) | (filebuf[2]<<16) | (filebuf[1]<<8) | filebuf[0];
284 biWidth = (filebuf[7]<<24) | (filebuf[6]<<16) | (filebuf[5]<<8) | filebuf[4];
285 biHeight = (filebuf[11]<<24) | (filebuf[10]<<16) | (filebuf[9]<<8) | filebuf[8];
286 biPlanes = (filebuf[13]<<8) | filebuf[12];
287 biBitCount = (filebuf[15]<<8) | filebuf[14];
288 biCompression = (filebuf[19]<<24) | (filebuf[18]<<16) | (filebuf[17]<<8) | filebuf[16];
289 biClrUsed = (filebuf[35]<<24) | (filebuf[34]<<16) | (filebuf[33]<<8) | filebuf[32];
290 D(biClrImportant = (filebuf[39]<<24) | (filebuf[38]<<16) | (filebuf[37]<<8) | filebuf[36]);
291 D(bug("bmp.datatype/LoadBMP() --- BMP-Screen %ld x %ld x %ld, %ld (%ld) colors, compression %ld, type %ld\n",
292 biWidth, biHeight, (long)biBitCount, biClrUsed, biClrImportant, biCompression, biSize));
293 if (biSize != 40 || biPlanes != 1 || biCompression != 0)
295 D(bug("bmp.datatype/LoadBMP() --- Image format not supported\n"));
296 BMP_Exit(bmphandle, ERROR_NOT_IMPLEMENTED);
297 return FALSE;
300 /* check color mode */
301 pixelfmt = PBPAFMT_LUT8;
302 switch (biBitCount)
304 case 1:
305 alignwidth = (biWidth + 31) & ~31UL;
306 alignbytes = alignwidth / 8;
307 break;
308 case 4:
309 alignwidth = (biWidth + 7) & ~7UL;
310 alignbytes = alignwidth / 2;
311 break;
312 case 8:
313 alignwidth = (biWidth + 3) & ~3UL;
314 alignbytes = alignwidth;
315 break;
316 case 16:
317 alignbytes = ((biBitCount * biWidth + 31) / 32) * 4;
318 alignwidth = alignbytes / 2;
319 pixelfmt = PBPAFMT_RGB;
320 break;
321 case 24:
322 alignbytes = ((biBitCount * biWidth + 31) / 32) * 4;
323 alignwidth = alignbytes / 3;
324 pixelfmt = PBPAFMT_RGB;
325 break;
326 default:
327 D(bug("bmp.datatype/LoadBMP() --- unsupported color depth\n"));
328 BMP_Exit(bmphandle, ERROR_NOT_IMPLEMENTED);
329 return FALSE;
331 D(bug("bmp.datatype/LoadBMP() --- align: pixels %ld bytes %ld\n", alignwidth, alignbytes));
333 /* set BitMapHeader with image size */
334 bmhd->bmh_Width = bmhd->bmh_PageWidth = biWidth;
335 bmhd->bmh_Height = bmhd->bmh_PageHeight = biHeight;
336 bmhd->bmh_Depth = biBitCount;
338 /* get empty colormap, then fill in colormap to use*/
339 if (biBitCount <= 8)
341 if( !(GetDTAttrs(o, PDTA_ColorRegisters, (IPTR)&colormap,
342 PDTA_CRegs, (IPTR)&colorregs,
343 TAG_DONE ) == 2) ||
344 !(colormap && colorregs) )
346 D(bug("bmp.datatype/LoadBMP() --- got no colormap\n"));
347 BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
348 return FALSE;
351 /* Zero in the color count field means calculate it based on bits */
352 if (biClrUsed == 0)
353 biClrUsed = 1 << biBitCount;
355 if( !LoadBMP_Colormap(bmphandle, biClrUsed, colormap, colorregs) )
357 BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
358 return FALSE;
361 /* skip offset */
362 bfOffBits = bfOffBits - 14 - 40 - biClrUsed*4;
363 D(bug("bmp.datatype/LoadBMP() --- remaining offset %ld\n", bfOffBits));
364 if ( bfOffBits < 0 ||
365 ( (bmphandle->filebufbytes -= bfOffBits ) < 0 && !LoadBMP_FillBuf(bmphandle, bfOffBits) ) )
367 D(bug("bmp.datatype/LoadBMP() --- cannot skip offset\n"));
368 BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
369 return FALSE;
371 bmphandle->filebufpos += bfOffBits;
373 /* Pass attributes to picture.datatype */
374 GetDTAttrs( o, DTA_Name, (IPTR)&name, TAG_DONE );
375 SetDTAttrs(o, NULL, NULL, PDTA_NumColors, biClrUsed,
376 DTA_NominalHoriz, biWidth,
377 DTA_NominalVert , biHeight,
378 DTA_ObjName , (IPTR)name,
379 TAG_DONE);
381 /* Now decode the picture data into a chunky buffer; and pass it to Bitmap line-by-line */
382 if (biBitCount > 8)
383 bmphandle->linebufsize = alignwidth * 3;
384 else
385 bmphandle->linebufsize = alignwidth;
386 if (! (bmphandle->linebuf = bmphandle->linebufpos = AllocMem(bmphandle->linebufsize, MEMF_ANY)) )
388 BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
389 return FALSE;
392 //D(bug("bmp.datatype/LoadBMP() --- bytes of %ld (%ld) bytes\n", (long)bmphandle->filebufbytes, (long)(bmphandle->filebufsize-(bmphandle->filebufpos-bmphandle->filebuf)) ));
393 cont = 1;
394 for (y=biHeight-1; y>=0 && cont; y--)
396 int r, g, b;
397 UBYTE *p;
398 UWORD pixel;
400 bmphandle->linebufpos = bmphandle->linebuf;
401 if (biBitCount == 24)
403 if ( (bmphandle->filebufbytes -= alignbytes) < 0 && !LoadBMP_FillBuf(bmphandle, alignbytes) )
405 D(bug("bmp.datatype/LoadBMP() --- early end of bitmap data, x %ld y %ld\n", x, y));
406 //BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
407 //return FALSE;
408 cont = 0;
410 for (x=0, p = bmphandle->filebufpos; x<alignwidth; x++)
412 b = *p++;
413 g = *p++;
414 r = *p++;
415 *(bmphandle->linebufpos)++ = r;
416 *(bmphandle->linebufpos)++ = g;
417 *(bmphandle->linebufpos)++ = b;
419 bmphandle->filebufpos += alignbytes;
421 else if (biBitCount == 16)
423 if ( (bmphandle->filebufbytes -= alignbytes) < 0 && !LoadBMP_FillBuf(bmphandle, alignbytes) )
425 D(bug("bmp.datatype/LoadBMP() --- early end of bitmap data, x %ld y %ld\n", x, y));
426 //BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
427 //return FALSE;
428 cont = 0;
430 for (x=0, p = bmphandle->filebufpos; x<alignwidth; x++)
432 pixel = *p++;
433 pixel |= *p++ << 8;
434 *(bmphandle->linebufpos)++ = (pixel & 0x7c00) >> 7;
435 *(bmphandle->linebufpos)++ = (pixel & 0x03e0) >> 2;
436 *(bmphandle->linebufpos)++ = (pixel & 0x1f) << 3;
438 bmphandle->filebufpos += alignbytes;
440 else
442 for (x=0; x<alignbytes; x++)
444 if ( (bmphandle->filebufbytes -= 1) < 0 && !LoadBMP_FillBuf(bmphandle, 1) )
446 D(bug("bmp.datatype/LoadBMP() --- early end of bitmap data, x %ld y %ld\n", x, y));
447 //BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
448 //return FALSE;
449 cont = 0;
450 break;
452 byte = *(bmphandle->filebufpos)++;
453 switch (biBitCount)
455 case 1:
456 for (b=0; b<8; b++)
458 *(bmphandle->linebufpos)++ = (byte & 0x80) ? 1 : 0;
459 byte <<= 1;
461 break;
462 case 4:
463 *(bmphandle->linebufpos)++ = (byte & 0xf0) >> 4;
464 *(bmphandle->linebufpos)++ = (byte & 0x0f);
465 break;
466 case 8:
467 *(bmphandle->linebufpos)++ = byte;
468 break;
469 case 24:
470 *(bmphandle->linebufpos)++ = byte;
471 break;
477 !DoSuperMethod(cl, o,
478 PDTM_WRITEPIXELARRAY, /* Method_ID */
479 (IPTR)bmphandle->linebuf, /* PixelData */
480 pixelfmt, /* PixelFormat */
481 alignbytes, /* PixelArrayMod (number of bytes per row) */
482 0, /* Left edge */
483 y, /* Top edge */
484 biWidth, /* Width */
485 1 /* Height (here: one line) */
489 D(bug("bmp.datatype/LoadBMP() --- WRITEPIXELARRAY failed !\n"));
490 BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
491 return FALSE;
494 //D(bug("bmp.datatype/LoadBMP() --- bytes of %ld (%ld) bytes\n", (long)bmphandle->filebufbytes, (long)(bmphandle->filebufsize-(bmphandle->filebufpos-bmphandle->filebuf)) ));
496 D(bug("bmp.datatype/LoadBMP() --- Normal Exit\n"));
497 BMP_Exit(bmphandle, 0);
498 return TRUE;
501 /**************************************************************************************************/
503 static BOOL SaveBMP(struct IClass *cl, Object *o, struct dtWrite *dtw )
505 BmpHandleType *bmphandle;
506 UBYTE *filebuf;
507 unsigned int width, height, widthxheight, numplanes, numcolors;
508 struct BitMapHeader *bmhd;
509 struct BitMap *bm;
510 struct RastPort rp;
511 long *colorregs;
512 int i, j, ret;
514 D(bug("bmp.datatype/SaveBMP()\n"));
516 if( !(bmphandle = AllocMem(sizeof(BmpHandleType), MEMF_ANY)) )
518 SetIoErr(ERROR_NO_FREE_STORE);
519 return FALSE;
521 bmphandle->filebuf = NULL;
522 bmphandle->linebuf = NULL;
523 bmphandle->codecvars = NULL;
525 /* A NULL file handle is a NOP */
526 if( !dtw->dtw_FileHandle )
528 D(bug("bmp.datatype/SaveBMP() --- empty Filehandle - just testing\n"));
529 BMP_Exit(bmphandle, 0);
530 return TRUE;
532 bmphandle->filehandle.bptr = dtw->dtw_FileHandle;
534 /* Get BitMap and color palette */
535 if( GetDTAttrs( o, PDTA_BitMapHeader, (IPTR)&bmhd,
536 PDTA_BitMap, (IPTR)&bm,
537 PDTA_CRegs, (IPTR)&colorregs,
538 PDTA_NumColors, (IPTR)&numcolors,
539 TAG_DONE ) != 4UL ||
540 !bmhd || !bm || !colorregs || !numcolors)
542 D(bug("bmp.datatype/SaveBMP() --- missing attributes\n"));
543 BMP_Exit(bmphandle, ERROR_OBJECT_NOT_FOUND);
544 return FALSE;
546 #if 0
547 /* Check if this is a standard BitMap */
548 if( !( GetBitMapAttr(bm, BMA_FLAGS) & BMF_STANDARD ) )
550 D(bug("bmp.datatype/SaveBMP() --- wrong BitMap type\n"));
551 BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
552 return FALSE;
554 #endif
555 /* initialize buffered file reads */
556 bmphandle->filebufsize = FILEBUFSIZE;
557 bmphandle->filebufbytes = bmphandle->filebufsize;
558 if( !(bmphandle->filebuf = bmphandle->filebufpos = AllocMem(bmphandle->filebufsize, MEMF_ANY)) )
560 BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
561 return FALSE;
564 /* write BMP 87a header to file, make sure, there are at least 13 bytes in buffer */
565 if ( (bmphandle->filebufbytes -= 13) < 0 && !SaveBMP_EmptyBuf(bmphandle, 13) )
567 D(bug("bmp.datatype/SaveBMP() --- filling buffer with header failed\n"));
568 BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
569 return FALSE;
571 filebuf = bmphandle->filebufpos; /* this makes things easier */
572 bmphandle->filebufpos += 13;
574 /* set screen descriptor attributes (from BitMapHeader) */
575 width = bmhd->bmh_PageWidth;
576 height = bmhd->bmh_PageHeight;
577 numplanes = bmhd->bmh_Depth - 1;
578 numcolors = 1 << (numplanes + 1);
579 D(bug("bmp.datatype/SaveBMP() --- BMP-Image %d x %d x %d, cols %d\n", width, height, numplanes+1, numcolors));
580 filebuf[6] = width & 0xff;
581 filebuf[7] = width >> 8;
582 filebuf[8] = height & 0xff;
583 filebuf[9] = height >> 8;
584 filebuf[10] = 0x80 | ((numplanes & 0x07) << 4) | (numplanes & 0x07) ; /* set numplanes, havecolmap=1 */
585 filebuf[11] = 0; /* this is fillcolor */
586 filebuf[12] = 0; /* this is pixel aspect ratio, 0 means unused */
588 /* write screen colormap, we don't use an image colormap */
589 for (i = 0; i < numcolors*3; i += 3)
591 if ( (bmphandle->filebufbytes -= 3) < 0 && !SaveBMP_EmptyBuf(bmphandle, 3) )
593 BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
594 return FALSE;
596 *(bmphandle->filebufpos)++ = colorregs[i] >> 24;
597 *(bmphandle->filebufpos)++ = colorregs[i+1] >> 24;
598 *(bmphandle->filebufpos)++ = colorregs[i+2] >> 24;
601 /* write image header, image has same size as screen */
602 if ( (bmphandle->filebufbytes -= 10) < 0 && !SaveBMP_EmptyBuf(bmphandle, 10) )
604 BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
605 return FALSE;
607 filebuf = bmphandle->filebufpos; /* this makes things easier */
608 bmphandle->filebufpos += 10;
609 filebuf[0] = ','; /* header ID */
610 filebuf[1] = filebuf[2] = 0; /* no left edge */
611 filebuf[3] = filebuf[4] = 0; /* no top edge */
612 filebuf[5] = width & 0xff;
613 filebuf[6] = width >> 8;
614 filebuf[7] = height & 0xff;
615 filebuf[8] = height >> 8;
616 filebuf[9] = numplanes & 0x07; /* set numplanes, havecolmap=0, interlaced=0 */
618 /* Now read the picture data from the bitplanes and write it to a chunky buffer */
619 /* For now, we use a full picture pixel buffer, not a single line */
620 widthxheight = width*height;
621 bmphandle->linebufsize = widthxheight;
622 if (! (bmphandle->linebuf = bmphandle->linebufpos = AllocMem(bmphandle->linebufsize, MEMF_ANY)) )
624 BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
625 return FALSE;
627 InitRastPort(&rp);
628 rp.BitMap=bm;
629 for (j=0; j<height; j++)
631 for (i=0; i<width; i++)
633 ret = (UBYTE)ReadPixel(&rp, i, j); /* very slow, to be changed */
634 *(bmphandle->linebufpos)++ = ret;
637 bmphandle->linebufpos = bmphandle->linebuf;
639 /* write the chunky buffer to file, after encoding */
641 /* write end-of-BMP marker */
642 if ( !bmphandle->filebufbytes-- && !SaveBMP_EmptyBuf(bmphandle, 1) )
644 BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
645 return FALSE;
647 *(bmphandle->filebufpos)++ = ';';
649 /* flush write buffer to file and exit */
650 SaveBMP_EmptyBuf(bmphandle, 0);
651 D(bug("bmp.datatype/SaveBMP() --- Normal Exit\n"));
652 BMP_Exit(bmphandle, 0);
653 return TRUE;
658 /**************************************************************************************************/
660 IPTR BMP__OM_NEW(Class *cl, Object *o, Msg msg)
662 Object *newobj;
664 D(bug("bmp.datatype/DT_Dispatcher: Method OM_NEW\n"));
666 newobj = (Object *)DoSuperMethodA(cl, o, msg);
667 if (newobj)
669 if (!LoadBMP(cl, newobj))
671 CoerceMethod(cl, newobj, OM_DISPOSE);
672 newobj = NULL;
676 return (IPTR)newobj;
679 /**************************************************************************************************/
681 IPTR BMP__DTM_WRITE(Class *cl, Object *o, struct dtWrite *dtw)
683 D(bug("bmp.datatype/DT_Dispatcher: Method DTM_WRITE\n"));
684 if( (dtw -> dtw_Mode) == DTWM_RAW )
686 /* Local data format requested */
687 return SaveBMP(cl, o, dtw );
689 else
691 /* Pass msg to superclass (which writes an IFF ILBM picture)... */
692 return DoSuperMethodA( cl, o, (Msg)dtw );