2 #include <dos/dosasl.h>
3 #include <dos/dosextens.h>
5 #include <dos/rdargs.h>
6 #include <exec/memory.h>
7 #include <exec/types.h>
8 #include <utility/utility.h>
10 #include <proto/arossupport.h>
11 #include <proto/dos.h>
12 #include <proto/exec.h>
13 #include <proto/graphics.h>
14 #include <proto/cybergraphics.h>
15 #include <proto/datatypes.h>
16 #include <proto/icon.h>
17 #include <workbench/workbench.h>
18 #include <workbench/icon.h>
19 #include <datatypes/pictureclass.h>
26 #define CTRL_C (SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
27 #define isDir(fib) ((fib)->fib_DirEntryType >= 0)
29 #define ARG_TEMPLATE "FILE/A,ALL/S,QUIET/S,W=WIDTH/N,H=HEIGHT/N,F=FORCEASPECT/S,M=METHOD,DEFTOOL"
44 /* Maximum file path length */
45 #define MAX_PATH_LEN 2048
47 const TEXT version
[] = "$VER: dt2thumb 1.1 (10.12.2010)\n";
48 static char cmdname
[] = "dt2thumb";
50 typedef struct rgbImage
58 int doThumbs(struct AnchorPath
*ap
, STRPTR files
, BOOL all
, BOOL quiet
,
59 ULONG destwidth
, ULONG destheight
, BOOL keepaspect
, STRPTR deftool
, STRPTR method
);
60 BOOL
CreateThumb(STRPTR infile
, ULONG destwidth
, ULONG destheight
, BOOL keepaspect
, STRPTR deftool
, STRPTR method
);
61 BOOL
readpic_by_datatype(RGBImage
*pic
, char *file_name
);
62 BOOL
savepic_by_datatype(RGBImage
*pic
, char *file_name
);
63 RGBImage
*resizeBilinear(RGBImage
*pic
, ULONG w2
, ULONG h2
);
64 RGBImage
*resizeNearest(RGBImage
*pic
, ULONG w2
, ULONG h2
);
65 RGBImage
*resizeAverage(RGBImage
*pic
, ULONG w2
, ULONG h2
);
70 struct RDArgs
*rda
= NULL
;
71 struct AnchorPath
*ap
= NULL
;
72 int retval
= RETURN_OK
;
77 ULONG destwidth
= 128;
78 ULONG destheight
= 128;
79 BOOL keepaspect
= TRUE
;
81 STRPTR deftool
= NULL
;
82 IPTR args
[NOOFARGS
] = { (IPTR
)files
, all
, quiet
, (IPTR
)&destwidth
, (IPTR
)&destheight
, !keepaspect
,(IPTR
)method
,(IPTR
)deftool
};
84 ap
= AllocVec(sizeof(struct AnchorPath
) + MAX_PATH_LEN
, MEMF_ANY
| MEMF_CLEAR
);
87 ap
->ap_Strlen
= MAX_PATH_LEN
;
89 rda
= ReadArgs(ARG_TEMPLATE
, args
, NULL
);
93 /* Convert arguments into (less complex) variables */
94 if (args
[ARG_FILE
]) files
= (STRPTR
)args
[ARG_FILE
];
95 if (args
[ARG_ALL
]) all
= TRUE
;
96 if (args
[ARG_QUIET
]) quiet
= TRUE
;
97 if (args
[ARG_WIDTH
]) destwidth
= (ULONG
)*((IPTR
*)args
[ARG_WIDTH
]);
98 if (args
[ARG_HEIGHT
]) destheight
= (ULONG
)*((IPTR
*)args
[ARG_HEIGHT
]);
99 if (args
[ARG_FORCEASPECT
]) keepaspect
= FALSE
;
100 if (args
[ARG_METHOD
]) method
= (STRPTR
)args
[ARG_METHOD
];
101 if (args
[ARG_DEFTOOL
]) deftool
= (STRPTR
)args
[ARG_DEFTOOL
];
103 if (!all
&&IsDosEntryA(files
, LDF_VOLUMES
| LDF_DEVICES
))
105 Printf("Can't create thumb for %s - ", files
);
106 SetIoErr(ERROR_OBJECT_WRONG_TYPE
);
107 PrintFault(IoErr(), NULL
);
109 retval
= RETURN_FAIL
;
112 retval
= doThumbs(ap
, files
, all
, quiet
, destwidth
, destheight
, keepaspect
, deftool
, method
);
118 PrintFault(IoErr(), cmdname
);
119 retval
= RETURN_FAIL
;
122 if (ap
!=NULL
) FreeVec(ap
);
126 retval
= RETURN_FAIL
;
132 int doThumbs(struct AnchorPath
*ap
, STRPTR files
, BOOL all
, BOOL quiet
,
133 ULONG destwidth
, ULONG destheight
, BOOL keepaspect
, STRPTR deftool
, STRPTR method
)
136 int retval
= RETURN_OK
;
138 int i
; /* Loop variable */
141 for (match
= MatchFirst(files
, ap
);
142 match
== 0 && retval
== RETURN_OK
;// && !CTRL_C;
143 match
= MatchNext(ap
))
145 if (isDir(&ap
->ap_Info
))
147 if (ap
->ap_Flags
& APF_DIDDIR
)
150 ap
->ap_Flags
&= ~APF_DIDDIR
; /* Should not be necessary */
155 ap
->ap_Flags
|= APF_DODIR
;
161 error
= CreateThumb(ap
->ap_Buf
, destwidth
, destheight
, keepaspect
, deftool
, method
);
165 /* Fix indentation level */
166 for (i
= 0; i
< indent
; i
++)
171 if (!isDir(&ap
->ap_Info
))
176 PutStr(ap
->ap_Info
.fib_FileName
);
178 if (isDir(&ap
->ap_Info
))
185 PutStr(" ..Not a known picture file\n");
189 PutStr(" ..Thumbnail created\n");
199 STRPTR
get_ext(char *filename
)
201 static char extension
[32];
202 int position
=strlen((char *)filename
)-1;
204 strcpy(extension
,"");
206 while(position
> -1 && filename
[position
] != '.') position
--;
210 strncpy(extension
,&filename
[position
+1],32);
216 BOOL
CreateThumb(STRPTR infile
, ULONG destwidth
, ULONG destheight
, BOOL keepaspect
, STRPTR deftool
, STRPTR method
)
218 RGBImage
*in_pic
= NULL
, *out_pic
= NULL
;
219 char outfile
[MAX_PATH_LEN
];
222 // do not create thumb for info files
223 if (strnicmp(get_ext(infile
),"info",4)==0) return retval
;
225 sprintf(outfile
,"%s.info",infile
);
227 if ((in_pic
= (RGBImage
*)AllocVec(sizeof(RGBImage
),MEMF_ANY
)))
230 if (readpic_by_datatype(in_pic
, infile
))
234 int arw
= in_pic
->Width
/ destwidth
;
235 int arh
= in_pic
->Height
/ destheight
;
237 if (arw
> arh
) destheight
= in_pic
->Height
/ arw
;
238 else if (arh
> arw
) destwidth
= in_pic
->Width
/ arh
;
243 if (strnicmp(method
,"BI",2)==0)
244 out_pic
= resizeBilinear(in_pic
, destwidth
, destheight
);
245 else if (strnicmp(method
,"AV",2)==0)
246 out_pic
= resizeAverage(in_pic
, destwidth
, destheight
);
248 out_pic
= resizeNearest(in_pic
, destwidth
, destheight
);
251 out_pic
= resizeNearest(in_pic
, destwidth
, destheight
);
255 if (savepic_by_datatype(out_pic
, outfile
))
257 // Write default tool
258 struct DiskObject
*icon
= GetIconTags
260 infile
, ICONGETA_FailIfUnavailable
, FALSE
, TAG_DONE
265 STRPTR oldDefaultTool
= icon
->do_DefaultTool
;
268 icon
->do_DefaultTool
= deftool
;
271 static STRPTR tool
= "multiview";
272 icon
->do_DefaultTool
= tool
;
274 if (!PutIconTags(infile
, icon
, TAG_DONE
))
276 Printf("ERROR: Failed to write icon.\n");
278 icon
->do_DefaultTool
= oldDefaultTool
;
280 FreeDiskObject(icon
);
286 Printf("ERROR: Failed to open icon for file\n");
294 if (in_pic
->Data
) FreeVec(in_pic
->Data
);
299 if (out_pic
->Data
) FreeVec(out_pic
->Data
);
308 BOOL
readpic_by_datatype(RGBImage
*pic
, char *file_name
)
310 Object
*DTImage
= NULL
;
311 struct BitMapHeader
*bmh
;
312 struct pdtBlitPixelArray bpa
;
314 DTImage
= NewDTObject( file_name
,
315 (DTA_SourceType
), DTST_FILE
,
316 (DTA_GroupID
), GID_PICTURE
,
318 (OBP_Precision
), PRECISION_EXACT
,
324 if (GetDTAttrs( DTImage
,
325 PDTA_BitMapHeader
, &bmh
,
330 /* Picture struct and buffer mem allocation */
331 pic
->Data
= (UBYTE
*)AllocVec(bmh
->bmh_Width
* bmh
->bmh_Height
* 4, MEMF_ANY
);
334 bpa
.MethodID
= PDTM_READPIXELARRAY
;
335 bpa
.pbpa_PixelData
= (APTR
)pic
->Data
;
336 bpa
.pbpa_PixelFormat
= PBPAFMT_ARGB
;
337 bpa
.pbpa_PixelArrayMod
= bmh
->bmh_Width
* 4;
340 bpa
.pbpa_Width
= bmh
->bmh_Width
;
341 bpa
.pbpa_Height
= bmh
->bmh_Height
;
343 DoMethodA( DTImage
, (Msg
)&bpa
);
345 pic
->Width
= bmh
->bmh_Width
;
346 pic
->Height
= bmh
->bmh_Height
;
348 DisposeDTObject( DTImage
);
353 DisposeDTObject( DTImage
);
360 * Nearest Neighbor resizing algorithm
361 * In case of thumbnail generation the loss of quality
362 * should be minimal vs the bilinear algorithm
364 RGBImage
*resizeNearest(RGBImage
*pic
, ULONG w2
, ULONG h2
)
367 RGBImage
*outpic
= NULL
;
368 ULONG
*pixels
= (ULONG
*)pic
->Data
;
369 ULONG x_ratio
= (ULONG
)((pic
->Width
<<16)/w2
) +1;
370 ULONG y_ratio
= (ULONG
)((pic
->Height
<<16)/h2
) +1;
373 if ((outpic
= (RGBImage
*)AllocVec(sizeof(RGBImage
),MEMF_ANY
)))
376 if ((outpic
->Data
= (UBYTE
*)AllocVec(w2
*h2
*4, MEMF_ANY
)))
380 temp
= (ULONG
*)outpic
->Data
;
384 y2
= ((i
*y_ratio
)>>16) ;
387 x2
= ((j
*x_ratio
)>>16) ;
388 temp
[(i
*w2
)+j
] = pixels
[(y2
*pic
->Width
)+x2
] ;
396 #define max(x,y) (x)>(y)?(x):(y)
397 #define min(x,y) (x)<(y)?(x):(y)
400 * Averaging resizing algorithm
404 RGBImage
*resizeAverage(RGBImage
*pic
, ULONG w2
, ULONG h2
)
407 RGBImage
*outpic
= NULL
;
408 ULONG
*pixels
= (ULONG
*)pic
->Data
;
409 ULONG xpixels
= min(256,max((ULONG
)(pic
->Width
/w2
),1));
410 ULONG ypixels
= min(256,max((ULONG
)(pic
->Height
/h2
),1));
411 ULONG x_ratio
= (ULONG
)((pic
->Width
<<16)/w2
) +1;
412 ULONG y_ratio
= (ULONG
)((pic
->Height
<<16)/h2
) +1;
416 if ((outpic
= (RGBImage
*)AllocVec(sizeof(RGBImage
),MEMF_ANY
)))
419 if ((outpic
->Data
= (UBYTE
*)AllocVec(w2
*h2
*4, MEMF_ANY
)))
423 temp
= (ULONG
*)outpic
->Data
;
427 y2
= ((i
*y_ratio
)>>16) ;
430 x2
= ((j
*x_ratio
)>>16) ;
437 for (y
=0;y
<ypixels
;y
++)
438 for (x
=0;x
<xpixels
;x
++)
440 index
= ((y2
+y
)*pic
->Width
+(x2
+x
));
441 b
+= (pixels
[index
]&0xff);
442 g
+= ((pixels
[index
]>>8)&0xff);
443 r
+= ((pixels
[index
]>>16)&0xff);
444 a
+= ((pixels
[index
]>>24)&0xff);
447 r
/= (ypixels
*xpixels
);
448 g
/= (ypixels
*xpixels
);
449 b
/= (ypixels
*xpixels
);
450 a
/= (ypixels
*xpixels
);
452 temp
[(i
*w2
)+j
] = ((((ULONG
)a
)<<24) & 0xff000000) |
453 ((((ULONG
)r
)<<16) & 0x00ff0000) |
454 ((((ULONG
)g
)<<8) & 0x0000ff00) |
464 * Bilinear resize ARGB image.
465 * pixels is an array of size w * h.
466 * Target dimension is w2 * h2.
467 * w2 * h2 cannot be zero.
469 RGBImage
*resizeBilinear(RGBImage
*pic
, ULONG w2
, ULONG h2
)
472 RGBImage
*outpic
= NULL
;
473 ULONG
*pixels
= (ULONG
*)pic
->Data
;
474 ULONG a
, b
, c
, d
, x
, y
, index
;
475 float x_ratio
= ((float)(pic
->Width
-1))/w2
;
476 float y_ratio
= ((float)(pic
->Height
-1))/h2
;
477 float x_diff
, y_diff
, blue
, red
, green
, alpha
;
481 if ((outpic
= (RGBImage
*)AllocVec(sizeof(RGBImage
),MEMF_ANY
)))
483 if ((outpic
->Data
= (UBYTE
*)AllocVec(w2
*h2
*4, MEMF_ANY
)))
487 temp
= (ULONG
*)outpic
->Data
;
489 if ((pic
->Width
==w2
) && (pic
->Height
=h2
))
491 CopyMem(pixels
, temp
, pic
->Width
* pic
->Height
* 4);
499 x
= (ULONG
)(x_ratio
* j
) ;
500 y
= (ULONG
)(y_ratio
* i
) ;
501 x_diff
= (x_ratio
* j
) - x
;
502 y_diff
= (y_ratio
* i
) - y
;
503 index
= (y
*pic
->Width
+x
) ;
505 b
= pixels
[index
+1] ;
506 c
= pixels
[index
+pic
->Width
] ;
507 d
= pixels
[index
+pic
->Width
+1] ;
510 // Yb = Ab(1-w)(1-h) + Bb(w)(1-h) + Cb(h)(1-w) + Db(wh)
511 blue
= (a
&0xff)*(1-x_diff
)*(1-y_diff
) + (b
&0xff)*(x_diff
)*(1-y_diff
) +
512 (c
&0xff)*(y_diff
)*(1-x_diff
) + (d
&0xff)*(x_diff
*y_diff
);
515 // Yg = Ag(1-w)(1-h) + Bg(w)(1-h) + Cg(h)(1-w) + Dg(wh)
516 green
= ((a
>>8)&0xff)*(1-x_diff
)*(1-y_diff
) + ((b
>>8)&0xff)*(x_diff
)*(1-y_diff
) +
517 ((c
>>8)&0xff)*(y_diff
)*(1-x_diff
) + ((d
>>8)&0xff)*(x_diff
*y_diff
);
520 // Yr = Ar(1-w)(1-h) + Br(w)(1-h) + Cr(h)(1-w) + Dr(wh)
521 red
= ((a
>>16)&0xff)*(1-x_diff
)*(1-y_diff
) + ((b
>>16)&0xff)*(x_diff
)*(1-y_diff
) +
522 ((c
>>16)&0xff)*(y_diff
)*(1-x_diff
) + ((d
>>16)&0xff)*(x_diff
*y_diff
);
525 // Yr = Ar(1-w)(1-h) + Br(w)(1-h) + Cr(h)(1-w) + Dr(wh)
526 alpha
= ((a
>>24)&0xff)*(1-x_diff
)*(1-y_diff
) + ((b
>>24)&0xff)*(x_diff
)*(1-y_diff
) +
527 ((c
>>24)&0xff)*(y_diff
)*(1-x_diff
) + ((d
>>24)&0xff)*(x_diff
*y_diff
);
530 temp
[offset
++] = ((((ULONG
)alpha
)<<24) & 0xff000000) |
531 ((((ULONG
)red
) <<16) & 0x00ff0000) |
532 ((((ULONG
)green
)<<8) & 0x0000ff00) |
541 BOOL
savepic_by_datatype(RGBImage
*pic
, char *file_name
)
543 Object
*DTImage
= NULL
;
544 struct BitMapHeader
*bmhd
;
546 struct pdtBlitPixelArray dtb
;
550 DTImage
= NewDTObject( (APTR
)NULL
,
551 DTA_SourceType
, DTST_RAM
,
552 DTA_BaseName
, (IPTR
)"png",
553 PDTA_DestMode
, PMODE_V43
,
555 if (!DTImage
) return(FALSE
);
558 if (GetDTAttrs(DTImage
,PDTA_BitMapHeader
,(IPTR
)&bmhd
,TAG_DONE
))
560 dtb
.MethodID
= PDTM_WRITEPIXELARRAY
;
561 dtb
.pbpa_PixelData
= pic
->Data
;
562 dtb
.pbpa_PixelFormat
= PBPAFMT_ARGB
;
563 dtb
.pbpa_PixelArrayMod
= pic
->Width
*4;
566 dtb
.pbpa_Width
= pic
->Width
;
567 dtb
.pbpa_Height
= pic
->Height
;
569 bmhd
->bmh_Width
= pic
->Width
;
570 bmhd
->bmh_Height
= pic
->Height
;
571 bmhd
->bmh_Depth
= 24;
572 bmhd
->bmh_PageWidth
= 320;
573 bmhd
->bmh_PageHeight
= 240;
575 DoMethodA(DTImage
, (Msg
) &dtb
);
577 //write datatype object to file
578 if ((file
= Open (file_name
,MODE_NEWFILE
)))
580 dtw
.MethodID
= DTM_WRITE
;
581 dtw
.dtw_GInfo
= NULL
;
582 dtw
.dtw_FileHandle
= file
;
583 dtw
.dtw_Mode
= DTWM_RAW
;
584 dtw
.dtw_AttrList
= NULL
;
586 if (DoMethodA(DTImage
, (Msg
) &dtw
)) retval
= TRUE
;
590 if (file
) Close (file
);
591 if (DTImage
) DisposeDTObject(DTImage
);