Page 1 of 1
How do I display Multipage tiff image
Posted: Thu Mar 27, 2014 1:56 pm
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
Re: How do I display Multipage tiff image
Posted: Thu Mar 27, 2014 7:11 pm
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.
Re: How do I display Multipage tiff image
Posted: Thu Mar 27, 2014 11:19 pm
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.
Re: How do I display Multipage tiff image
Posted: Fri Mar 28, 2014 8:05 am
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
Re: How do I display Multipage tiff image
Posted: Fri Mar 28, 2014 8:17 am
by infratec
Re: How do I display Multipage tiff image
Posted: Fri Mar 28, 2014 9:35 am
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.
Re: How do I display Multipage tiff image
Posted: Fri Mar 28, 2014 11:22 am
by wilbert
I found some test files and can confirm it's easy to create a simple cross platform solution.
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.
Re: How do I display Multipage tiff image
Posted: Sun Mar 30, 2014 3:40 pm
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
Re: How do I display Multipage tiff image
Posted: Sun Mar 30, 2014 4:48 pm
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.
Re: How do I display Multipage tiff image
Posted: Mon Mar 31, 2014 12:17 am
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.