Faster resize image
- 
				Blade
 - Enthusiast

 - Posts: 362
 - Joined: Wed Aug 06, 2003 2:49 pm
 - Location: Venice - Italy, Japan when possible.
 - Contact:
 
Faster resize image
Is there a faster way to resize an image than ResizeImage() ?
I wish to generate thumbnails of all images inside a directory, by it take ages to compute even in my 2400+ Athlon!
The ResizeImage quality is photoshop-like (too good) perhaps a simple stretch could be enough...
p.s.
using "StretchBlt_" seems to badly reduce the images to 256 colors...
			
			
									
									
						I wish to generate thumbnails of all images inside a directory, by it take ages to compute even in my 2400+ Athlon!
The ResizeImage quality is photoshop-like (too good) perhaps a simple stretch could be enough...
p.s.
using "StretchBlt_" seems to badly reduce the images to 256 colors...
Re: Faster resize image
> Is there a faster way to resize an image than ResizeImage() ?
I need this, too. My images are all 1280x1024 and I have to load them, then
resize them to a new image thumbnail, which is slow because I have to copy
them first and then resize the copy (I need to retain the original image).
Using #PB_Image_Raw is no good because the resized images are 386x202
and having a raw resize makes the quality basically useless. Does anyone
have any API examples that could do what I want, faster? Here's the code
I'm currently using. Surely it can be done faster than that?
Here's what my thumbnails look like without and with smoothing, and why
I don't want to use #PB_Image_Raw:


			
			
									
									I need this, too. My images are all 1280x1024 and I have to load them, then
resize them to a new image thumbnail, which is slow because I have to copy
them first and then resize the copy (I need to retain the original image).
Using #PB_Image_Raw is no good because the resized images are 386x202
and having a raw resize makes the quality basically useless. Does anyone
have any API examples that could do what I want, faster? Here's the code
I'm currently using. Surely it can be done faster than that?
Code: Select all
LoadImage(#Img_ScreenShot,shotname$)
CopyImage(#Img_ScreenShot,#Img_ScreenShotThumb)
SetGadgetState(#shotview,ResizeImage(#Img_ScreenShotThumb,386,202))
I don't want to use #PB_Image_Raw:


I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
						"PureBasic won't be object oriented, period" - Fred.
Re: Faster resize image
Okay, I re-coded the routine so that it loads the original, resizes that raw, and
shows that as the thumbnail. Ugly, but I guess I can live with it. (Maybe I'll
put an option in my app where the user can select if they want smoothing or
not, and leave it up to them to live with the slower speed?).
I will then only show the fullsize image (by reloading it) if the user selects the
thumbnail, rather than my first approach of loading it, copying it, and resizing
the copy. Just goes to show that a bit of re-coding can speed things up too.
(But a faster ResizeImage would still be very nice).
			
			
									
									shows that as the thumbnail. Ugly, but I guess I can live with it. (Maybe I'll
put an option in my app where the user can select if they want smoothing or
not, and leave it up to them to live with the slower speed?).
I will then only show the fullsize image (by reloading it) if the user selects the
thumbnail, rather than my first approach of loading it, copying it, and resizing
the copy. Just goes to show that a bit of re-coding can speed things up too.
(But a faster ResizeImage would still be very nice).
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
						"PureBasic won't be object oriented, period" - Fred.
- netmaestro
 - PureBasic Bullfrog

 - Posts: 8452
 - Joined: Wed Jul 06, 2005 5:42 am
 - Location: Fort Nelson, BC, Canada
 
Blade and PB, I may have something for you. I thought your challenge looked interesting so I put something together using gdiplus. Feed it a 1280*1024 image and run the test. Here it's creating 50 thumbnails 2.5 to 5 times faster than ResizeImage (depending on format) and the quality is photoshop-level imho:
I just tested against this code:
PNG results: Using ResizeImage() the 50 images took 12 seconds vs. 5 for the gdiplus version. 
JPEG results: ResizeImage() took 5 seconds, gdiplus took 1 second.
It's also beating ResizeImage with #PB_Image_Raw by a significant margin.
			
			
									
									
						Code: Select all
; netmaestro's gdiplus thumbnail creator
;
;----------------------------------------------------------------------------
;                     GDIPlus Initialization Section
;----------------------------------------------------------------------------
;
CompilerIf Defined(GdiplusStartupInput, #PB_Structure) = 0
  Structure GdiplusStartupInput 
    GdiPlusVersion.l 
    *DebugCallback
    SuppressBackgroundThread.l 
    SuppressExternalCodecs.l 
  EndStructure 
CompilerEndIf  
Global PixelFormatIndexed        = $00010000 ; Indexes into a palette
Global PixelFormatGDI            = $00020000 ; Is a GDI-supported format
Global PixelFormatAlpha          = $00040000 ; Has an alpha component
Global PixelFormatPAlpha         = $00080000 ; Pre-multiplied alpha
Global PixelFormatExtended       = $00100000 ; Extended color 16 bits/channel
Global PixelFormatCanonical      = $00200000 
Global PixelFormatUndefined      = 0
Global PixelFormatDontCare       = 0 
Global PixelFormat1bppIndexed    = (1 | ( 1 << 8) |PixelFormatIndexed |PixelFormatGDI)
Global PixelFormat4bppIndexed    = (2 | ( 4 << 8) |PixelFormatIndexed |PixelFormatGDI)
Global PixelFormat8bppIndexed    = (3 | ( 8 << 8) |PixelFormatIndexed |PixelFormatGDI)
Global PixelFormat16bppGrayScale = (4 | (16 << 8) |PixelFormatExtended) ; $100
Global PixelFormat16bppRGB555    = (5 | (16 << 8) |PixelFormatGDI)
Global PixelFormat16bppRGB565    = (6 | (16 << 8) |PixelFormatGDI)
Global PixelFormat16bppARGB1555  = (7 | (16 << 8) |PixelFormatAlpha |PixelFormatGDI)
Global PixelFormat24bppRGB       = (8 | (24 << 8) |PixelFormatGDI)
Global PixelFormat32bppRGB       = (9 | (32 << 8) |PixelFormatGDI)
Global PixelFormat32bppARGB      = (10 | (32 << 8) |PixelFormatAlpha |PixelFormatGDI |PixelFormatCanonical)
Global PixelFormat32bppPARGB     = (11 | (32 << 8) |PixelFormatAlpha |PixelFormatPAlpha |PixelFormatGDI)
Global PixelFormat48bppRGB       = (12 | (48 << 8) |PixelFormatExtended)
Global PixelFormat64bppARGB      = (13 | (64 << 8) |PixelFormatAlpha  |PixelFormatCanonical |PixelFormatExtended)
Global PixelFormat64bppPARGB     = (14 | (64 << 8) |PixelFormatAlpha  |PixelFormatPAlpha |PixelFormatExtended)
Global PixelFormatMax            =  15  
Prototype GdiplusStartup( *token, *input, mode )
Prototype GdipCreateBitmapFromFile( Filename, *image )
Prototype GdipGetImageWidth( *image, *Width )
Prototype GdipGetImageHeight( *image, *Height )
Prototype GdipGetImagePixelFormat( *image, *Format )
Prototype GdipCreateFromHDC( hdc, *gfx)
Prototype GdipDrawImageRectI( *gfx, *image, x, y, Width, Height ) 
Prototype GdipDeleteGraphics( *gfx ) 
Prototype GdipDisposeImage( *image )
Prototype GdiplusShutdown( *token ) 
OpenLibrary(0, "gdiplus.dll")
Global Startup.GdiplusStartup                        = GetFunction( 0, "GdiplusStartup" )         
Global CreateBitmapFromFile.GdipCreateBitmapFromFile = GetFunction( 0, "GdipCreateBitmapFromFile" )
Global GetImageWidth.GdipGetImageWidth               = GetFunction( 0, "GdipGetImageWidth" )               
Global GetImageHeight.GdipGetImageHeight             = GetFunction( 0, "GdipGetImageHeight" )     
Global GetImagePixelFormat.GdipGetImagePixelFormat   = GetFunction( 0, "GdipGetImagePixelFormat" )
Global CreateFromHDC.GdipCreateFromHDC               = GetFunction( 0, "GdipCreateFromHDC" )      
Global DrawImageRectI.GdipDrawImageRectI             = GetFunction( 0, "GdipDrawImageRectI" )     
Global DeleteGraphics.GdipDeleteGraphics             = GetFunction( 0, "GdipDeleteGraphics" )     
Global DisposeImage.GdipDisposeImage                 = GetFunction( 0, "GdipDisposeImage" )       
Global Shutdown.GdiplusShutdown                      = GetFunction( 0, "GdiplusShutdown" )  
;      
;-----------------------------------------------------------------------------
;                      End GDIPlus Initialization Section
;-----------------------------------------------------------------------------
Procedure StringToBStr (string$) ; By Zapman Inspired by Fr34k 
  Protected Unicode$ = Space(Len(String$)* 2 + 2) 
  Protected bstr_string.l 
  PokeS(@Unicode$, String$, -1, #PB_Unicode) 
  bstr_string = SysAllocString_(@Unicode$) 
  ProcedureReturn bstr_string 
EndProcedure
ProcedureDLL LoadThumbnail(ImageNumber, xsize, ysize, Filename.s)
  input.GdiplusStartupInput
  input\GdiPlusVersion = 1
  Startup( @*token, @input, #Null)
  CreateBitmapFromFile( StringToBStr(Filename), @*image)
  
  GetImageWidth( *image, @Width.l )
  GetImageHeight( *image, @Height.l )
  GetImagePixelFormat( *image, @Format.l )
  Select Format
    Case PixelFormat1bppIndexed: bits_per_pixel = 1
    Case PixelFormat4bppIndexed: bits_per_pixel = 4
    Case PixelFormat8bppIndexed: bits_per_pixel = 8
    Case PixelFormat16bppARGB1555: bits_per_pixel = 16
    Case PixelFormat16bppGrayScale: bits_per_pixel = 16
    Case PixelFormat16bppRGB555: bits_per_pixel = 16
    Case PixelFormat16bppRGB565: bits_per_pixel = 16
    Case PixelFormat24bppRGB: bits_per_pixel = 24
    Case PixelFormat32bppARGB: bits_per_pixel = 32
    Case PixelFormat32bppPARGB: bits_per_pixel = 32
    Case PixelFormat32bppRGB: bits_per_pixel = 32
    Case PixelFormat48bppRGB: bits_per_pixel = 48
    Case PixelFormat64bppARGB: bits_per_pixel = 64
    Case PixelFormat64bppPARGB: bits_per_pixel = 64
    Default : bits_per_pixel = 32
  EndSelect
  Retval = CreateImage(ImageNumber, xsize, ysize, bits_per_pixel)
  hDC = StartDrawing(ImageOutput(ImageNumber))
    CreateFromHDC( hdc, @*gfx )
    DrawImageRectI( *gfx, *image, 0, 0, xsize, ysize )
  StopDrawing()  
  DeleteGraphics( *gfx )  
  
  DisposeImage( *image )
  Shutdown( *token )
  
  ProcedureReturn Retval
EndProcedure
tt = ElapsedMilliseconds()
For i = 1 To 50
  LoadThumbnail(0, 382, 202, "desktop.png") ; input image can be any size; parameters are for thumbnail-out size
Next
MessageRequester("Time to create 50 Thumbnails:",Str((ElapsedMilliseconds()-tt)/1000)+" seconds")
CloseLibrary(0)
OpenWindow(0,0,0,382,202,"",$CF0001)
CreateGadgetList(WindowID(0))
ImageGadget(0,0,0,0,0,ImageID(0))
Repeat:Until WaitWindowEvent() = #WM_CLOSE
Code: Select all
UsePNGImageDecoder()
tt = ElapsedMilliseconds()
For i = 1 To 50
  LoadImage(0, "desktop.png")
  ResizeImage(0, 382,202,#PB_Image_Smooth)
Next
MessageRequester("Time to create 50 Thumbnails:",Str((ElapsedMilliseconds()-tt)/1000)+" seconds")
CloseLibrary(0)
OpenWindow(0,0,0,382,202,"",$CF0001)
CreateGadgetList(WindowID(0))
ImageGadget(0,0,0,0,0,ImageID(0))
Repeat:Until WaitWindowEvent() = #WM_CLOSEJPEG results: ResizeImage() took 5 seconds, gdiplus took 1 second.
It's also beating ResizeImage with #PB_Image_Raw by a significant margin.
This is one mighty nice routine and extremely timely. I'm resizing images of undetermined size down to thumbs and this speeds it up tremendously.
No timing tests yet, but using resize in my program, it can take several seconds and is noticeably slow. This external routine rendered the same image in much less time.
I'll get a timing test after I insert this routine into my program.
Pure genius.
cheers
			
			
									
									
						No timing tests yet, but using resize in my program, it can take several seconds and is noticeably slow. This external routine rendered the same image in much less time.
I'll get a timing test after I insert this routine into my program.
Pure genius.
cheers
- netmaestro
 - PureBasic Bullfrog

 - Posts: 8452
 - Joined: Wed Jul 06, 2005 5:42 am
 - Location: Fort Nelson, BC, Canada
 
And thanks for pointing that out. I always tend to add these things without thinking out the platform considerations. Got into trouble on some transparent windows code too.netmaestro wrote:
I hope it pans out for you. Just remember that WinXP is the only OS that natively includes gdiplus.dll. For other target OS's you must distribute the dll with your app. (MS says it's redistributable)
Guess I better have a look at Flype's lib:)
Thanks again
This is going to be a great help for me, I tried to find this kind of solution earlier this year!
Look->http://www.purebasic.fr/english/viewtop ... size+image
Thanks a ot Netmaestro!
Timo
			
			
									
									
						Look->http://www.purebasic.fr/english/viewtop ... size+image
Thanks a ot Netmaestro!
Timo
- 
				SoulReaper
 - Enthusiast

 - Posts: 372
 - Joined: Sun Apr 03, 2005 2:14 am
 - Location: England
 
- netmaestro
 - PureBasic Bullfrog

 - Posts: 8452
 - Joined: Wed Jul 06, 2005 5:42 am
 - Location: Fort Nelson, BC, Canada
 
Thanks Sparkie, I modified the procedure to do the resizing with GdipGetImageThumbnail, but it didn't change the speed any. It's going to be slower than the task you describe as it has to make a PB image out of the thumbnail, if it could just do a GdipSaveImageToFile without creating an HBITMAP it would go much faster. I can write a version that does that if that's generally desired. Or you can if you have time. Your coding is better than mine.
[useless code removed]
			
			
													[useless code removed]
					Last edited by netmaestro on Sat Nov 11, 2006 7:49 pm, edited 1 time in total.
									
			
									
						I know you didn't want to use the raw resize mode of PB, but in case someone else does, check the speed differences in this code:
			
			
									
									
						Code: Select all
OpenWindow(0, 0, 0, 258, 72, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu) 
CreateGadgetList(WindowID(0)) 
  ResX = 1024 
  ResY = 768 
  Factor = 32 
  ScaledX = ResX/Factor 
  ScaledY = ResY/Factor 
  
  CreateImage(0, ScaledX, ScaledY, #PB_Image_DisplayFormat) 
  CreateImage(1, ScaledX, ScaledY, #PB_Image_DisplayFormat) 
  CreateImage(2, ResX, ResY, #PB_Image_DisplayFormat) 
  CreateImage(3, ResX, ResY, #PB_Image_DisplayFormat) 
  
  ; Custom 
  timer = GetTickCount_() 
  StartDrawing(ImageOutput(0)) 
    hDC = CreateDC_("DISPLAY", 0, 0, 0) 
    HalfFactor = Factor/2 
    DrawX = HalfFactor 
    DrawY = DrawX 
    For I = 0 To ScaledX-1 
      For J = 0 To ScaledY-1 
        Plot(I, J, GetPixel_(hDC, DrawX, DrawY)) 
        DrawY + Factor 
      Next 
      DrawY = HalfFactor 
      DrawX + Factor 
    Next 
    DeleteDC_(hDC) 
  StopDrawing() 
  CustomTime = GetTickCount_()-timer 
  
  ; API 
  timer = GetTickCount_() 
  ImghDC = StartDrawing(ImageOutput(1)) 
    hDC = CreateDC_("DISPLAY", 0, 0, 0) 
    ;SetStretchBltMode_(hDC, #HALFTONE) 
    ;SetBrushOrgEx_(hDC, 0, 0, 0) 
    StretchBlt_(ImghDC, 0, 0, ScaledX, ScaledY, hDC, 0, 0, ResX, ResY, #SRCCOPY) 
    DeleteDC_(hDC) 
  StopDrawing() 
  ApiTime = GetTickCount_()-timer 
  
  ; PB raw 
  timer = GetTickCount_() 
  ImghDC = StartDrawing(ImageOutput(2)) 
    hDC = CreateDC_("DISPLAY", 0, 0, 0) 
    BitBlt_(ImghDC, 0, 0, ResX, ResY, hDC, 0, 0, #SRCCOPY) 
    DeleteDC_(hDC) 
  StopDrawing() 
  ResizeImage(2, ScaledX, ScaledY, #PB_Image_Raw) 
  RawTime = GetTickCount_()-timer 
  
  ; PB smooth 
  timer = GetTickCount_() 
  ImghDC = StartDrawing(ImageOutput(3)) 
    hDC = CreateDC_("DISPLAY", 0, 0, 0) 
    BitBlt_(ImghDC, 0, 0, ResX, ResY, hDC, 0, 0, #SRCCOPY) 
    DeleteDC_(hDC) 
  StopDrawing() 
  ResizeImage(3, ScaledX, ScaledY, #PB_Image_Smooth) 
  SmoothTime = GetTickCount_()-timer 
  
  Frame3DGadget(100, 10, 10, 10+32+10, 10+32+10, Str(CustomTime)) 
  ImageGadget(0, 20, 20+(32-24), 32, 24, ImageID(0)) 
  Frame3DGadget(101, GadgetX(100)+GadgetWidth(100)+10, 10, 10+32+10, 10+32+10, Str(ApiTime)) 
  ImageGadget(1, GadgetX(100)+GadgetWidth(100)+20, 20+(32-24), 32, 24, ImageID(1)) 
  Frame3DGadget(102, GadgetX(101)+GadgetWidth(101)+10, 10, 10+32+10, 10+32+10, Str(RawTime)) 
  ImageGadget(2, GadgetX(101)+GadgetWidth(101)+20, 20+(32-24), 32, 24, ImageID(2)) 
  Frame3DGadget(103, GadgetX(102)+GadgetWidth(102)+10, 10, 10+32+10, 10+32+10, Str(SmoothTime)) 
  ImageGadget(3, GadgetX(102)+GadgetWidth(102)+20, 20+(32-24), 32, 24, ImageID(3)) 
  
Repeat 
  Select WaitWindowEvent() 
    Case #PB_Event_CloseWindow 
      Break 
  EndSelect 
ForEver- netmaestro
 - PureBasic Bullfrog

 - Posts: 8452
 - Joined: Wed Jul 06, 2005 5:42 am
 - Location: Fort Nelson, BC, Canada
 
Here's a version that creates a file thumbnail based on a filename. You can easily write a program to examine a dir for images and send this procedure each image to have a thumbnail created in the same folder. As it isn't creating a HBITMAP and drawing on it, it's even faster:
			
			
													Code: Select all
; netmaestro's gdiplus Thumbnail File creator 
; 
;---------------------------------------------------------------------------- 
;                     GDIPlus Initialization Section 
;---------------------------------------------------------------------------- 
; 
CompilerIf Defined(GdiplusStartupInput, #PB_Structure) = 0 
  Structure GdiplusStartupInput 
    GdiPlusVersion.l 
    *DebugCallback 
    SuppressBackgroundThread.l 
    SuppressExternalCodecs.l 
  EndStructure 
CompilerEndIf 
CompilerIf Defined(EncoderParameter, #PB_Structure) = 0 
  Structure EncoderParameter 
    count.l 
    guid.GUID 
    numberOfValues.l 
    type.l 
    *value 
  EndStructure 
CompilerEndIf 
CompilerIf  Defined(ImageCodecInfo, #PB_Structure) = 0 
  Structure ImageCodecInfo 
    clsid.CLSID 
    formatID.GUID 
    codecName.i 
    dllName.i 
    formatDescription.i 
    filenameExtension.i 
    mimeType.i 
    flags.l 
    version.l 
    sigCount.l 
    sigSize.l 
    *sigPattern.byte 
    *sigMask.byte
  EndStructure 
CompilerEndIf 
Prototype GdiplusStartup( *token, *input, mode ) 
Prototype GdipCreateBitmapFromFile( Filename.p-unicode, *image ) 
Prototype GdipSaveImageToFile ( *image, Filename.p-unicode, *encoder.CLSID, params) 
Prototype GdipGetImageEncodersSize( *num, *Size ) 
Prototype GdipGetImageEncoders( *num, *Size, *info.ImageCodecInfo) 
Prototype GdipGetImageThumbnail(*image, tn_xsize, tn_ysize, *tn_image, *callbackproc, *callbackdata) 
Prototype GdipDisposeImage( *image ) 
Prototype GdiplusShutdown( *token ) 
OpenLibrary(0, "gdiplus.dll") 
Global Startup.GdiplusStartup                        = GetFunction( 0, "GdiplusStartup" )          
Global CreateBitmapFromFile.GdipCreateBitmapFromFile = GetFunction( 0, "GdipCreateBitmapFromFile" ) 
Global SaveImageToFile.GdipSaveImageToFile           = GetFunction( 0, "GdipSaveImageToFile" ) 
Global GetImageEncodersSize.GdipGetImageEncodersSize = GetFunction( 0, "GdipGetImageEncodersSize" ) 
Global GetImageEncoders.GdipGetImageEncoders         = GetFunction( 0, "GdipGetImageEncoders" ) 
Global GetImageThumbnail.GdipGetImageThumbnail       = GetFunction( 0, "GdipGetImageThumbnail" ) 
Global DisposeImage.GdipDisposeImage                 = GetFunction( 0, "GdipDisposeImage" )        
Global Shutdown.GdiplusShutdown                      = GetFunction( 0, "GdiplusShutdown" ) 
;      
;----------------------------------------------------------------------------- 
;                      End GDIPlus Initialization Section 
;----------------------------------------------------------------------------- 
ProcedureDLL SaveThumbnail(*image, decoder, filename.s) 
  
  Protected encoder2use.s 
  Select decoder 
    Case 0 
      encoder2use = "image/bmp" 
    Case 1 
      encoder2use = "image/jpeg" 
    Case 2 
      encoder2use = "image/gif" 
    Case 3 
      encoder2use = "image/tiff" 
    Case 4 
      encoder2use = "image/png" 
    Default 
      ProcedureReturn 0 
  EndSelect 
  
  GetImageEncodersSize( @num, @Size ) 
  *mem = AllocateMemory(size)
  *ptr.ImageCodecInfo = *mem
  
  GetImageEncoders( num, Size, *ptr ) 
  For i = 0 To num - 1 
    If PeekS(*ptr\MimeType, -1, #PB_Unicode) = encoder2use 
      *clsid.CLSID = *ptr\clsid 
      Break 
    Else
      *ptr + SizeOf(ImageCodecInfo)
    EndIf 
  Next 
  If *clsid 
    result = SaveImageToFile( *image, filename, *clsid, 0) 
    FreeMemory(*mem)
    If result = #S_OK 
      ProcedureReturn 1 
    Else 
      ProcedureReturn 0 
    EndIf 
  Else 
    ProcedureReturn 0 
  EndIf 
  
EndProcedure 
ProcedureDLL CreateFileThumbnail( xsize, ysize, Filename.s ) 
  Select LCase(GetExtensionPart(filename)) 
    Case "bmp" : encoder.l = 0 
    Case "jpg" : encoder.l = 1 
    Case "gif" : encoder.l = 2 
    Case "tif" : encoder.l = 3 
    Case "png" : encoder.l = 4 
    Default : encoder.l = 0 
  EndSelect 
  input.GdiplusStartupInput 
  input\GdiPlusVersion = 1 
  Startup( @*token, @input, #Null) 
  CreateBitmapFromFile( Filename, @*image)
  GetImageThumbnail(*image, xsize,ysize, @*tn_image, #Null, #Null) 
  file2save$ = GetPathPart(filename)+"tn_"+GetFilePart(filename)
  SaveThumbnail( *tn_image, encoder, file2save$)    
  DisposeImage( *image ) 
  DisposeImage( *tn_image ) 
  Shutdown( *token ) 
EndProcedure 
filename$ =  OpenFileRequester("","","",0)
CreateFileThumbnail( 100, 75, filename$) ; input image can be any size; parameters are for thumbnail-out size 
CloseLibrary(0) 
					Last edited by netmaestro on Wed May 13, 2009 11:08 pm, edited 3 times in total.
									
			
									
						

