Faster resize image

Just starting out? Need help? Post your questions and find answers here.
Blade
Enthusiast
Enthusiast
Posts: 362
Joined: Wed Aug 06, 2003 2:49 pm
Location: Venice - Italy, Japan when possible.
Contact:

Faster resize image

Post by Blade »

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...
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Faster resize image

Post by PB »

> 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?

Code: Select all

LoadImage(#Img_ScreenShot,shotname$)
CopyImage(#Img_ScreenShot,#Img_ScreenShotThumb)
SetGadgetState(#shotview,ResizeImage(#Img_ScreenShotThumb,386,202))
Here's what my thumbnails look like without and with smoothing, and why
I don't want to use #PB_Image_Raw:

Image

Image
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Faster resize image

Post by PB »

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. :oops:

(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.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

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:

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
I just tested against this code:

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_CLOSE
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.
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

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
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

Pure genius.
Oh, the wanton abuse I have to put up with... :D

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)
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

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)
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. :oops: Wouldn't want to mess up all them other Windows users.

Guess I better have a look at Flype's lib:)

Thanks again
omit59
User
User
Posts: 63
Joined: Fri Mar 11, 2005 8:41 am
Location: Finland

Post by omit59 »

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
SoulReaper
Enthusiast
Enthusiast
Posts: 372
Joined: Sun Apr 03, 2005 2:14 am
Location: England

Post by SoulReaper »

Thanks netmaestro your a shining star and pure genius :lol: :wink:
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

Nice work Netmaestro :)

Try using GdipGetImageThumbnail and see if the results are satisfactory. I use it in one of my apps and a folder with 89 jpgs (mix of 640 x 480 and 1600 x 1200) displays 100 x 75 sized thumbs in 441 ms.
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

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]
Last edited by netmaestro on Sat Nov 11, 2006 7:49 pm, edited 1 time in total.
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

I'll see if I can cleanly rip out the GDI+ code from my app and post it here. :)
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

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
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

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.
dige
Addict
Addict
Posts: 1405
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

Post by dige »

@netmaestro: thx that very nice gdiplus code!
Where can I find information about gdiplus? I know that
it should be possible to do a lossless jpeg rotation...

And how to change the gdi resize code to use it without
file loading. ( create a gdi image from a pb image )
could you help?
Post Reply