file is a BPTR, not BPTR *
[AROS-Contrib.git] / gfx / dt2thumb / Datatype2Thumb.c
blobdcc760cf9bfe261f3375996c718714ea454186a4
1 #include <dos/dos.h>
2 #include <dos/dosasl.h>
3 #include <dos/dosextens.h>
4 #include <dos/exall.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>
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.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"
31 enum
33 ARG_FILE = 0,
34 ARG_ALL,
35 ARG_QUIET,
36 ARG_WIDTH,
37 ARG_HEIGHT,
38 ARG_FORCEASPECT,
39 ARG_METHOD,
40 ARG_DEFTOOL,
41 NOOFARGS
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
52 UWORD Width;
53 UWORD Height;
54 UBYTE *Data;
56 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);
68 int main(void)
70 struct RDArgs *rda = NULL;
71 struct AnchorPath *ap = NULL;
72 int retval = RETURN_OK;
74 STRPTR files = "#?";
75 BOOL all = FALSE;
76 BOOL quiet = FALSE;
77 ULONG destwidth = 128;
78 ULONG destheight = 128;
79 BOOL keepaspect = TRUE;
80 STRPTR method = NULL;
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);
85 if (ap != NULL)
87 ap->ap_Strlen = MAX_PATH_LEN;
89 rda = ReadArgs(ARG_TEMPLATE, args, NULL);
91 if (rda != 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;
111 else
112 retval = doThumbs(ap, files, all, quiet, destwidth, destheight, keepaspect, deftool, method);
114 FreeArgs(rda);
116 else
118 PrintFault(IoErr(), cmdname);
119 retval = RETURN_FAIL;
122 if (ap!=NULL) FreeVec(ap);
124 else
126 retval = RETURN_FAIL;
129 return retval;
130 } /* main */
132 int doThumbs(struct AnchorPath *ap, STRPTR files, BOOL all, BOOL quiet,
133 ULONG destwidth, ULONG destheight, BOOL keepaspect, STRPTR deftool, STRPTR method)
135 LONG match;
136 int retval = RETURN_OK;
137 LONG indent = 0;
138 int i; /* Loop variable */
139 BOOL error;
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)
149 indent--;
150 ap->ap_Flags &= ~APF_DIDDIR; /* Should not be necessary */
151 continue;
153 else if (all)
155 ap->ap_Flags |= APF_DODIR;
156 indent++;
161 error = CreateThumb(ap->ap_Buf, destwidth, destheight, keepaspect, deftool, method);
163 if (!quiet)
165 /* Fix indentation level */
166 for (i = 0; i < indent; i++)
168 PutStr(" ");
171 if (!isDir(&ap->ap_Info))
173 PutStr(" ");
176 PutStr(ap->ap_Info.fib_FileName);
178 if (isDir(&ap->ap_Info))
180 PutStr(" (dir)");
183 if (error)
185 PutStr(" ..Not a known picture file\n");
187 else
189 PutStr(" ..Thumbnail created\n");
194 MatchEnd(ap);
196 return retval;
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--;
208 if (position > -1)
210 strncpy(extension,&filename[position+1],32);
213 return extension;
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];
220 BOOL retval = TRUE;
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)))
229 in_pic->Data = NULL;
230 if (readpic_by_datatype(in_pic, infile))
232 if (keepaspect)
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;
241 if (method != NULL)
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);
247 else
248 out_pic = resizeNearest(in_pic, destwidth, destheight);
250 else
251 out_pic = resizeNearest(in_pic, destwidth, destheight);
253 if (out_pic)
255 if (savepic_by_datatype(out_pic, outfile))
257 // Write default tool
258 struct DiskObject *icon = GetIconTags
260 infile, ICONGETA_FailIfUnavailable, FALSE, TAG_DONE
263 if (icon != NULL)
265 STRPTR oldDefaultTool = icon->do_DefaultTool;
267 if (deftool)
268 icon->do_DefaultTool = deftool;
269 else
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);
282 retval = FALSE;
284 else
286 Printf("ERROR: Failed to open icon for file\n");
287 retval = TRUE;;
292 if (in_pic)
294 if (in_pic->Data) FreeVec(in_pic->Data);
295 FreeVec(in_pic);
297 if (out_pic)
299 if (out_pic->Data) FreeVec(out_pic->Data);
300 FreeVec(out_pic);
304 return retval;
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,
317 (PDTA_Remap), FALSE,
318 (OBP_Precision), PRECISION_EXACT,
319 TAG_DONE);
321 if (DTImage)
324 if (GetDTAttrs( DTImage,
325 PDTA_BitMapHeader, &bmh,
326 TAG_END ) == 1)
330 /* Picture struct and buffer mem allocation */
331 pic->Data = (UBYTE *)AllocVec(bmh->bmh_Width * bmh->bmh_Height * 4, MEMF_ANY);
332 if (pic->Data)
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;
338 bpa.pbpa_Left = 0;
339 bpa.pbpa_Top = 0;
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 );
350 return TRUE;
353 DisposeDTObject( DTImage );
355 return FALSE;
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)
366 ULONG *temp = NULL;
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;
371 ULONG x2,y2,i,j;
373 if ((outpic = (RGBImage *)AllocVec(sizeof(RGBImage),MEMF_ANY)))
375 outpic->Data = NULL;
376 if ((outpic->Data = (UBYTE *)AllocVec(w2*h2*4, MEMF_ANY)))
378 outpic->Width = w2;
379 outpic->Height = h2;
380 temp = (ULONG *)outpic->Data;
382 for (i=0;i<h2;i++)
384 y2 = ((i*y_ratio)>>16) ;
385 for (j=0;j<w2;j++)
387 x2 = ((j*x_ratio)>>16) ;
388 temp[(i*w2)+j] = pixels[(y2*pic->Width)+x2] ;
393 return outpic;
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)
406 ULONG *temp = NULL;
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;
413 ULONG r,g,b,a,index;
414 ULONG x2,y2,i,j,x,y;
416 if ((outpic = (RGBImage *)AllocVec(sizeof(RGBImage),MEMF_ANY)))
418 outpic->Data = NULL;
419 if ((outpic->Data = (UBYTE *)AllocVec(w2*h2*4, MEMF_ANY)))
421 outpic->Width = w2;
422 outpic->Height = h2;
423 temp = (ULONG *)outpic->Data;
425 for (i=0;i<h2;i++)
427 y2 = ((i*y_ratio)>>16) ;
428 for (j=0;j<w2;j++)
430 x2 = ((j*x_ratio)>>16) ;
432 r = 0;
433 g = 0;
434 b = 0;
435 a = 0;
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) |
455 ((ULONG)b) ;
460 return outpic;
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)
471 ULONG *temp = NULL;
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 ;
478 ULONG offset = 0 ;
479 int i,j;
481 if ((outpic = (RGBImage *)AllocVec(sizeof(RGBImage),MEMF_ANY)))
483 if ((outpic->Data = (UBYTE *)AllocVec(w2*h2*4, MEMF_ANY)))
485 outpic->Width = w2;
486 outpic->Height = h2;
487 temp = (ULONG *)outpic->Data;
489 if ((pic->Width==w2) && (pic->Height=h2))
491 CopyMem(pixels, temp, pic->Width * pic->Height * 4);
492 return outpic;
495 for (i=0;i<h2;i++)
497 for (j=0;j<w2;j++)
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) ;
504 a = pixels[index] ;
505 b = pixels[index+1] ;
506 c = pixels[index+pic->Width] ;
507 d = pixels[index+pic->Width+1] ;
509 // blue element
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);
514 // green element
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);
519 // red element
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);
524 // alpha element
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) |
533 ((ULONG)blue) ;
538 return outpic ;
541 BOOL savepic_by_datatype(RGBImage *pic, char *file_name)
543 Object *DTImage = NULL;
544 struct BitMapHeader *bmhd;
545 struct dtWrite dtw;
546 struct pdtBlitPixelArray dtb;
547 BPTR file = NULL;
548 BOOL retval = FALSE;
550 DTImage = NewDTObject( (APTR)NULL,
551 DTA_SourceType, DTST_RAM,
552 DTA_BaseName, (IPTR)"png",
553 PDTA_DestMode, PMODE_V43,
554 TAG_DONE);
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;
564 dtb.pbpa_Left = 0;
565 dtb.pbpa_Top = 0;
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);
592 return retval;