How do I display Multipage tiff image

Just starting out? Need help? Post your questions and find answers here.
leodh
Enthusiast
Enthusiast
Posts: 164
Joined: Sun Nov 06, 2005 6:07 am
Location: Perth Western Australia

How do I display Multipage tiff image

Post by leodh »

Hi,

I am trying to find a way to display Multipage Tiff images in PB.

If I use the Tiff decoder it only displays the first page, is there a way to display them with PB or do I have to use a library to display them. I would be happy with the pages to be joined at the bottom of the previous page.

Does anyone have any ideas or clues.

Thanks
Regards
Leo
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: How do I display Multipage tiff image

Post by netmaestro »

Your best bet would probably be the FreeImage library. Gdiplus is capable as well but with more effort required from the coder. You could always write your own decoder like Wilbert and I both did for Gif over the last 2 months of 2013 but that would be overkill unless you really love tiffs.
BERESHEIT
coco2
Enthusiast
Enthusiast
Posts: 461
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

Re: How do I display Multipage tiff image

Post by coco2 »

I always liked multipage tiffs for document storage although I now scan and OCR documents into PDF so they are searchable so I stopped using TIFF. Would be handy to have a native PB reader.
leodh
Enthusiast
Enthusiast
Posts: 164
Joined: Sun Nov 06, 2005 6:07 am
Location: Perth Western Australia

Re: How do I display Multipage tiff image

Post by leodh »

Hi,

I got this far but can't display the other pages.

Code: Select all

; Modified from ************************************
;==================================================
;  Program:     GDIPlus Rotation Demo
;  Author:      netmaestro
;  Date:        November 12, 2006
;==================================================
;****************************************************

CompilerIf Defined(GdiplusStartupInput, #PB_Structure) = 0
  Structure GdiplusStartupInput
    GdiPlusVersion.l
    *DebugCallback
    SuppressBackgroundThread.l
    SuppressExternalCodecs.l
  EndStructure
CompilerEndIf 

Prototype GdiplusStartup( *token, *input, mode )
Prototype GdipCreateBitmapFromFile( Filename, *image )
Prototype GdipGetImageWidth( *image, *Width )
Prototype GdipGetImageHeight( *image, *Height )
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 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

input.GdiplusStartupInput
input\GdiPlusVersion = 1
Startup( @*token, @input, #Null)

FileName.s = "C:\AS-13-0731-RS-1.tif"
Imagenumber = 0
CreateBitmapFromFile( StringToBStr(Filename), @*image)
GetImageWidth( *image, @Width.l )
GetImageHeight( *image, @Height.l )
Retval = CreateImage(ImageNumber, width, Height, 24)
hdc = StartDrawing(ImageOutput(ImageNumber))
    DrawingMode(#PB_2DDrawing_AlphaChannel)
    Box(0, 0, width, height, 0)
  CreateFromHDC( hdc, @*gfx )
  DrawImageRectI( *gfx, *image, 0, 0, Width, Height)
StopDrawing() 
DeleteGraphics( *gfx ) 
DisposeImage( *image )
Shutdown( *token )
  
CreateImage(1, width, height, 24)
StartDrawing(ImageOutput(1))
  Box(0, 0, width, Height, GetSysColor_(#COLOR_3DFACE))
  DrawAlphaImage(ImageID(0), 0, 0)
StopDrawing()

CloseLibrary(0)

OpenWindow(0,0,0,600,800,"")
ScrollAreaGadget(99,0,0,600,800,1700,2200)
ImageGadget(0,0,0,Width,Height,ImageID(1))
CloseGadgetList()
Repeat
  
Until WaitWindowEvent() = #WM_CLOSE
ShutDownGDIPlus(*token)
Does anyone have an example of multipage display.

Regards
Regards
Leo
infratec
Always Here
Always Here
Posts: 7620
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: How do I display Multipage tiff image

Post by infratec »

Hi,

look at
http://www.purebasic.fr/english/viewtop ... hilit=tiff

at the bottom of the first page.

Bernd
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: How do I display Multipage tiff image

Post by wilbert »

I think it should be possible with the decoder that comes with PureBasic.
If you load the tiff file into memory, you should be able to change the offset of the image data to the next page, catch the image and move on to the next one.
Last edited by wilbert on Fri Mar 28, 2014 11:38 am, edited 1 time in total.
Windows (x64)
Raspberry Pi OS (Arm64)
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: How do I display Multipage tiff image

Post by wilbert »

I found some test files and can confirm it's easy to create a simple cross platform solution. :D

Code: Select all

UseTIFFImageDecoder()

Procedure.w SwapBytesW(v.w)
  !movzx eax, word [p.v_v]
  !xchg al, ah
  ProcedureReturn
EndProcedure

Procedure.l SwapBytesL(v.l)
  !mov eax, [p.v_v]
  !bswap eax
  ProcedureReturn
EndProcedure

Procedure.i CatchTIFFPage(Image, *MemoryAddress.Word, Page = 0)
  Protected.i Result, Count, *Entries.Word
  Protected *IFD0.Long = *MemoryAddress + 4
  Protected *IFD.Long = *IFD0
  While *IFD\l
    If Count = Page
      Swap *IFD0\l, *IFD\l
      Result = CatchImage(Image, *MemoryAddress)
      Swap *IFD0\l, *IFD\l
      Break
    EndIf
    Count + 1  
    If *MemoryAddress\w = $4D4D
      ; big endian
      *Entries = *MemoryAddress + SwapBytesL(*IFD\l)
      *IFD = *Entries + 2 + SwapBytesW(*Entries\w) * 12
    Else
      ; little endian
      *Entries = *MemoryAddress + *IFD\l
      *IFD = *Entries + 2 + *Entries\w * 12
    EndIf
  Wend
  If Page >= 0
    ProcedureReturn Result
  Else
    ProcedureReturn Count
  EndIf
EndProcedure

Code: Select all

CatchTIFFPage(0, *TIFFData, 1); Catches the second page (page number starts at 0)
If you specify a negative page number, the procedure returns the amount of pages.
Windows (x64)
Raspberry Pi OS (Arm64)
leodh
Enthusiast
Enthusiast
Posts: 164
Joined: Sun Nov 06, 2005 6:07 am
Location: Perth Western Australia

Re: How do I display Multipage tiff image

Post by leodh »

Hi Wilbert,

I have had a look at your code and I think I understand what you are saying, but I can not get it to work, I've not done much with images.

When you say load the Tiff file into memory, how do I load it into memory as Image 0 ?

In the statement CatchTiffPage is *TIFFData the pointer to image was loaded ? I think I tried just about everything I could think of.

I am most probably doing something really silly, but I have no idea.

Code: Select all


OpenWindow(0,0,0,800,700,"",#PB_Window_ScreenCentered)

CreateImage(0,800,600,24)
LoadImage(0,FileName.s)

ImageGadget(0,0,0,800,600,ImageID(0))
Delay(1000)

For t = 1 To 9
  CatchTIFFPage(0, *TIFFData, t); Catches the t page (10 pages in Image)
  SetGadgetState(0,ImageID(0))
Next t

Repeat
  
Until WaitWindowEvent() = #WM_CLOSE
Could you push me in the right direction.

Thanks
Regards
Leo
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: How do I display Multipage tiff image

Post by wilbert »

leodh wrote:When you say load the Tiff file into memory, how do I load it into memory as Image 0 ?
Here's a more complete example.
Hopefully this helps.

Code: Select all

UseTIFFImageDecoder()

Procedure.w SwapBytesW(v.w)
  !movzx eax, word [p.v_v]
  !xchg al, ah
  ProcedureReturn
EndProcedure

Procedure.l SwapBytesL(v.l)
  !mov eax, [p.v_v]
  !bswap eax
  ProcedureReturn
EndProcedure

Procedure.i CatchTIFFPage(Image, *MemoryAddress.Word, Page = 0)
  Protected.i Result, Count, *Entries.Word
  Protected *IFD0.Long = *MemoryAddress + 4
  Protected *IFD.Long = *IFD0
  While *IFD\l
    If Count = Page
      Swap *IFD0\l, *IFD\l
      Result = CatchImage(Image, *MemoryAddress)
      Swap *IFD0\l, *IFD\l
      Break
    EndIf
    Count + 1  
    If *MemoryAddress\w = $4D4D
      ; big endian
      *Entries = *MemoryAddress + SwapBytesL(*IFD\l)
      *IFD = *Entries + 2 + SwapBytesW(*Entries\w) * 12
    Else
      ; little endian
      *Entries = *MemoryAddress + *IFD\l
      *IFD = *Entries + 2 + *Entries\w * 12
    EndIf
  Wend
  If Page >= 0
    ProcedureReturn Result
  Else
    ProcedureReturn Count
  EndIf
EndProcedure

Procedure.i LoadFile(FileName.s)
  Protected.i File, Length, *Memory
  File = ReadFile(#PB_Any, FileName)
  If File
    Length = Lof(File)
    *Memory = AllocateMemory(Length)
    If *Memory
      ReadData(File, *Memory, Length)
    EndIf
    CloseFile(File)
  EndIf
  ProcedureReturn *Memory
EndProcedure



; *** Test code ***

Define.i Event, Page, PageCount, *TIFFData

OpenWindow(0, 0, 0, 800, 700, "", #PB_Window_ScreenCentered)

*TIFFData = LoadFile("MyTiffFile.tiff")
If *TIFFData
  PageCount = CatchTIFFPage(0, *TIFFData, -1)
  
  For Page = 0 To PageCount - 1
    CatchTIFFPage(Page, *TIFFData, Page)
  Next
  
  FreeMemory(*TIFFData)
  
  ImageGadget(0, 0, 0, 800, 600, ImageID(0))
  
  Repeat
    Event = WaitWindowEvent()
    
    If Event = #PB_Event_Gadget And EventType() = #PB_EventType_LeftClick
      Page = (Page + 1) % PageCount
      SetGadgetState(0, ImageID(Page))
    EndIf
    
  Until Event = #PB_Event_CloseWindow
  
EndIf
The LoadFile procedure loads the tiff file into memory.
After that you can catch the images you want.
When the tiff data is no longer needed, FreeMemory needs to be used to free the memory it occupies.
Windows (x64)
Raspberry Pi OS (Arm64)
leodh
Enthusiast
Enthusiast
Posts: 164
Joined: Sun Nov 06, 2005 6:07 am
Location: Perth Western Australia

Re: How do I display Multipage tiff image

Post by leodh »

Hi Wilbert,

Thank you, I was close but I could not figure out the memory allocation stuff.

Once again the PB community helps a battler.

Thanks again.
Regards
Leo
Post Reply