4 Copyright (C) 2002-2011 Neil Cafferkey
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
24 #include <exec/memory.h>
25 #include <utility/hooks.h>
26 #include <datatypes/pictureclass.h>
27 #include <intuition/classusr.h>
29 #include <proto/exec.h>
30 #include <proto/dos.h>
31 #include <proto/intuition.h>
32 #include <proto/utility.h>
33 #include <proto/graphics.h>
34 #include <proto/datatypes.h>
35 #include <proto/alib.h>
39 #include "gemimage_protos.h"
42 #define MIN_HEADER_SIZE 16
43 #define VDI_ENTRY_SIZE 6
44 #define XBIOS_ENTRY_SIZE 2
45 #define XIMG_ID ('X' << 24 | 'I' << 16 | 'M' << 8 | 'G')
46 #define STTT_ID ('S' << 24 | 'T' << 16 | 'T' << 8 | 'T')
58 #define SCALEVDI(A) ((A) * ((1 << 29) / 125))
59 #define SCALEXBIOS(A) ((A) * 0x24924924)
62 static UPINT
DispatchOp(struct IClass
*class REG("a0"),
63 Object
*object
REG("a2"), Msg op
REG("a1"));
64 static UPINT
OMNew(struct IClass
*class, Object
*object
, struct opSet
*op
,
65 struct GemImgBase
*base
);
68 static const struct ColorRegister bilevel_palette
[] =
75 static const struct ColorRegister pc_palette
[]=
97 /****i* gemimage.datatype/MakeGemImgClass **********************************
103 * class = MakeGemImgClass()
105 * struct IClass *MakeGemImgClass(VOID);
107 ****************************************************************************
111 struct IClass
*MakeGemImgClass(struct GemImgBase
*base
)
114 struct IClass
*class;
117 MakeClass(base
->library
.lib_Node
.ln_Name
, PICTUREDTCLASS
, NULL
, 0, 0);
123 class->cl_Dispatcher
.h_Entry
= (HOOKFUNC
)DispatchOp
;
124 class->cl_UserData
= (IPTR
)base
;
133 /****i* gemimage.datatype/DispatchOp ***************************************
139 * result = DispatchOp(class, object, op)
141 * UPINT DispatchOp(struct IClass, Object, Msg);
143 ****************************************************************************
147 static UPINT
DispatchOp(struct IClass
*class REG("a0"),
148 Object
*object
REG("a2"), Msg op
REG("a1"))
150 struct GemImgBase
*base
;
153 base
= (APTR
)class->cl_UserData
;
157 result
= OMNew(class, object
, (APTR
)op
, base
);
161 result
= DoSuperMethodA(class, object
, op
);
169 /****i* gemimage.datatype/OMNew ********************************************
175 * result = OMNew(class, object, op)
177 * UPINT OMNew(struct IClass, Object, struct opSet);
179 ****************************************************************************
183 static UPINT
OMNew(struct IClass
*class, Object
*object
, struct opSet
*op
,
184 struct GemImgBase
*base
)
187 struct TagItem
*tags
;
188 UWORD header_size
, extension_size
, pattern_size
, pixel_width
,
189 pixel_height
, in_line_size
, out_line_size
, repeat_count
= 0,
190 colour_count
, i
, j
, k
, entry
, version
;
191 UBYTE datum
, *buffer
= NULL
, *buffer_end
, *in
, *out
, *in_stop
, *out_stop
,
192 *end_of_line
, fill
, *pattern
, palette_type
;
194 struct FileInfoBlock
*info
= NULL
;
195 struct BitMap
*bitmap
= NULL
;
196 struct BitMapHeader
*bitmap_header
;
197 struct ColorRegister
*colour_registers
;
198 const struct ColorRegister
*palette
;
199 BOOL repeat
= FALSE
, il
= TRUE
, reverse_planes
= FALSE
;
200 ULONG screen_mode
, *c_regs
, *c_reg
, level
;
202 /* Get a new picture object */
204 object
= (Object
*)DoSuperMethodA(class, object
, (Msg
)op
);
210 tags
= op
->ops_AttrList
;
211 if(GetTagData(DTA_SourceType
, DTST_FILE
, tags
) != DTST_FILE
)
212 error
= ERROR_OBJECT_WRONG_TYPE
;
216 GetDTAttrs(object
, DTA_Handle
, (UPINT
)&file
,
217 PDTA_BitMapHeader
, (UPINT
)&bitmap_header
, TAG_END
);
218 if(Seek(file
, 0, OFFSET_BEGINNING
) == -1)
220 info
= AllocDosObject(DOS_FIB
, NULL
);
227 if(!ExamineFH(file
, info
))
233 if(info
->fib_Size
< MIN_HEADER_SIZE
)
234 error
= ERROR_OBJECT_WRONG_TYPE
;
236 buffer
= AllocVec(info
->fib_Size
, MEMF_ANY
);
237 buffer_end
= buffer
+ info
->fib_Size
;
244 /* Read entire file */
246 if(Read(file
, buffer
, info
->fib_Size
) == -1)
252 /* Interpret header */
255 version
= BEWord(*(UWORD
*)in
);
257 header_size
= BEWord(*(UWORD
*)in
) * sizeof(UWORD
);
259 bitmap_header
->bmh_Depth
= BEWord(*(UWORD
*)in
);
261 pattern_size
= BEWord(*(UWORD
*)in
);
263 pixel_width
= BEWord(*(UWORD
*)in
);
265 pixel_height
= BEWord(*(UWORD
*)in
);
267 bitmap_header
->bmh_Width
= BEWord(*(UWORD
*)in
);
269 bitmap_header
->bmh_Height
= BEWord(*(UWORD
*)in
);
272 if(info
->fib_Size
< header_size
)
273 error
= ERROR_OBJECT_WRONG_TYPE
;
275 in_line_size
= (bitmap_header
->bmh_Width
- 1) / 8 + 1;
276 colour_count
= 1 << bitmap_header
->bmh_Depth
;
277 SetDTAttrs(object
, NULL
, NULL
, PDTA_NumColors
, colour_count
, TAG_END
);
278 GetDTAttrs(object
, PDTA_ColorRegisters
, (UPINT
)&colour_registers
,
279 PDTA_CRegs
, (UPINT
)&c_regs
, TAG_END
);
281 /* Allocate picture's bitmap */
283 bitmap
= AllocBitMap(bitmap_header
->bmh_Width
,
284 bitmap_header
->bmh_Height
, bitmap_header
->bmh_Depth
, BMF_CLEAR
,
292 /* Determine subformat */
294 extension_size
= header_size
- MIN_HEADER_SIZE
;
296 if(extension_size
== colour_count
* XBIOS_ENTRY_SIZE
)
298 /* "No Sig" subformat */
300 palette_type
= XBIOS_PALETTE
;
303 else if(extension_size
== 2 + colour_count
* XBIOS_ENTRY_SIZE
304 && BEWord(*(UWORD
*)in
) == 0x0080)
306 /* HyperPaint subformat */
308 palette_type
= XBIOS_PALETTE
;
311 else if(extension_size
== (1 + colour_count
) * VDI_ENTRY_SIZE
312 && BELong(*(ULONG
*)in
) == XIMG_ID
313 && BEWord(*(UWORD
*)(in
+ 4)) == 0x0000
314 && (version
== 2 || version
== 1))
318 palette_type
= VDI_PALETTE
;
319 in
+= VDI_ENTRY_SIZE
;
321 else if(extension_size
== 2 + colour_count
* XBIOS_ENTRY_SIZE
322 && BELong(*(ULONG
*)in
) == STTT_ID
323 && BEWord(*(UWORD
*)(in
+ 4)) == 0x0010)
325 /* ST/TT subformat */
328 palette_type
= XBIOS_PALETTE
;
331 else if(extension_size
== 0)
333 /* Original format or a paletteless subformat */
335 switch(bitmap_header
->bmh_Depth
)
338 palette
= bilevel_palette
;
339 palette_type
= BUILTIN_PALETTE
;
342 palette
= pc_palette
;
343 palette_type
= BUILTIN_PALETTE
;
346 palette_type
= GREYSCALE_PALETTE
;
347 reverse_planes
= TRUE
;
352 palette_type
= NO_PALETTE
;
354 error
= ERROR_OBJECT_WRONG_TYPE
;
358 error
= ERROR_OBJECT_WRONG_TYPE
;
363 /* Fill in bitmap's palette */
369 for(i
= 0; i
< colour_count
* 3; i
++)
371 *(c_reg
++) = SCALEVDI(BEWord(*(UWORD
*)in
));
376 for(i
= 0; i
< colour_count
; i
++)
379 entry
= BEWord(*(UWORD
*)in
);
380 for(j
= 1; j
<= 3; j
++)
382 *(c_reg
- j
) = SCALEXBIOS(entry
& 0x7);
388 case BUILTIN_PALETTE
:
389 for(i
= 0; i
< colour_count
; i
++, palette
++)
391 *(c_reg
++) = palette
->red
<< 24;
392 *(c_reg
++) = palette
->green
<<24;
393 *(c_reg
++) = palette
->blue
<< 24;
396 case GREYSCALE_PALETTE
:
398 for(i
= 0; i
< colour_count
; i
++)
400 for(j
= 0; j
< 3; j
++)
406 /* Make lower-precision copy of palette */
408 if(palette_type
!= NO_PALETTE
)
410 for(i
= 0; i
< colour_count
; i
++, colour_registers
++)
412 colour_registers
->red
= *(c_regs
++) >> 24;
413 colour_registers
->green
= *(c_regs
++) >> 24;
414 colour_registers
->blue
= *(c_regs
++) >> 24;
418 /* Read image data into bitmap */
420 out_line_size
= bitmap
->BytesPerRow
;
421 in
= buffer
+ header_size
;
423 for(il
? (i
= 0): (j
= 0);
424 il
? i
< bitmap_header
->bmh_Height
: j
< bitmap_header
->bmh_Depth
;
429 if(in
+ 1 < buffer_end
)
431 if(*((UWORD
*)in
) == 0)
433 if(in
+ 3 < buffer_end
)
436 repeat_count
= *(in
++);
437 if(repeat_count
!= 0)
441 error
= ERROR_OBJECT_WRONG_TYPE
;
446 for(il
? (j
= 0): (i
= 0);
447 il
? j
< bitmap_header
->bmh_Depth
: i
< bitmap_header
->bmh_Height
;
451 k
= bitmap_header
->bmh_Depth
- (j
+ 1);
454 out
= bitmap
->Planes
[k
] + out_line_size
* i
;
455 end_of_line
= out
+ in_line_size
;
458 CopyMem(out
- out_line_size
, out
, out_line_size
);
461 while(error
== 0 && out
< end_of_line
)
464 error
= ERROR_OBJECT_WRONG_TYPE
;
469 if((datum
& ~0x80) == 0)
472 error
= ERROR_OBJECT_WRONG_TYPE
;
478 in_stop
= in
+ pattern_size
;
479 out_stop
= out
+ pattern_size
* datum
;
480 if(in_stop
<= buffer_end
481 && out_stop
<= end_of_line
)
484 while(out
< out_stop
)
492 error
= ERROR_OBJECT_WRONG_TYPE
;
497 in_stop
= in
+ datum
;
498 if(in_stop
<= buffer_end
499 && out
+ datum
<= end_of_line
)
505 error
= ERROR_OBJECT_WRONG_TYPE
;
511 if((datum
& 0x80) != 0)
516 out_stop
= out
+ datum
;
517 if(out_stop
<= end_of_line
)
519 while(out
< out_stop
)
523 error
= ERROR_OBJECT_WRONG_TYPE
;
530 if(repeat_count
!= 0)
539 /* Check there isn't any unused picture data */
542 error
= ERROR_OBJECT_WRONG_TYPE
;
548 screen_mode
= BestModeID(
549 BIDTAG_DesiredWidth
, bitmap_header
->bmh_Width
,
550 BIDTAG_DesiredHeight
, bitmap_header
->bmh_Height
,
551 BIDTAG_NominalWidth
, (pixel_width
* bitmap_header
->bmh_Width
),
552 BIDTAG_NominalHeight
, (pixel_height
* bitmap_header
->bmh_Height
),
553 BIDTAG_Depth
, bitmap_header
->bmh_Depth
,
556 screen_mode
= BestModeID(
557 BIDTAG_NominalWidth
, bitmap_header
->bmh_Width
,
558 BIDTAG_NominalHeight
, bitmap_header
->bmh_Height
,
559 BIDTAG_Depth
, bitmap_header
->bmh_Depth
,
563 SetDTAttrs(object
, NULL
, NULL
,
565 (UPINT
)FilePart((APTR
)GetTagData(DTA_Name
, (UPINT
)NULL
, tags
)),
566 DTA_NominalHoriz
, bitmap_header
->bmh_Width
,
567 DTA_NominalVert
, bitmap_header
->bmh_Height
,
568 PDTA_BitMap
, (UPINT
)bitmap
,
569 PDTA_ModeID
, screen_mode
,
576 FreeDosObject(DOS_FIB
, info
);
581 CoerceMethod(class, object
, OM_DISPOSE
);
585 /* Return new object */
588 return (UPINT
)object
;