From e841b13166218ba152595a7c0adf5b70c4e5558d Mon Sep 17 00:00:00 2001 From: Francois-Olivier Devaux Date: Thu, 22 Feb 2007 17:05:58 +0000 Subject: [PATCH] Added the OPJViewer Module (/OPJViewer), developed by Giuseppe Baruffa of the University of Perugia --- ChangeLog | 3 + OPJViewer/OPJViewer.dsp | 206 ++++ OPJViewer/OPJViewer.dsw | 44 + OPJViewer/OPJViewer.iss | 34 + OPJViewer/source/OPJViewer.cpp | 1849 ++++++++++++++++++++++++++++++ OPJViewer/source/OPJViewer.h | 469 ++++++++ OPJViewer/source/OPJViewer.ico | Bin 0 -> 1078 bytes OPJViewer/source/OPJViewer.rc | 2 + OPJViewer/source/OPJViewer16.xpm | 26 + OPJViewer/source/icon1.xpm | 79 ++ OPJViewer/source/icon2.xpm | 53 + OPJViewer/source/icon3.xpm | 79 ++ OPJViewer/source/icon4.xpm | 43 + OPJViewer/source/icon5.xpm | 79 ++ OPJViewer/source/imagj2k.cpp | 312 +++++ OPJViewer/source/imagj2k.h | 75 ++ OPJViewer/source/imagjp2.cpp | 286 +++++ OPJViewer/source/imagjp2.h | 75 ++ OPJViewer/source/imagmj2.cpp | 785 +++++++++++++ OPJViewer/source/imagmj2.h | 75 ++ OPJViewer/source/wxj2kparser.cpp | 337 ++++++ OPJViewer/source/wxjp2parser.cpp | 851 ++++++++++++++ 22 files changed, 5762 insertions(+) create mode 100644 OPJViewer/OPJViewer.dsp create mode 100644 OPJViewer/OPJViewer.dsw create mode 100644 OPJViewer/OPJViewer.iss create mode 100644 OPJViewer/source/OPJViewer.cpp create mode 100644 OPJViewer/source/OPJViewer.h create mode 100644 OPJViewer/source/OPJViewer.ico create mode 100644 OPJViewer/source/OPJViewer.rc create mode 100644 OPJViewer/source/OPJViewer16.xpm create mode 100644 OPJViewer/source/icon1.xpm create mode 100644 OPJViewer/source/icon2.xpm create mode 100644 OPJViewer/source/icon3.xpm create mode 100644 OPJViewer/source/icon4.xpm create mode 100644 OPJViewer/source/icon5.xpm create mode 100644 OPJViewer/source/imagj2k.cpp create mode 100644 OPJViewer/source/imagj2k.h create mode 100644 OPJViewer/source/imagjp2.cpp create mode 100644 OPJViewer/source/imagjp2.h create mode 100644 OPJViewer/source/imagmj2.cpp create mode 100644 OPJViewer/source/imagmj2.h create mode 100644 OPJViewer/source/wxj2kparser.cpp create mode 100644 OPJViewer/source/wxjp2parser.cpp diff --git a/ChangeLog b/ChangeLog index 0a693ac4..fa24ad1f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,9 @@ What's New for OpenJPEG ! : changed + : added +February 22, 2007 ++ [FOD] Added the OPJViewer Module (/OPJViewer), developed by Giuseppe Baruffa of the university of Perugia + February 21, 2007 + [FOD] Algorithmic optimizations in t1.c, thanks to Guido J. ! diff --git a/OPJViewer/OPJViewer.dsp b/OPJViewer/OPJViewer.dsp new file mode 100644 index 00000000..1ab84c3e --- /dev/null +++ b/OPJViewer/OPJViewer.dsp @@ -0,0 +1,206 @@ +# Microsoft Developer Studio Project File - Name="OPJViewer" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=OPJVIEWER - WIN32 RELEASE +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "OPJViewer.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "OPJViewer.mak" CFG="OPJVIEWER - WIN32 RELEASE" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "OPJViewer - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "OPJViewer - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "OPJViewer - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "W32Release" +# PROP Intermediate_Dir "W32Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /G6 /MD /GX /O2 /I "c:\programmi\wxWidgets-2.8.0\lib\vc_lib\msw" /I "c:\programmi\wxWidgets-2.8.0\include" /I ".." /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D WINVER=0x400 /D "_MT" /D wxUSE_GUI=1 /D "wxUSE_LIBOPENJPEG" /D "OPJ_STATIC" /D "USE_JPWL" /FR /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x410 /d "NDEBUG" +# ADD RSC /l 0x409 /i "c:\programmi\wxWidgets-2.8.0\include" /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib wxzlib.lib wxregex.lib wxpng.lib wxjpeg.lib wxbase28.lib wxmsw28_core.lib wxmsw28_html.lib wxmsw28_adv.lib wxmsw28_core.lib wxbase28.lib wxtiff.lib wxjpeg.lib wxpng.lib wxzlib.lib wxregex.lib wxexpat.lib LibOpenJPEG_JPWL.lib /nologo /subsystem:windows /machine:I386 /nodefaultlib:"libcmt.lib" /libpath:"c:\programmi\wxWidgets-2.8.0\lib\vc_lib" /libpath:"..\jpwl\Release" /IGNORE:4089 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "OPJViewer - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "OPJViewer___Win32_Debug" +# PROP BASE Intermediate_Dir "OPJViewer___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "W32Debug" +# PROP Intermediate_Dir "W32Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /Zi /Od /I "C:\Programmi\wxWidgets-2.8.0\INCLUDE" /I "c:\programmi\wxWidgets-2.8.0\lib\vc_lib\msw" /I "c:\programmi\wxWidgets-2.8.0\include" /I ".." /D "_DEBUG" /D "__WXDEBUG__" /D WXDEBUG=1 /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D WINVER=0x400 /D "_MT" /D wxUSE_GUI=1 /D "wxUSE_LIBOPENJPEG" /D "OPJ_STATIC" /D "USE_JPWL" /FR /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x410 /d "_DEBUG" +# ADD RSC /l 0x410 /i "c:\programmi\wxWidgets-2.8.0\include" /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib wxzlibd.lib wxregexd.lib wxpngd.lib wxjpegd.lib wxtiffd.lib wxbase28d.lib wxmsw28d_core.lib wxmsw28d_html.lib wxmsw28d_adv.lib LibOpenJPEG_JPWL.lib /nologo /subsystem:windows /debug /machine:I386 /nodefaultlib:"libcmtd.lib" /pdbtype:sept /libpath:"c:\programmi\wxWidgets-2.8.0\lib\vc_lib" /libpath:"..\jpwl\Debug" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "OPJViewer - Win32 Release" +# Name "OPJViewer - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\source\imagj2k.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\imagjp2.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\imagmj2.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\OPJViewer.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\wxj2kparser.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\wxjp2parser.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\source\imagj2k.h +# End Source File +# Begin Source File + +SOURCE=.\source\imagjp2.h +# End Source File +# Begin Source File + +SOURCE=.\source\imagmj2.h +# End Source File +# Begin Source File + +SOURCE=.\source\OPJViewer.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\source\icon1.xpm +# End Source File +# Begin Source File + +SOURCE=.\source\icon2.xpm +# End Source File +# Begin Source File + +SOURCE=.\source\icon3.xpm +# End Source File +# Begin Source File + +SOURCE=.\source\icon4.xpm +# End Source File +# Begin Source File + +SOURCE=.\source\icon5.xpm +# End Source File +# Begin Source File + +SOURCE=.\source\OPJViewer.ico +# End Source File +# Begin Source File + +SOURCE=.\source\OPJViewer.rc +# End Source File +# Begin Source File + +SOURCE=.\source\OPJViewer16.xpm +# End Source File +# End Group +# Begin Group "JPWL" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\jpwl\crc.c +# End Source File +# Begin Source File + +SOURCE=..\jpwl\crc.h +# End Source File +# Begin Source File + +SOURCE=..\jpwl\jpwl.c +# End Source File +# Begin Source File + +SOURCE=..\jpwl\jpwl.h +# End Source File +# Begin Source File + +SOURCE=..\jpwl\jpwl_lib.c +# End Source File +# Begin Source File + +SOURCE=..\jpwl\rs.c +# End Source File +# Begin Source File + +SOURCE=..\jpwl\rs.h +# End Source File +# End Group +# End Target +# End Project diff --git a/OPJViewer/OPJViewer.dsw b/OPJViewer/OPJViewer.dsw new file mode 100644 index 00000000..a4d64f93 --- /dev/null +++ b/OPJViewer/OPJViewer.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "LibOpenJPEG_JPWL"=..\jpwl\LibOpenJPEG_JPWL.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "OPJViewer"=.\OPJViewer.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name LibOpenJPEG_JPWL + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/OPJViewer/OPJViewer.iss b/OPJViewer/OPJViewer.iss new file mode 100644 index 00000000..6b324c7a --- /dev/null +++ b/OPJViewer/OPJViewer.iss @@ -0,0 +1,34 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +[Setup] +AppName=OPJViewer +AppVerName=OPJViewer 0.1 alpha +AppPublisher=OpenJPEG +AppPublisherURL=http://www.openjpeg.org +AppSupportURL=http://www.openjpeg.org +AppUpdatesURL=http://www.openjpeg.org +DefaultDirName={pf}\OPJViewer +DefaultGroupName=OPJViewer +OutputDir=setup +OutputBaseFilename=OPJViewer01alpha_setup +Compression=lzma +SolidCompression=yes + +[Languages] +Name: english; MessagesFile: compiler:Default.isl + +[Tasks] +Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked + +[Files] +Source: W32Release\OPJViewer.exe; DestDir: {app}; Flags: ignoreversion +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: {group}\OPJViewer; Filename: {app}\OPJViewer.exe +Name: {group}\{cm:UninstallProgram,OPJViewer}; Filename: {uninstallexe} +Name: {userdesktop}\OPJViewer; Filename: {app}\OPJViewer.exe; Tasks: desktopicon + +[Run] +Filename: {app}\OPJViewer.exe; Description: {cm:LaunchProgram,OPJViewer}; Flags: nowait postinstall skipifsilent diff --git a/OPJViewer/source/OPJViewer.cpp b/OPJViewer/source/OPJViewer.cpp new file mode 100644 index 00000000..3bbf4797 --- /dev/null +++ b/OPJViewer/source/OPJViewer.cpp @@ -0,0 +1,1849 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: sashtest.cpp +// Purpose: Layout/sash sample +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: sashtest.cpp,v 1.18 2005/08/23 15:54:35 ABX Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: treetest.cpp +// Purpose: wxTreeCtrl sample +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: treetest.cpp,v 1.110 2006/11/04 11:26:51 VZ Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: dialogs.cpp +// Purpose: Common dialogs demo +// Author: Julian Smart +// Modified by: ABX (2004) - adjustements for conditional building + new menu +// Created: 04/01/98 +// RCS-ID: $Id: dialogs.cpp,v 1.163 2006/11/04 10:57:24 VZ Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: thread.cpp +// Purpose: wxWidgets thread sample +// Author: Guilhem Lavaux, Vadim Zeitlin +// Modified by: +// Created: 06/16/98 +// RCS-ID: $Id: thread.cpp,v 1.26 2006/10/02 05:36:28 PC Exp $ +// Copyright: (c) 1998-2002 wxWidgets team +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Name: samples/image/image.cpp +// Purpose: sample showing operations with wxImage +// Author: Robert Roebling +// Modified by: +// Created: 1998 +// RCS-ID: $Id: image.cpp,v 1.120 2006/12/06 17:13:11 VZ Exp $ +// Copyright: (c) 1998-2005 Robert Roebling +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: samples/console/console.cpp +// Purpose: A sample console (as opposed to GUI) program using wxWidgets +// Author: Vadim Zeitlin +// Modified by: +// Created: 04.10.99 +// RCS-ID: $Id: console.cpp,v 1.206 2006/11/12 19:55:19 VZ Exp $ +// Copyright: (c) 1999 Vadim Zeitlin +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: samples/notebook/notebook.cpp +// Purpose: a sample demonstrating notebook usage +// Author: Julian Smart +// Modified by: Dimitri Schoolwerth +// Created: 26/10/98 +// RCS-ID: $Id: notebook.cpp,v 1.49 2006/11/04 18:24:07 RR Exp $ +// Copyright: (c) 1998-2002 wxWidgets team +// License: wxWindows license +///////////////////////////////////////////////////////////////////////////// +#include "OPJViewer.h" + +OPJFrame *frame = NULL; +wxList my_children; + +IMPLEMENT_APP(OPJViewerApp) + +// For drawing lines in a canvas +long xpos = -1; +long ypos = -1; + +int winNumber = 1; + +// Initialise this in OnInit, not statically +bool OPJViewerApp::OnInit(void) +{ +#if wxUSE_UNICODE + wxChar **wxArgv = new wxChar *[argc + 1]; + + { + int n; + + for (n = 0; n < argc; n++ ) + { + wxMB2WXbuf warg = wxConvertMB2WX(argv[n]); + wxArgv[n] = wxStrdup(warg); + } + + wxArgv[n] = NULL; + } +#else // !wxUSE_UNICODE + #define wxArgv argv +#endif // wxUSE_UNICODE/!wxUSE_UNICODE + +#if wxUSE_CMDLINE_PARSER + static const wxCmdLineEntryDesc cmdLineDesc[] = + { + { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("show this help message"), + wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP }, + /*{ wxCMD_LINE_SWITCH, _T("v"), _T("verbose"), _T("be verbose") }, + { wxCMD_LINE_SWITCH, _T("q"), _T("quiet"), _T("be quiet") }, + + { wxCMD_LINE_OPTION, _T("o"), _T("output"), _T("output file") }, + { wxCMD_LINE_OPTION, _T("i"), _T("input"), _T("input dir") }, + { wxCMD_LINE_OPTION, _T("s"), _T("size"), _T("output block size"), + wxCMD_LINE_VAL_NUMBER }, + { wxCMD_LINE_OPTION, _T("d"), _T("date"), _T("output file date"), + wxCMD_LINE_VAL_DATE },*/ + + { wxCMD_LINE_PARAM, NULL, NULL, _T("input file"), + wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE }, + + { wxCMD_LINE_NONE } + }; + + wxCmdLineParser parser(cmdLineDesc, argc, wxArgv); + + /*parser.AddOption(_T("project_name"), _T(""), _T("full path to project file"), + wxCMD_LINE_VAL_STRING, + wxCMD_LINE_OPTION_MANDATORY | wxCMD_LINE_NEEDS_SEPARATOR);*/ + + switch ( parser.Parse() ) + { + case -1: + wxLogMessage(_T("Help was given, terminating.")); + break; + + case 0: + ShowCmdLine(parser); + break; + + default: + wxLogMessage(_T("Syntax error detected.")); + break; + } +#endif // wxUSE_CMDLINE_PARSER + + //wxInitAllImageHandlers(); +#if wxUSE_LIBJPEG + wxImage::AddHandler( new wxJPEGHandler ); +#endif +#if wxUSE_LIBOPENJPEG + wxImage::AddHandler( new wxJ2KHandler ); + wxImage::AddHandler( new wxJP2Handler ); + wxImage::AddHandler( new wxMJ2Handler ); +#endif + + + // Create the main frame window + + frame = new OPJFrame(NULL, wxID_ANY, OPJ_APPLICATION_TITLEBAR, wxDefaultPosition, wxSize(800, 600), + wxDEFAULT_FRAME_STYLE | + wxNO_FULL_REPAINT_ON_RESIZE | + wxHSCROLL | wxVSCROLL); + + // Give it an icon (this is ignored in MDI mode: uses resources) +#ifdef __WXMSW__ + frame->SetIcon(wxIcon(_T("OPJViewer16"))); +#endif + + frame->Show(true); + + SetTopWindow(frame); + + return true; +} + +void OPJViewerApp::ShowCmdLine(const wxCmdLineParser& parser) +{ + wxString s = _T("Command line parsed successfully:\nInput files: "); + + size_t count = parser.GetParamCount(); + for ( size_t param = 0; param < count; param++ ) + { + s << parser.GetParam(param) << ';'; + + m_filelist.Add(parser.GetParam(param)); + } + + /*s << '\n' + << _T("Verbose:\t") << (parser.Found(_T("v")) ? _T("yes") : _T("no")) << '\n' + << _T("Quiet:\t") << (parser.Found(_T("q")) ? _T("yes") : _T("no")) << '\n'; + + wxString strVal; + long lVal; + wxDateTime dt; + if ( parser.Found(_T("o"), &strVal) ) + s << _T("Output file:\t") << strVal << '\n'; + if ( parser.Found(_T("i"), &strVal) ) + s << _T("Input dir:\t") << strVal << '\n'; + if ( parser.Found(_T("s"), &lVal) ) + s << _T("Size:\t") << lVal << '\n'; + if ( parser.Found(_T("d"), &dt) ) + s << _T("Date:\t") << dt.FormatISODate() << '\n'; + if ( parser.Found(_T("project_name"), &strVal) ) + s << _T("Project:\t") << strVal << '\n';*/ + + //wxLogMessage(s); +} + +// OPJFrame events +BEGIN_EVENT_TABLE(OPJFrame, wxMDIParentFrame) + EVT_MENU(SASHTEST_ABOUT, OPJFrame::OnAbout) + EVT_MENU(SASHTEST_NEW_WINDOW, OPJFrame::OnFileOpen) + EVT_SIZE(OPJFrame::OnSize) + EVT_MENU(SASHTEST_QUIT, OPJFrame::OnQuit) + EVT_MENU(SASHTEST_TOGGLE_WINDOW, OPJFrame::OnToggleWindow) + EVT_SASH_DRAGGED_RANGE(ID_WINDOW_TOP, ID_WINDOW_BOTTOM, OPJFrame::OnSashDrag) + EVT_NOTEBOOK_PAGE_CHANGED(LEFT_NOTEBOOK_ID, OPJFrame::OnNotebook) +END_EVENT_TABLE() + +// this is the frame constructor +OPJFrame::OPJFrame(wxWindow *parent, const wxWindowID id, const wxString& title, + const wxPoint& pos, const wxSize& size, const long style) + : wxMDIParentFrame(parent, id, title, pos, size, style) +{ + // file menu and its items + wxMenu *file_menu = new wxMenu; + + file_menu->Append(SASHTEST_NEW_WINDOW, wxT("&Open\tCtrl+O")); + file_menu->SetHelpString(SASHTEST_NEW_WINDOW, wxT("Open one or more files")); + + file_menu->Append(SASHTEST_TOGGLE_WINDOW, wxT("&Toggle browser\tCtrl+T")); + file_menu->SetHelpString(SASHTEST_TOGGLE_WINDOW, wxT("Toggle the left browsing pane")); + + file_menu->Append(SASHTEST_QUIT, wxT("&Exit\tCtrl+Q")); + file_menu->SetHelpString(SASHTEST_QUIT, wxT("Quit this program")); + + // help menu and its items + wxMenu *help_menu = new wxMenu; + + help_menu->Append(SASHTEST_ABOUT, wxT("&About\tF1")); + help_menu->SetHelpString(SASHTEST_ABOUT, wxT("Basic info on the program")); + + // the whole menubar + wxMenuBar *menu_bar = new wxMenuBar; + menu_bar->Append(file_menu, wxT("&File")); + menu_bar->Append(help_menu, wxT("&Help")); + + // Associate the menu bar with the frame + SetMenuBar(menu_bar); + + // the status bar + CreateStatusBar(); + + // the logging window + loggingWindow = new wxSashLayoutWindow(this, ID_WINDOW_BOTTOM, + wxDefaultPosition, wxSize(400, 130), + wxNO_BORDER | wxSW_3D | wxCLIP_CHILDREN + ); + loggingWindow->SetDefaultSize(wxSize(1000, 130)); + loggingWindow->SetOrientation(wxLAYOUT_HORIZONTAL); + loggingWindow->SetAlignment(wxLAYOUT_BOTTOM); + //loggingWindow->SetBackgroundColour(wxColour(0, 0, 255)); + loggingWindow->SetSashVisible(wxSASH_TOP, true); + + // create the bottom notebook + m_bookCtrlbottom = new wxNotebook(loggingWindow, BOTTOM_NOTEBOOK_ID, + wxDefaultPosition, wxDefaultSize, + wxBK_LEFT); + + // create the text control of the logger + m_textCtrl = new wxTextCtrl(m_bookCtrlbottom, wxID_ANY, wxT(""), + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE | wxSUNKEN_BORDER | wxTE_READONLY + ); + m_textCtrl->SetValue(_T("Logging window\n")); + + // add it to the notebook + m_bookCtrlbottom->AddPage(m_textCtrl, wxT("Log")); + + // create the text control of the browser + m_textCtrlbrowse = new wxTextCtrl(m_bookCtrlbottom, wxID_ANY, wxT(""), + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE | wxSUNKEN_BORDER | wxTE_READONLY + ); + m_textCtrlbrowse->SetValue(_T("Browsing window\n")); + + // add it the notebook + m_bookCtrlbottom->AddPage(m_textCtrlbrowse, wxT("Peek")); + + // the browser window + markerTreeWindow = new wxSashLayoutWindow(this, ID_WINDOW_LEFT1, + wxDefaultPosition, wxSize(300, 30), + wxNO_BORDER | wxSW_3D | wxCLIP_CHILDREN + ); + markerTreeWindow->SetDefaultSize(wxSize(300, 1000)); + markerTreeWindow->SetOrientation(wxLAYOUT_VERTICAL); + markerTreeWindow->SetAlignment(wxLAYOUT_LEFT); + //markerTreeWindow->SetBackgroundColour(wxColour(0, 255, 0)); + markerTreeWindow->SetSashVisible(wxSASH_RIGHT, true); + markerTreeWindow->SetExtraBorderSize(0); + + // create the browser notebook + m_bookCtrl = new wxNotebook(markerTreeWindow, LEFT_NOTEBOOK_ID, + wxDefaultPosition, wxDefaultSize, + wxBK_TOP); + + +#if wxUSE_LOG +#ifdef __WXMOTIF__ + // For some reason, we get a memcpy crash in wxLogStream::DoLogStream + // on gcc/wxMotif, if we use wxLogTextCtl. Maybe it's just gcc? + delete wxLog::SetActiveTarget(new wxLogStderr); +#else + // set our text control as the log target + wxLogTextCtrl *logWindow = new wxLogTextCtrl(m_textCtrl); + delete wxLog::SetActiveTarget(logWindow); +#endif +#endif // wxUSE_LOG + + // if there are files on the command line, open them + /*if (!wxGetApp().m_filelist.IsEmpty()) { + wxLogMessage(wxT("Habemus files!!!")); + wxArrayString paths, filenames; + for (int f = 0; f < wxGetApp().m_filelist.GetCount(); f++) { + paths.Add(wxFileName(wxGetApp().m_filelist[f]).GetFullPath()); + filenames.Add(wxFileName(wxGetApp().m_filelist[f]).GetFullName()); + } + OpenFiles(paths, filenames); + }*/ +} + +// this is the frame destructor +OPJFrame::~OPJFrame(void) +{ + // delete all possible things + delete m_bookCtrl; + m_bookCtrl = NULL; + + delete markerTreeWindow; + markerTreeWindow = NULL; + + delete m_textCtrl; + m_textCtrl = NULL; + + delete m_bookCtrlbottom; + m_bookCtrlbottom = NULL; + + delete loggingWindow; + loggingWindow = NULL; +} + +void OPJFrame::OnNotebook(wxNotebookEvent& event) +{ + int sel = event.GetSelection(); + long childnum; + + m_bookCtrl->GetPageText(sel).ToLong(&childnum); + + m_childhash[childnum]->Activate(); + + wxLogMessage(wxString::Format(wxT("Selection changed (now %d --> %d)"), childnum, m_childhash[childnum]->m_winnumber)); + +} + + +void OPJFrame::Resize(int number) +{ + wxSize size = GetClientSize(); +} + +void OPJFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) +{ + Close(true); +} + +// about window for the frame +void OPJFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ + wxMessageBox(wxString::Format(OPJ_APPLICATION_TITLEBAR + wxT("\n\n") + wxT("Built with %s and OpenJPEG ") + wxT(OPENJPEG_VERSION) + wxT("\non ") wxT(__DATE__) wxT(", ") wxT(__TIME__) + wxT("\nRunning under %s\n\n") + OPJ_APPLICATION_COPYRIGHT, + wxVERSION_STRING, + wxGetOsDescription().c_str() + ), + wxT("About ") OPJ_APPLICATION_NAME, + wxOK | wxICON_INFORMATION, + this + ); +} + +void OPJFrame::OnToggleWindow(wxCommandEvent& WXUNUSED(event)) +{ + if (markerTreeWindow->IsShown()) + { + markerTreeWindow->Show(false); + } + else + { + markerTreeWindow->Show(true); + } +#if wxUSE_MDI_ARCHITECTURE + wxLayoutAlgorithm layout; + layout.LayoutMDIFrame(this); +#endif // wxUSE_MDI_ARCHITECTURE +} + +void OPJFrame::OnSashDrag(wxSashEvent& event) +{ + if (event.GetDragStatus() == wxSASH_STATUS_OUT_OF_RANGE) + return; + + switch (event.GetId()) + { + case ID_WINDOW_LEFT1: + { + markerTreeWindow->SetDefaultSize(wxSize(event.GetDragRect().width, 1000)); + break; + } + case ID_WINDOW_BOTTOM: + { + loggingWindow->SetDefaultSize(wxSize(1000, event.GetDragRect().height)); + break; + } + } + +#if wxUSE_MDI_ARCHITECTURE + wxLayoutAlgorithm layout; + layout.LayoutMDIFrame(this); +#endif // wxUSE_MDI_ARCHITECTURE + + // Leaves bits of itself behind sometimes + GetClientWindow()->Refresh(); +} + +// physically open the files +void OPJFrame::OpenFiles(wxArrayString paths, wxArrayString filenames) +{ + + size_t count = paths.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + wxString msg, s; + s.Printf(_T("File %d: %s (%s)\n"), + (int)n, paths[n].c_str(), filenames[n].c_str()); + + msg += s; + //s.Printf(_T("Filter index: %d"), dialog.GetFilterIndex()); + msg += s; + + /*wxMessageDialog dialog2(this, msg, _T("Selected files")); + dialog2.ShowModal();*/ + + // Make another frame, containing a canvas + OPJChildFrame *subframe = new OPJChildFrame(frame, + paths[n], + winNumber, + _T("Canvas Frame"), + wxDefaultPosition, wxSize(300, 300), + wxDEFAULT_FRAME_STYLE | + wxNO_FULL_REPAINT_ON_RESIZE); + m_childhash[winNumber] = subframe; + + // create own marker tree + long tstyle = wxTR_DEFAULT_STYLE | wxSUNKEN_BORDER | + #ifndef NO_VARIABLE_HEIGHT + wxTR_HAS_VARIABLE_ROW_HEIGHT /*|*/ + #endif + /*wxTR_EDIT_LABELS*/; + + m_treehash[winNumber] = new OPJMarkerTree(m_bookCtrl, paths[n], wxT("Parsing..."), TreeTest_Ctrl, + wxDefaultPosition, wxDefaultSize, + tstyle); + + m_bookCtrl->AddPage(m_treehash[winNumber], + wxString::Format(wxT("%u"), winNumber), false); + + for (int p = 0; p < m_bookCtrl->GetPageCount(); p++) { + + if (m_bookCtrl->GetPageText(p) == wxString::Format(wxT("%u"), winNumber)) { + m_bookCtrl->ChangeSelection(p); + break; + } + + } + + winNumber++; + + } + + +} + +void OPJFrame::OnFileOpen(wxCommandEvent& WXUNUSED(event)) +{ + wxString wildcards = +#ifdef __WXMOTIF__ + wxT("JPEG 2000 files (*.jp2,*.j2k,*.j2c,*.mj2)|*.*j*2*"); +#else + wxT("JPEG 2000 files (*.jp2,*.j2k,*.j2c,*.mj2)|*.jp2;*.j2k;*.j2c;*.mj2|JPEG files (*.jpg)|*.jpg|All files|*"); +#endif + wxFileDialog dialog(this, _T("Open JPEG 2000 file(s)"), + wxEmptyString, wxEmptyString, wildcards, + wxFD_OPEN|wxFD_MULTIPLE); + + if (dialog.ShowModal() == wxID_OK) + { + wxArrayString paths, filenames; + + dialog.GetPaths(paths); + dialog.GetFilenames(filenames); + + OpenFiles(paths, filenames); + + } + +} + +BEGIN_EVENT_TABLE(OPJCanvas, wxScrolledWindow) + EVT_MOUSE_EVENTS(OPJCanvas::OnEvent) +END_EVENT_TABLE() + +// Define a constructor for my canvas +OPJCanvas::OPJCanvas(wxFileName fname, wxWindow *parent, const wxPoint& pos, const wxSize& size) + : wxScrolledWindow(parent, wxID_ANY, pos, size, + wxSUNKEN_BORDER | wxNO_FULL_REPAINT_ON_RESIZE) +{ + SetBackgroundColour(OPJ_CANVAS_COLOUR); + + m_fname = fname; + + OPJDecoThread *dthread = CreateDecoThread(); + + if (dthread->Run() != wxTHREAD_NO_ERROR) + wxLogMessage(wxT("Can't start deco thread!")); + else + wxLogMessage(_T("New deco thread started.")); + +} + +OPJDecoThread *OPJCanvas::CreateDecoThread(void) +{ + OPJDecoThread *dthread = new OPJDecoThread(this); + + if (dthread->Create() != wxTHREAD_NO_ERROR) + wxLogError(wxT("Can't create deco thread!")); + + wxCriticalSectionLocker enter(wxGetApp().m_deco_critsect); + wxGetApp().m_deco_threads.Add(dthread); + + return dthread; +} + +// Define the repainting behaviour +void OPJCanvas::OnDraw(wxDC& dc) +{ + /*dc.SetFont(*wxSWISS_FONT); + dc.SetPen(*wxBLACK_PEN); + dc.DrawText(_T("Image drawing canvas"), 10, 10); + dc.DrawLine(8, 22, 300, 22);*/ + if (m_image.Ok()) { + dc.DrawBitmap(m_image, OPJ_CANVAS_BORDER, OPJ_CANVAS_BORDER); + } else { + dc.SetFont(*wxSWISS_FONT); + dc.SetPen(*wxBLACK_PEN); + dc.DrawText(_T("Decoding image, please wait..."), 40, 50); + } + + /*dc.SetFont(*wxSWISS_FONT); + dc.SetPen(*wxGREEN_PEN); + dc.DrawLine(0, 0, 200, 200); + dc.DrawLine(200, 0, 0, 200); + + dc.SetBrush(*wxCYAN_BRUSH); + dc.SetPen(*wxRED_PEN); + dc.DrawRectangle(100, 100, 100, 50); + dc.DrawRoundedRectangle(150, 150, 100, 50, 20); + + dc.DrawEllipse(250, 250, 100, 50); +#if wxUSE_SPLINES + dc.DrawSpline(50, 200, 50, 100, 200, 10); +#endif // wxUSE_SPLINES + dc.DrawLine(50, 230, 200, 230); + dc.DrawText(_T("This is a test string"), 50, 230); + + wxPoint points[3]; + points[0].x = 200; points[0].y = 300; + points[1].x = 100; points[1].y = 400; + points[2].x = 300; points[2].y = 400; + + dc.DrawPolygon(3, points);*/ +} + +// This implements a tiny doodling program! Drag the mouse using +// the left button. +void OPJCanvas::OnEvent(wxMouseEvent& event) +{ + wxClientDC dc(this); + PrepareDC(dc); + + wxPoint pt(event.GetLogicalPosition(dc)); + + if (xpos > -1 && ypos > -1 && event.Dragging()) + { + dc.SetPen(*wxBLACK_PEN); + dc.DrawLine(xpos, ypos, pt.x, pt.y); + } + xpos = pt.x; + ypos = pt.y; +} + +void OPJFrame::OnSize(wxSizeEvent& WXUNUSED(event)) +{ +#if wxUSE_MDI_ARCHITECTURE + wxLayoutAlgorithm layout; + layout.LayoutMDIFrame(this); +#endif // wxUSE_MDI_ARCHITECTURE +} + +// Note that SASHTEST_NEW_WINDOW and SASHTEST_ABOUT commands get passed +// to the parent window for processing, so no need to +// duplicate event handlers here. + +BEGIN_EVENT_TABLE(OPJChildFrame, wxMDIChildFrame) + /*EVT_MENU(SASHTEST_CHILD_QUIT, OPJChildFrame::OnQuit)*/ + EVT_CLOSE(OPJChildFrame::OnClose) + EVT_SET_FOCUS(OPJChildFrame::OnGotFocus) + /*EVT_KILL_FOCUS(OPJChildFrame::OnLostFocus)*/ +END_EVENT_TABLE() + +OPJChildFrame::OPJChildFrame(OPJFrame *parent, wxFileName fname, int winnumber, const wxString& title, const wxPoint& pos, const wxSize& size, +const long style): + wxMDIChildFrame(parent, wxID_ANY, title, pos, size, style) +{ + m_frame = (OPJFrame *) parent; + m_canvas = NULL; + my_children.Append(this); + m_fname = fname; + m_winnumber = winnumber; + SetTitle(wxString::Format(_T("%d: "), m_winnumber) + m_fname.GetFullName()); + + + // Give it an icon (this is ignored in MDI mode: uses resources) +#ifdef __WXMSW__ + SetIcon(wxIcon(_T("sashtest_icn"))); +#endif + +#if wxUSE_STATUSBAR + // Give it a status line + //CreateStatusBar(); +#endif // wxUSE_STATUSBAR + + // Make a menubar + /*wxMenu *file_menu = new wxMenu; + + file_menu->Append(SASHTEST_NEW_WINDOW, _T("&Open\tCtrl+O")); + file_menu->Append(SASHTEST_CHILD_QUIT, _T("&Close\tCtrl+C")); + file_menu->Append(SASHTEST_QUIT, _T("&Exit\tCtrl+Q")); + + wxMenu *option_menu = new wxMenu; + + // Dummy option + option_menu->Append(SASHTEST_REFRESH, _T("&Refresh picture")); + + wxMenu *help_menu = new wxMenu; + help_menu->Append(SASHTEST_ABOUT, _T("&About\tF1")); + + wxMenuBar *menu_bar = new wxMenuBar; + + menu_bar->Append(file_menu, _T("&File")); + menu_bar->Append(option_menu, _T("&Options")); + menu_bar->Append(help_menu, _T("&Help")); + + // Associate the menu bar with the frame + SetMenuBar(menu_bar);*/ + + + int width, height; + GetClientSize(&width, &height); + + OPJCanvas *canvas = new OPJCanvas(fname, this, wxPoint(0, 0), wxSize(width, height)); + canvas->SetCursor(wxCursor(wxCURSOR_PENCIL)); + m_canvas = canvas; + + // Give it scrollbars + canvas->SetScrollbars(20, 20, 5, 5); + + Show(true); + Maximize(true); + + + /*wxSize gsize = m_frame->m_bookCtrl->GetClientSize(); + m_frame->m_treehash[m_winnumber]->SetSize(0, 0, gsize.x, gsize.y);*/ + + /*m_frame->Resize(m_winnumber);*/ + /*m_frame->m_treehash[0]->Show(false); + m_frame->m_treehash[m_winnumber]->Show(true);*/ + /*m_frame->Resize(m_winnumber);*/ + + /*wxLogError(wxString::Format(wxT("Created tree %d (0x%x)"), m_winnumber, m_frame->m_treehash[m_winnumber]));*/ + +} + +OPJChildFrame::~OPJChildFrame(void) +{ + my_children.DeleteObject(this); +} + +/*void OPJChildFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) +{ + for (int p = 0; p < m_frame->m_bookCtrl->GetPageCount(); p++) { + + if (m_frame->m_bookCtrl->GetPageText(p) == wxString::Format(wxT("%u"), m_winnumber)) { + m_frame->m_bookCtrl->DeletePage(p);; + break; + } + + } + + Close(true); +}*/ + +void OPJChildFrame::OnClose(wxCloseEvent& event) +{ + for (int p = 0; p < m_frame->m_bookCtrl->GetPageCount(); p++) { + + if (m_frame->m_bookCtrl->GetPageText(p) == wxString::Format(wxT("%u"), m_winnumber)) { + m_frame->m_bookCtrl->DeletePage(p); + break; + } + + } + Destroy(); + + wxLogMessage(wxString::Format(wxT("Closed: %d"), m_winnumber)); + +} + +void OPJChildFrame::OnActivate(wxActivateEvent& event) +{ + /*if (event.GetActive() && m_canvas) + m_canvas->SetFocus();*/ +} + +void OPJChildFrame::OnGotFocus(wxFocusEvent& event) +{ + // we need to check if the notebook is being destroyed or not + if (!m_frame->m_bookCtrl) + return; + + for (int p = 0; p < m_frame->m_bookCtrl->GetPageCount(); p++) { + + if (m_frame->m_bookCtrl->GetPageText(p) == wxString::Format(wxT("%u"), m_winnumber)) { + m_frame->m_bookCtrl->ChangeSelection(p); + break; + } + + } + + wxLogMessage(wxString::Format(wxT("Got focus: %d (%x)"), m_winnumber, event.GetWindow())); +} + +/*void OPJChildFrame::OnLostFocus(wxFocusEvent& event) +{ + wxLogMessage(wxString::Format(wxT("Lost focus: %d (%x)"), m_winnumber, event.GetWindow())); + +}*/ + +#if USE_GENERIC_TREECTRL +BEGIN_EVENT_TABLE(OPJMarkerTree, wxGenericTreeCtrl) +#else +BEGIN_EVENT_TABLE(OPJMarkerTree, wxTreeCtrl) +#endif + /*EVT_TREE_BEGIN_DRAG(TreeTest_Ctrl, OPJMarkerTree::OnBeginDrag) + EVT_TREE_BEGIN_RDRAG(TreeTest_Ctrl, OPJMarkerTree::OnBeginRDrag) + EVT_TREE_END_DRAG(TreeTest_Ctrl, OPJMarkerTree::OnEndDrag)*/ + /*EVT_TREE_BEGIN_LABEL_EDIT(TreeTest_Ctrl, OPJMarkerTree::OnBeginLabelEdit) + EVT_TREE_END_LABEL_EDIT(TreeTest_Ctrl, OPJMarkerTree::OnEndLabelEdit)*/ + /*EVT_TREE_DELETE_ITEM(TreeTest_Ctrl, OPJMarkerTree::OnDeleteItem)*/ +#if 0 // there are so many of those that logging them causes flicker + /*EVT_TREE_GET_INFO(TreeTest_Ctrl, OPJMarkerTree::OnGetInfo)*/ +#endif + /*EVT_TREE_SET_INFO(TreeTest_Ctrl, OPJMarkerTree::OnSetInfo) + EVT_TREE_ITEM_EXPANDED(TreeTest_Ctrl, OPJMarkerTree::OnItemExpanded)*/ + EVT_TREE_ITEM_EXPANDING(TreeTest_Ctrl, OPJMarkerTree::OnItemExpanding) + /*EVT_TREE_ITEM_COLLAPSED(TreeTest_Ctrl, OPJMarkerTree::OnItemCollapsed) + EVT_TREE_ITEM_COLLAPSING(TreeTest_Ctrl, OPJMarkerTree::OnItemCollapsing)*/ + + EVT_TREE_SEL_CHANGED(TreeTest_Ctrl, OPJMarkerTree::OnSelChanged) + /*EVT_TREE_SEL_CHANGING(TreeTest_Ctrl, OPJMarkerTree::OnSelChanging)*/ + /*EVT_TREE_KEY_DOWN(TreeTest_Ctrl, OPJMarkerTree::OnTreeKeyDown)*/ + /*EVT_TREE_ITEM_ACTIVATED(TreeTest_Ctrl, OPJMarkerTree::OnItemActivated)*/ + + // so many differents ways to handle right mouse button clicks... + /*EVT_CONTEXT_MENU(OPJMarkerTree::OnContextMenu)*/ + // EVT_TREE_ITEM_MENU is the preferred event for creating context menus + // on a tree control, because it includes the point of the click or item, + // meaning that no additional placement calculations are required. + /*EVT_TREE_ITEM_MENU(TreeTest_Ctrl, OPJMarkerTree::OnItemMenu)*/ + /*EVT_TREE_ITEM_RIGHT_CLICK(TreeTest_Ctrl, OPJMarkerTree::OnItemRClick)*/ + + /*EVT_RIGHT_DOWN(OPJMarkerTree::OnRMouseDown) + EVT_RIGHT_UP(OPJMarkerTree::OnRMouseUp) + EVT_RIGHT_DCLICK(OPJMarkerTree::OnRMouseDClick)*/ +END_EVENT_TABLE() + +// OPJMarkerTree implementation +#if USE_GENERIC_TREECTRL +IMPLEMENT_DYNAMIC_CLASS(OPJMarkerTree, wxGenericTreeCtrl) +#else +IMPLEMENT_DYNAMIC_CLASS(OPJMarkerTree, wxTreeCtrl) +#endif + +OPJMarkerTree::OPJMarkerTree(wxWindow *parent, wxFileName fname, wxString name, const wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style) + : wxTreeCtrl(parent, id, pos, size, style) +{ + m_reverseSort = false; + m_fname = fname; + + m_peektextCtrl = ((OPJFrame *) (parent->GetParent()->GetParent()))->m_textCtrlbrowse; + CreateImageList(); + + // Add some items to the tree + //AddTestItemsToTree(5, 5); + int image = wxGetApp().ShowImages() ? OPJMarkerTree::TreeCtrlIcon_Folder : -1; + wxTreeItemId rootId = AddRoot(name, + image, image, + new OPJMarkerData(name)); + + OPJParseThread *pthread = CreateParseThread(); + if (pthread->Run() != wxTHREAD_NO_ERROR) + wxLogMessage(wxT("Can't start parse thread!")); + else + wxLogMessage(_T("New parse thread started.")); +} + +void OPJMarkerTree::CreateImageList(int size) +{ + if ( size == -1 ) + { + SetImageList(NULL); + return; + } + if ( size == 0 ) + size = m_imageSize; + else + m_imageSize = size; + + // Make an image list containing small icons + wxImageList *images = new wxImageList(size, size, true); + + // should correspond to TreeCtrlIcon_xxx enum + wxBusyCursor wait; + wxIcon icons[5]; + icons[0] = wxIcon(icon1_xpm); + icons[1] = wxIcon(icon2_xpm); + icons[2] = wxIcon(icon3_xpm); + icons[3] = wxIcon(icon4_xpm); + icons[4] = wxIcon(icon5_xpm); + + int sizeOrig = icons[0].GetWidth(); + for ( size_t i = 0; i < WXSIZEOF(icons); i++ ) + { + if ( size == sizeOrig ) + { + images->Add(icons[i]); + } + else + { + images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size))); + } + } + + AssignImageList(images); +} + +#if USE_GENERIC_TREECTRL || !defined(__WXMSW__) +void OPJMarkerTree::CreateButtonsImageList(int size) +{ + if ( size == -1 ) + { + SetButtonsImageList(NULL); + return; + } + + // Make an image list containing small icons + wxImageList *images = new wxImageList(size, size, true); + + // should correspond to TreeCtrlIcon_xxx enum + wxBusyCursor wait; + wxIcon icons[4]; + icons[0] = wxIcon(icon3_xpm); // closed + icons[1] = wxIcon(icon3_xpm); // closed, selected + icons[2] = wxIcon(icon5_xpm); // open + icons[3] = wxIcon(icon5_xpm); // open, selected + + for ( size_t i = 0; i < WXSIZEOF(icons); i++ ) + { + int sizeOrig = icons[i].GetWidth(); + if ( size == sizeOrig ) + { + images->Add(icons[i]); + } + else + { + images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size))); + } + } + + AssignButtonsImageList(images); +#else +void OPJMarkerTree::CreateButtonsImageList(int WXUNUSED(size)) +{ +#endif +} + +void OPJParseThread::LoadFile(wxFileName fname) +{ + wxTreeItemId rootid; + + // this is the root node + int image = wxGetApp().ShowImages() ? m_tree->TreeCtrlIcon_Folder : -1; + + if (this->m_parentid) { + // leaf of a tree + rootid = m_parentid; + m_tree->SetItemText(rootid, wxT("Parsing...")); + + } else { + + // delete the existing tree hierarchy + m_tree->DeleteAllItems(); + + // new tree + rootid = m_tree->AddRoot(wxT("Parsing..."), + image, + image, + new OPJMarkerData(fname.GetFullPath()) + ); + //m_tree->SetItemFont(rootid, *wxITALIC_FONT); + m_tree->SetItemBold(rootid); + } + + // open the file + wxFile m_file(fname.GetFullPath().c_str(), wxFile::read); + + // what is the extension? + if ((fname.GetExt() == wxT("j2k")) || (fname.GetExt() == wxT("j2c"))) { + + // parse the file + ParseJ2KFile(&m_file, 0, m_file.Length(), rootid); + + } else if ((fname.GetExt() == wxT("jp2")) || (fname.GetExt() == wxT("mj2"))) { + + // parse the file + if (this->m_parentid) { + //WriteText(wxT("Only a subsection of jp2")); + OPJMarkerData *data = (OPJMarkerData *) m_tree->GetItemData(rootid); + ParseJ2KFile(&m_file, data->m_start, data->m_length, rootid); + m_tree->Expand(rootid); + + } else + // as usual + ParseJP2File(&m_file, 0, m_file.Length(), rootid); + + } else { + + // unknown extension + WriteText(wxT("Unknown file format!")); + + } + + // close the file + m_file.Close(); + + // this is the root node + if (this->m_parentid) + m_tree->SetItemText(rootid, wxT("Codestream")); + else + m_tree->SetItemText(rootid, fname.GetFullName()); + + WriteText(wxT("Parsing finished!")); +} + +/*int OPJMarkerTree::OnCompareItems(const wxTreeItemId& item1, + const wxTreeItemId& item2) +{ + if ( m_reverseSort ) + { + // just exchange 1st and 2nd items + return wxTreeCtrl::OnCompareItems(item2, item1); + } + else + { + return wxTreeCtrl::OnCompareItems(item1, item2); + } +}*/ + +/*void OPJMarkerTree::AddItemsRecursively(const wxTreeItemId& idParent, + size_t numChildren, + size_t depth, + size_t folder) +{ + if ( depth > 0 ) + { + bool hasChildren = depth > 1; + + wxString str; + for ( size_t n = 0; n < numChildren; n++ ) + { + // at depth 1 elements won't have any more children + if ( hasChildren ) + str.Printf(wxT("%s child %u"), wxT("Folder"), unsigned(n + 1)); + else + str.Printf(wxT("%s child %u.%u"), wxT("File"), unsigned(folder), unsigned(n + 1)); + + // here we pass to AppendItem() normal and selected item images (we + // suppose that selected image follows the normal one in the enum) + int image, imageSel; + if ( wxGetApp().ShowImages() ) + { + image = depth == 1 ? TreeCtrlIcon_File : TreeCtrlIcon_Folder; + imageSel = image + 1; + } + else + { + image = imageSel = -1; + } + wxTreeItemId id = AppendItem(idParent, str, image, imageSel, + new OPJMarkerData(str)); + + // and now we also set the expanded one (only for the folders) + if ( hasChildren && wxGetApp().ShowImages() ) + { + SetItemImage(id, TreeCtrlIcon_FolderOpened, + wxTreeItemIcon_Expanded); + } + + // remember the last child for OnEnsureVisible() + if ( !hasChildren && n == numChildren - 1 ) + { + m_lastItem = id; + } + + AddItemsRecursively(id, numChildren, depth - 1, n + 1); + } + } + //else: done! +}*/ + +/*void OPJMarkerTree::AddTestItemsToTree(size_t numChildren, + size_t depth) +{ + int image = wxGetApp().ShowImages() ? OPJMarkerTree::TreeCtrlIcon_Folder : -1; + wxTreeItemId rootId = AddRoot(wxT("Root"), + image, image, + new OPJMarkerData(wxT("Root item"))); + if ( image != -1 ) + { + SetItemImage(rootId, TreeCtrlIcon_FolderOpened, wxTreeItemIcon_Expanded); + } + + AddItemsRecursively(rootId, numChildren, depth, 0); + + // set some colours/fonts for testing + SetItemFont(rootId, *wxITALIC_FONT); + + wxTreeItemIdValue cookie; + wxTreeItemId id = GetFirstChild(rootId, cookie); + SetItemTextColour(id, *wxBLUE); + + id = GetNextChild(rootId, cookie); + id = GetNextChild(rootId, cookie); + SetItemTextColour(id, *wxRED); + SetItemBackgroundColour(id, *wxLIGHT_GREY); +}*/ + +/*void OPJMarkerTree::GetItemsRecursively(const wxTreeItemId& idParent, + wxTreeItemIdValue cookie) +{ + wxTreeItemId id; + + if ( !cookie ) + id = GetFirstChild(idParent, cookie); + else + id = GetNextChild(idParent, cookie); + + if ( !id.IsOk() ) + return; + + wxString text = GetItemText(id); + wxLogMessage(text); + + if (ItemHasChildren(id)) + GetItemsRecursively(id); + + GetItemsRecursively(idParent, cookie); +}*/ + +/*void OPJMarkerTree::DoToggleIcon(const wxTreeItemId& item) +{ + int image = (GetItemImage(item) == TreeCtrlIcon_Folder) + ? TreeCtrlIcon_File + : TreeCtrlIcon_Folder; + SetItemImage(item, image, wxTreeItemIcon_Normal); + + image = (GetItemImage(item) == TreeCtrlIcon_FolderSelected) + ? TreeCtrlIcon_FileSelected + : TreeCtrlIcon_FolderSelected; + SetItemImage(item, image, wxTreeItemIcon_Selected); +}*/ + +void OPJMarkerTree::LogEvent(const wxChar *name, const wxTreeEvent& event) +{ + wxTreeItemId item = event.GetItem(); + wxString text; + if ( item.IsOk() ) + text << _T('"') << GetItemText(item).c_str() << _T('"'); + else + text = _T("invalid item"); + wxLogMessage(wxT("%s(%s)"), name, text.c_str()); +} + +OPJParseThread *OPJMarkerTree::CreateParseThread(wxTreeItemId parentid) +{ + OPJParseThread *pthread = new OPJParseThread(this, parentid); + + if (pthread->Create() != wxTHREAD_NO_ERROR) + wxLogError(wxT("Can't create parse thread!")); + + wxCriticalSectionLocker enter(wxGetApp().m_parse_critsect); + wxGetApp().m_parse_threads.Add(pthread); + + return pthread; +} + + +/*// avoid repetition +#define TREE_EVENT_HANDLER(name) \ +void OPJMarkerTree::name(wxTreeEvent& event) \ +{ \ + LogEvent(_T(#name), event); \ + SetLastItem(wxTreeItemId()); \ + event.Skip(); \ +}*/ + +/*TREE_EVENT_HANDLER(OnBeginRDrag)*/ +/*TREE_EVENT_HANDLER(OnDeleteItem)*/ +/*TREE_EVENT_HANDLER(OnGetInfo) +TREE_EVENT_HANDLER(OnSetInfo)*/ +/*TREE_EVENT_HANDLER(OnItemExpanded) +TREE_EVENT_HANDLER(OnItemExpanding)*/ +/*TREE_EVENT_HANDLER(OnItemCollapsed)*/ +/*TREE_EVENT_HANDLER(OnSelChanged) +TREE_EVENT_HANDLER(OnSelChanging)*/ + +/*#undef TREE_EVENT_HANDLER*/ + +void OPJMarkerTree::OnItemExpanding(wxTreeEvent& event) +{ + wxTreeItemId item = event.GetItem(); + OPJMarkerData* data = (OPJMarkerData *) GetItemData(item); + wxString text; + + if (item.IsOk()) + text << wxT('"') << GetItemText(item).c_str() << wxT('"'); + else + text = wxT("invalid item"); + + if (strcmp(data->GetDesc1(), wxT("INFO-CSTREAM"))) + return; + + wxLogMessage(wxT("Expanding... (%s -> %s, %s, %d, %d)"), + text.c_str(), data->GetDesc1(), data->GetDesc2(), + data->m_start, data->m_length); + + // the codestream box is being asked for expansion + wxTreeItemIdValue cookie; + if (!GetFirstChild(item, cookie).IsOk()) { + OPJParseThread *pthread = CreateParseThread(item); + if (pthread->Run() != wxTHREAD_NO_ERROR) + wxLogMessage(wxT("Can't start parse thread!")); + else + wxLogMessage(wxT("New parse thread started.")); + } +} + +void OPJMarkerTree::OnSelChanged(wxTreeEvent& event) +{ +#define BUNCH_LINESIZE 24 +#define BUNCH_NUMLINES 6 + + wxTreeItemId item = event.GetItem(); + OPJMarkerData* data = (OPJMarkerData *) GetItemData(item); + wxString text; + int l, c, pos = 0, pre_pos; + unsigned char buffer[BUNCH_LINESIZE * BUNCH_NUMLINES]; + + m_peektextCtrl->Clear(); + + /*wxTextAttr myattr = m_peektextCtrl->GetDefaultStyle(); + myattr.SetFont(wxFont(10, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + m_peektextCtrl->SetDefaultStyle(myattr);*/ + + text << wxString::Format(wxT("Selected... (%s -> %s, %s, %d, %d)"), + text.c_str(), data->GetDesc1(), data->GetDesc2(), + data->m_start, data->m_length) << wxT("\n"); + + // open the file and browse a little + wxFile *fp = new wxFile(m_fname.GetFullPath().c_str(), wxFile::read); + + // go to position claimed + fp->Seek(data->m_start, wxFromStart); + + // read a bunch + int max_read = wxMin(WXSIZEOF(buffer), data->m_length - data->m_start + 1); + fp->Read(buffer, max_read); + + pos = 0; + for (l = 0; l < BUNCH_NUMLINES; l++) { + + text << wxString::Format(wxT("%08d:"), data->m_start + pos); + + pre_pos = pos; + + // add hex browsing text + for (c = 0; c < BUNCH_LINESIZE; c++) { + + if (!(c % 8)) + text << wxT(" "); + + if (pos < max_read) { + text << wxString::Format(wxT("%02X "), wxT(buffer[pos])); + } else + text << wxT(" "); + pos++; + } + + text << wxT(" "); + + // add char browsing text + for (c = 0; c < BUNCH_LINESIZE; c++) { + + if (pre_pos < max_read) { + if ((buffer[pre_pos] == '\n') || (buffer[pre_pos] == '\t')) + buffer[pre_pos] = ' '; + text << wxString::Format(wxT("%c."), wxChar(buffer[pre_pos])); + } else + text << wxT(" "); + pre_pos++; + } + + text << wxT("\n"); + + } + + // close the file + fp->Close(); + + m_peektextCtrl->WriteText(text); +} + +/*void LogKeyEvent(const wxChar *name, const wxKeyEvent& event) +{ + wxString key; + long keycode = event.GetKeyCode(); + { + switch ( keycode ) + { + case WXK_BACK: key = wxT("BACK"); break; + case WXK_TAB: key = wxT("TAB"); break; + case WXK_RETURN: key = wxT("RETURN"); break; + case WXK_ESCAPE: key = wxT("ESCAPE"); break; + case WXK_SPACE: key = wxT("SPACE"); break; + case WXK_DELETE: key = wxT("DELETE"); break; + case WXK_START: key = wxT("START"); break; + case WXK_LBUTTON: key = wxT("LBUTTON"); break; + case WXK_RBUTTON: key = wxT("RBUTTON"); break; + case WXK_CANCEL: key = wxT("CANCEL"); break; + case WXK_MBUTTON: key = wxT("MBUTTON"); break; + case WXK_CLEAR: key = wxT("CLEAR"); break; + case WXK_SHIFT: key = wxT("SHIFT"); break; + case WXK_ALT: key = wxT("ALT"); break; + case WXK_CONTROL: key = wxT("CONTROL"); break; + case WXK_MENU: key = wxT("MENU"); break; + case WXK_PAUSE: key = wxT("PAUSE"); break; + case WXK_CAPITAL: key = wxT("CAPITAL"); break; + case WXK_END: key = wxT("END"); break; + case WXK_HOME: key = wxT("HOME"); break; + case WXK_LEFT: key = wxT("LEFT"); break; + case WXK_UP: key = wxT("UP"); break; + case WXK_RIGHT: key = wxT("RIGHT"); break; + case WXK_DOWN: key = wxT("DOWN"); break; + case WXK_SELECT: key = wxT("SELECT"); break; + case WXK_PRINT: key = wxT("PRINT"); break; + case WXK_EXECUTE: key = wxT("EXECUTE"); break; + case WXK_SNAPSHOT: key = wxT("SNAPSHOT"); break; + case WXK_INSERT: key = wxT("INSERT"); break; + case WXK_HELP: key = wxT("HELP"); break; + case WXK_NUMPAD0: key = wxT("NUMPAD0"); break; + case WXK_NUMPAD1: key = wxT("NUMPAD1"); break; + case WXK_NUMPAD2: key = wxT("NUMPAD2"); break; + case WXK_NUMPAD3: key = wxT("NUMPAD3"); break; + case WXK_NUMPAD4: key = wxT("NUMPAD4"); break; + case WXK_NUMPAD5: key = wxT("NUMPAD5"); break; + case WXK_NUMPAD6: key = wxT("NUMPAD6"); break; + case WXK_NUMPAD7: key = wxT("NUMPAD7"); break; + case WXK_NUMPAD8: key = wxT("NUMPAD8"); break; + case WXK_NUMPAD9: key = wxT("NUMPAD9"); break; + case WXK_MULTIPLY: key = wxT("MULTIPLY"); break; + case WXK_ADD: key = wxT("ADD"); break; + case WXK_SEPARATOR: key = wxT("SEPARATOR"); break; + case WXK_SUBTRACT: key = wxT("SUBTRACT"); break; + case WXK_DECIMAL: key = wxT("DECIMAL"); break; + case WXK_DIVIDE: key = wxT("DIVIDE"); break; + case WXK_F1: key = wxT("F1"); break; + case WXK_F2: key = wxT("F2"); break; + case WXK_F3: key = wxT("F3"); break; + case WXK_F4: key = wxT("F4"); break; + case WXK_F5: key = wxT("F5"); break; + case WXK_F6: key = wxT("F6"); break; + case WXK_F7: key = wxT("F7"); break; + case WXK_F8: key = wxT("F8"); break; + case WXK_F9: key = wxT("F9"); break; + case WXK_F10: key = wxT("F10"); break; + case WXK_F11: key = wxT("F11"); break; + case WXK_F12: key = wxT("F12"); break; + case WXK_F13: key = wxT("F13"); break; + case WXK_F14: key = wxT("F14"); break; + case WXK_F15: key = wxT("F15"); break; + case WXK_F16: key = wxT("F16"); break; + case WXK_F17: key = wxT("F17"); break; + case WXK_F18: key = wxT("F18"); break; + case WXK_F19: key = wxT("F19"); break; + case WXK_F20: key = wxT("F20"); break; + case WXK_F21: key = wxT("F21"); break; + case WXK_F22: key = wxT("F22"); break; + case WXK_F23: key = wxT("F23"); break; + case WXK_F24: key = wxT("F24"); break; + case WXK_NUMLOCK: key = wxT("NUMLOCK"); break; + case WXK_SCROLL: key = wxT("SCROLL"); break; + case WXK_PAGEUP: key = wxT("PAGEUP"); break; + case WXK_PAGEDOWN: key = wxT("PAGEDOWN"); break; + case WXK_NUMPAD_SPACE: key = wxT("NUMPAD_SPACE"); break; + case WXK_NUMPAD_TAB: key = wxT("NUMPAD_TAB"); break; + case WXK_NUMPAD_ENTER: key = wxT("NUMPAD_ENTER"); break; + case WXK_NUMPAD_F1: key = wxT("NUMPAD_F1"); break; + case WXK_NUMPAD_F2: key = wxT("NUMPAD_F2"); break; + case WXK_NUMPAD_F3: key = wxT("NUMPAD_F3"); break; + case WXK_NUMPAD_F4: key = wxT("NUMPAD_F4"); break; + case WXK_NUMPAD_HOME: key = wxT("NUMPAD_HOME"); break; + case WXK_NUMPAD_LEFT: key = wxT("NUMPAD_LEFT"); break; + case WXK_NUMPAD_UP: key = wxT("NUMPAD_UP"); break; + case WXK_NUMPAD_RIGHT: key = wxT("NUMPAD_RIGHT"); break; + case WXK_NUMPAD_DOWN: key = wxT("NUMPAD_DOWN"); break; + case WXK_NUMPAD_PAGEUP: key = wxT("NUMPAD_PAGEUP"); break; + case WXK_NUMPAD_PAGEDOWN: key = wxT("NUMPAD_PAGEDOWN"); break; + case WXK_NUMPAD_END: key = wxT("NUMPAD_END"); break; + case WXK_NUMPAD_BEGIN: key = wxT("NUMPAD_BEGIN"); break; + case WXK_NUMPAD_INSERT: key = wxT("NUMPAD_INSERT"); break; + case WXK_NUMPAD_DELETE: key = wxT("NUMPAD_DELETE"); break; + case WXK_NUMPAD_EQUAL: key = wxT("NUMPAD_EQUAL"); break; + case WXK_NUMPAD_MULTIPLY: key = wxT("NUMPAD_MULTIPLY"); break; + case WXK_NUMPAD_ADD: key = wxT("NUMPAD_ADD"); break; + case WXK_NUMPAD_SEPARATOR: key = wxT("NUMPAD_SEPARATOR"); break; + case WXK_NUMPAD_SUBTRACT: key = wxT("NUMPAD_SUBTRACT"); break; + case WXK_NUMPAD_DECIMAL: key = wxT("NUMPAD_DECIMAL"); break; + + default: + { + if ( keycode < 128 && wxIsprint((int)keycode) ) + key.Printf(wxT("'%c'"), (char)keycode); + else if ( keycode > 0 && keycode < 27 ) + key.Printf(_("Ctrl-%c"), wxT('A') + keycode - 1); + else + key.Printf(wxT("unknown (%ld)"), keycode); + } + } + } + + wxLogMessage( wxT("%s event: %s (flags = %c%c%c%c)"), + name, + key.c_str(), + event.ControlDown() ? wxT('C') : wxT('-'), + event.AltDown() ? wxT('A') : wxT('-'), + event.ShiftDown() ? wxT('S') : wxT('-'), + event.MetaDown() ? wxT('M') : wxT('-')); +} + +void OPJMarkerTree::OnTreeKeyDown(wxTreeEvent& event) +{ + LogKeyEvent(wxT("Tree key down "), event.GetKeyEvent()); + + event.Skip(); +}*/ + +/*void OPJMarkerTree::OnBeginDrag(wxTreeEvent& event) +{ + // need to explicitly allow drag + if ( event.GetItem() != GetRootItem() ) + { + m_draggedItem = event.GetItem(); + + wxLogMessage(wxT("OnBeginDrag: started dragging %s"), + GetItemText(m_draggedItem).c_str()); + + event.Allow(); + } + else + { + wxLogMessage(wxT("OnBeginDrag: this item can't be dragged.")); + } +} + +void OPJMarkerTree::OnEndDrag(wxTreeEvent& event) +{ + wxTreeItemId itemSrc = m_draggedItem, + itemDst = event.GetItem(); + m_draggedItem = (wxTreeItemId)0l; + + // where to copy the item? + if ( itemDst.IsOk() && !ItemHasChildren(itemDst) ) + { + // copy to the parent then + itemDst = GetItemParent(itemDst); + } + + if ( !itemDst.IsOk() ) + { + wxLogMessage(wxT("OnEndDrag: can't drop here.")); + + return; + } + + wxString text = GetItemText(itemSrc); + wxLogMessage(wxT("OnEndDrag: '%s' copied to '%s'."), + text.c_str(), GetItemText(itemDst).c_str()); + + // just do append here - we could also insert it just before/after the item + // on which it was dropped, but this requires slightly more work... we also + // completely ignore the client data and icon of the old item but could + // copy them as well. + // + // Finally, we only copy one item here but we might copy the entire tree if + // we were dragging a folder. + int image = wxGetApp().ShowImages() ? TreeCtrlIcon_File : -1; + AppendItem(itemDst, text, image); +}*/ + +/*void OPJMarkerTree::OnBeginLabelEdit(wxTreeEvent& event) +{ + wxLogMessage(wxT("OnBeginLabelEdit")); + + // for testing, prevent this item's label editing + wxTreeItemId itemId = event.GetItem(); + if ( IsTestItem(itemId) ) + { + wxMessageBox(wxT("You can't edit this item.")); + + event.Veto(); + } + else if ( itemId == GetRootItem() ) + { + // test that it is possible to change the text of the item being edited + SetItemText(itemId, _T("Editing root item")); + } +} + +void OPJMarkerTree::OnEndLabelEdit(wxTreeEvent& event) +{ + wxLogMessage(wxT("OnEndLabelEdit")); + + // don't allow anything except letters in the labels + if ( !event.GetLabel().IsWord() ) + { + wxMessageBox(wxT("The new label should be a single word.")); + + event.Veto(); + } +}*/ + +/*void OPJMarkerTree::OnItemCollapsing(wxTreeEvent& event) +{ + wxLogMessage(wxT("OnItemCollapsing")); + + // for testing, prevent the user from collapsing the first child folder + wxTreeItemId itemId = event.GetItem(); + if ( IsTestItem(itemId) ) + { + wxMessageBox(wxT("You can't collapse this item.")); + + event.Veto(); + } +}*/ + +/*void OPJMarkerTree::OnItemActivated(wxTreeEvent& event) +{ + // show some info about this item + wxTreeItemId itemId = event.GetItem(); + OPJMarkerData *item = (OPJMarkerData *)GetItemData(itemId); + + if ( item != NULL ) + { + item->ShowInfo(this); + } + + wxLogMessage(wxT("OnItemActivated")); +}*/ + +/*void OPJMarkerTree::OnItemMenu(wxTreeEvent& event) +{ + wxTreeItemId itemId = event.GetItem(); + OPJMarkerData *item = itemId.IsOk() ? (OPJMarkerData *)GetItemData(itemId) + : NULL; + + wxLogMessage(wxT("OnItemMenu for item \"%s\""), item ? item->GetDesc() + : _T("")); + + event.Skip(); +}*/ + +/*void OPJMarkerTree::OnContextMenu(wxContextMenuEvent& event) +{ + wxPoint pt = event.GetPosition(); + wxTreeItemId item; + wxLogMessage(wxT("OnContextMenu at screen coords (%i, %i)"), pt.x, pt.y); + + // check if event was generated by keyboard (MSW-specific?) + if ( pt.x == -1 && pt.y == -1 ) //(this is how MSW indicates it) + { + if ( !HasFlag(wxTR_MULTIPLE) ) + item = GetSelection(); + + // attempt to guess where to show the menu + if ( item.IsOk() ) + { + // if an item was clicked, show menu to the right of it + wxRect rect; + GetBoundingRect(item, rect, true );// only the label + pt = wxPoint(rect.GetRight(), rect.GetTop()); + } + else + { + pt = wxPoint(0, 0); + } + } + else // event was generated by mouse, use supplied coords + { + pt = ScreenToClient(pt); + item = HitTest(pt); + } + + ShowMenu(item, pt); +}*/ + +/*void OPJMarkerTree::ShowMenu(wxTreeItemId id, const wxPoint& pt) +{ + wxString title; + if ( id.IsOk() ) + { + title << wxT("Menu for ") << GetItemText(id); + } + else + { + title = wxT("Menu for no particular item"); + } + +#if wxUSE_MENUS + wxMenu menu(title); + menu.Append(TreeTest_About, wxT("&About...")); + menu.AppendSeparator(); + menu.Append(TreeTest_Highlight, wxT("&Highlight item")); + menu.Append(TreeTest_Dump, wxT("&Dump")); + + PopupMenu(&menu, pt); +#endif // wxUSE_MENUS +}*/ + +/*void OPJMarkerTree::OnItemRClick(wxTreeEvent& event) +{ + wxTreeItemId itemId = event.GetItem(); + OPJMarkerData *item = itemId.IsOk() ? (OPJMarkerData *)GetItemData(itemId) + : NULL; + + wxLogMessage(wxT("Item \"%s\" right clicked"), item ? item->GetDesc() + : _T("")); + + event.Skip(); +}*/ + +/* +void OPJMarkerTree::OnRMouseDown(wxMouseEvent& event) +{ + wxLogMessage(wxT("Right mouse button down")); + + event.Skip(); +} + +void OPJMarkerTree::OnRMouseUp(wxMouseEvent& event) +{ + wxLogMessage(wxT("Right mouse button up")); + + event.Skip(); +} + +void OPJMarkerTree::OnRMouseDClick(wxMouseEvent& event) +{ + wxTreeItemId id = HitTest(event.GetPosition()); + if ( !id ) + wxLogMessage(wxT("No item under mouse")); + else + { + OPJMarkerData *item = (OPJMarkerData *)GetItemData(id); + if ( item ) + wxLogMessage(wxT("Item '%s' under mouse"), item->GetDesc()); + } + + event.Skip(); +} +*/ + +static inline const wxChar *Bool2String(bool b) +{ + return b ? wxT("") : wxT("not "); +} + +void OPJMarkerData::ShowInfo(wxTreeCtrl *tree) +{ + wxLogMessage(wxT("Item '%s': %sselected, %sexpanded, %sbold,\n") + wxT("%u children (%u immediately under this item)."), + m_desc.c_str(), + Bool2String(tree->IsSelected(GetId())), + Bool2String(tree->IsExpanded(GetId())), + Bool2String(tree->IsBold(GetId())), + unsigned(tree->GetChildrenCount(GetId())), + unsigned(tree->GetChildrenCount(GetId(), false))); +} + +///////////////////////////////////////////////////////////////////// +// Decoding thread class +///////////////////////////////////////////////////////////////////// + +OPJDecoThread::OPJDecoThread(OPJCanvas *canvas) + : wxThread() +{ + m_count = 0; + m_canvas = canvas; +} + +void OPJDecoThread::WriteText(const wxString& text) +{ + wxString msg; + + // before doing any GUI calls we must ensure that this thread is the only + // one doing it! + + wxMutexGuiEnter(); + + msg << text; + m_canvas->WriteText(msg); + + wxMutexGuiLeave(); +} + +void OPJDecoThread::OnExit() +{ + wxCriticalSectionLocker locker(wxGetApp().m_deco_critsect); + + wxArrayThread& dthreads = wxGetApp().m_deco_threads; + dthreads.Remove(this); + + if (dthreads.IsEmpty() ) + { + // signal the main thread that there are no more threads left if it is + // waiting for us + if (wxGetApp().m_deco_waitingUntilAllDone) { + wxGetApp().m_deco_waitingUntilAllDone = false; + wxGetApp().m_deco_semAllDone.Post(); + } + } +} + +void *OPJDecoThread::Entry() +{ + + wxString text; + + srand(GetId()); + int m_countnum = rand() % 9; + text.Printf(wxT("Deco thread 0x%lx started (priority = %u, time = %d)."), + GetId(), GetPriority(), m_countnum); + WriteText(text); + // wxLogMessage(text); -- test wxLog thread safeness + + //wxBusyCursor wait; + //wxBusyInfo wait(wxT("Decoding image ...")); + + + /*for (m_count = 0; m_count < m_countnum; m_count++) { + // check if we were asked to exit + if ( TestDestroy() ) + break; + + text.Printf(wxT("[%u] Deco thread 0x%lx here."), m_count, GetId()); + WriteText(text); + + // wxSleep() can't be called from non-GUI thread! + wxThread::Sleep(10); + }*/ + + wxBitmap bitmap( 100, 100 ); + wxImage image = bitmap.ConvertToImage(); + image.Destroy(); + + WriteText(m_canvas->m_fname.GetFullPath()); + + if (!image.LoadFile(m_canvas->m_fname.GetFullPath(), wxBITMAP_TYPE_ANY), 0) { + wxLogError(wxT("Can't load image")); + return NULL; + } + + m_canvas->m_image = wxBitmap(image); + m_canvas->Refresh(); + m_canvas->SetScrollbars(20, 20, (int)(0.5 + (double) image.GetWidth() / 20.0), (int)(0.5 + (double) image.GetHeight() / 20.0)); + + text.Printf(wxT("Deco thread 0x%lx finished."), GetId()); + WriteText(text); + // wxLogMessage(text); -- test wxLog thread safeness + + return NULL; +} + +///////////////////////////////////////////////////////////////////// +// Parsing thread class +///////////////////////////////////////////////////////////////////// + +OPJParseThread::OPJParseThread(OPJMarkerTree *tree, wxTreeItemId parentid) + : wxThread() +{ + m_count = 0; + m_tree = tree; + m_parentid = parentid; +} + +void OPJParseThread::WriteText(const wxString& text) +{ + wxString msg; + + // before doing any GUI calls we must ensure that this thread is the only + // one doing it! + + wxMutexGuiEnter(); + + msg << text; + m_tree->WriteText(msg); + + wxMutexGuiLeave(); +} + +void OPJParseThread::OnExit() +{ + wxCriticalSectionLocker locker(wxGetApp().m_parse_critsect); + + wxArrayThread& threads = wxGetApp().m_parse_threads; + threads.Remove(this); + + if ( threads.IsEmpty() ) + { + // signal the main thread that there are no more threads left if it is + // waiting for us + if ( wxGetApp().m_parse_waitingUntilAllDone ) + { + wxGetApp().m_parse_waitingUntilAllDone = false; + + wxGetApp().m_parse_semAllDone.Post(); + } + } +} + +void *OPJParseThread::Entry() +{ + + wxString text; + + srand( GetId() ); + int m_countnum = rand() % 9; + text.Printf(wxT("Parse thread 0x%lx started (priority = %u, time = %d)."), + GetId(), GetPriority(), m_countnum); + WriteText(text); + // wxLogMessage(text); -- test wxLog thread safeness + + //wxBusyCursor wait; + //wxBusyInfo wait(wxT("Decoding image ...")); + + + /*for ( m_count = 0; m_count < m_countnum; m_count++ ) + { + // check if we were asked to exit + if ( TestDestroy() ) + break; + + text.Printf(wxT("[%u] Parse thread 0x%lx here."), m_count, GetId()); + WriteText(text); + + // wxSleep() can't be called from non-GUI thread! + wxThread::Sleep(10); + }*/ + + + LoadFile(m_tree->m_fname); + + text.Printf(wxT("Parse thread 0x%lx finished."), GetId()); + WriteText(text); + // wxLogMessage(text); -- test wxLog thread safeness + + return NULL; +} diff --git a/OPJViewer/source/OPJViewer.h b/OPJViewer/source/OPJViewer.h new file mode 100644 index 00000000..f386ea8c --- /dev/null +++ b/OPJViewer/source/OPJViewer.h @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: sashtest.h +// Purpose: Layout window/sash sample +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: sashtest.h,v 1.5 2005/06/02 12:04:24 JS Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: treectrl.h +// Purpose: wxTreeCtrl sample +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: treetest.h,v 1.50 2006/11/04 11:26:51 VZ Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +#ifndef __OPJ_VIEWER_H__ +#define __OPJ_VIEWER_H__ + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#include "wx/mdi.h" +#endif + +#include "wx/toolbar.h" +#include "wx/laywin.h" +#include "wx/treectrl.h" + +#include "icon1.xpm" +#include "icon2.xpm" +#include "icon3.xpm" +#include "icon4.xpm" +#include "icon5.xpm" + +#include "wx/filedlg.h" +#include "wx/toolbar.h" +#include +#include +#include +#include +#include "wx/notebook.h" + +#include "libopenjpeg\openjpeg.h" + +#include "imagj2k.h" +#include "imagjp2.h" +#include "imagmj2.h" + +#define USE_GENERIC_TREECTRL 0 + +#if USE_GENERIC_TREECTRL +#include "wx/generic/treectlg.h" +#ifndef wxTreeCtrl +#define wxTreeCtrl wxGenericTreeCtrl +#define sm_classwxTreeCtrl sm_classwxGenericTreeCtrl +#endif +#endif + +#define OPJ_APPLICATION_NAME wxT("OpenJPEG Viewer") +#define OPJ_APPLICATION_VERSION wxT("0.1 alpha") +#define OPJ_APPLICATION_TITLEBAR OPJ_APPLICATION_NAME wxT(" ") OPJ_APPLICATION_VERSION +#define OPJ_APPLICATION_COPYRIGHT wxT("(C) 2007, Giuseppe Baruffa") + +#define OPJ_CANVAS_BORDER 10 +#define OPJ_CANVAS_COLOUR *wxWHITE + +class OPJDecoThread; +class OPJParseThread; +WX_DEFINE_ARRAY_PTR(wxThread *, wxArrayThread); +class OPJChildFrame; + +////////////////////////////////// +// this is our main application // +////////////////////////////////// +class OPJViewerApp: public wxApp +{ + // public methods and variables + public: + + // class constructor + OPJViewerApp() { m_showImages = true; m_showButtons = false; } + + // other methods + bool OnInit(void); + void SetShowImages(bool show) { m_showImages = show; } + bool ShowImages() const { return m_showImages; } + void ShowCmdLine(const wxCmdLineParser& parser); + + // all the threads currently alive - as soon as the thread terminates, it's + // removed from the array + wxArrayThread m_deco_threads, m_parse_threads; + + // crit section protects access to all of the arrays below + wxCriticalSection m_deco_critsect, m_parse_critsect; + + // semaphore used to wait for the threads to exit, see OPJFrame::OnQuit() + wxSemaphore m_deco_semAllDone, m_parse_semAllDone; + + // the last exiting thread should post to m_semAllDone if this is true + // (protected by the same m_critsect) + bool m_deco_waitingUntilAllDone, m_parse_waitingUntilAllDone; + + // the list of all filenames written in the command line + wxArrayString m_filelist; + + // private methods and variables + private: + bool m_showImages, m_showButtons; + +}; + +DECLARE_APP(OPJViewerApp) + +/////////////////////////////////////////// +// this canvas is used to draw the image // +/////////////////////////////////////////// +class OPJCanvas: public wxScrolledWindow +{ + // public methods and variables + public: + + // class constructor + OPJCanvas(wxFileName fname, wxWindow *parent, const wxPoint& pos, const wxSize& size); + + virtual void OnDraw(wxDC& dc); + void OnEvent(wxMouseEvent& event); + void WriteText(const wxString& text) { wxMutexGuiEnter(); wxLogMessage(text); wxMutexGuiLeave();} + OPJDecoThread *CreateDecoThread(void); + + wxBitmap m_image; + wxFileName m_fname; + + DECLARE_EVENT_TABLE() +}; + +/////////////////////////////////////////////////// +// the data associated to each tree leaf or node // +/////////////////////////////////////////////////// +class OPJMarkerData : public wxTreeItemData +{ + // public methods and variables + public: + + // class constructor + OPJMarkerData(const wxString& desc, const wxString& fname = wxT(""), wxFileOffset start = 0, wxFileOffset length = 0) : m_desc(desc), m_filestring(fname) { m_start = start; m_length = length; } + + void ShowInfo(wxTreeCtrl *tree); + const wxChar *GetDesc1() const { return m_desc.c_str(); } + const wxChar *GetDesc2() const { return m_filestring.c_str(); } + wxFileOffset m_start, m_length; + + // private methods and variables + private: + wxString m_desc; + wxString m_filestring; +}; + + +class OPJMarkerTree : public wxTreeCtrl +{ +public: + enum + { + TreeCtrlIcon_File, + TreeCtrlIcon_FileSelected, + TreeCtrlIcon_Folder, + TreeCtrlIcon_FolderSelected, + TreeCtrlIcon_FolderOpened + }; + + OPJMarkerTree() { }; + OPJMarkerTree(wxWindow *parent, wxFileName fname, wxString name, const wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style); + virtual ~OPJMarkerTree(){}; + OPJParseThread *CreateParseThread(wxTreeItemId parentid = 0x00); + void WriteText(const wxString& text) { wxMutexGuiEnter(); wxLogMessage(text); wxMutexGuiLeave(); } + + wxFileName m_fname; + wxTextCtrl *m_peektextCtrl; + + /*void OnBeginDrag(wxTreeEvent& event); + void OnBeginRDrag(wxTreeEvent& event); + void OnEndDrag(wxTreeEvent& event);*/ + /*void OnBeginLabelEdit(wxTreeEvent& event); + void OnEndLabelEdit(wxTreeEvent& event);*/ + /*void OnDeleteItem(wxTreeEvent& event);*/ + /*void OnContextMenu(wxContextMenuEvent& event);*/ + /*void OnItemMenu(wxTreeEvent& event);*/ + /*void OnGetInfo(wxTreeEvent& event); + void OnSetInfo(wxTreeEvent& event);*/ + /*void OnItemExpanded(wxTreeEvent& event);*/ + void OnItemExpanding(wxTreeEvent& event); + /*void OnItemCollapsed(wxTreeEvent& event); + void OnItemCollapsing(wxTreeEvent& event);*/ + void OnSelChanged(wxTreeEvent& event); + /*void OnSelChanging(wxTreeEvent& event);*/ + /*void OnTreeKeyDown(wxTreeEvent& event);*/ + /*void OnItemActivated(wxTreeEvent& event);*/ + /*void OnItemRClick(wxTreeEvent& event);*/ + /*void OnRMouseDown(wxMouseEvent& event); + void OnRMouseUp(wxMouseEvent& event); + void OnRMouseDClick(wxMouseEvent& event);*/ + /*void GetItemsRecursively(const wxTreeItemId& idParent, + wxTreeItemIdValue cookie = 0);*/ + + void CreateImageList(int size = 16); + void CreateButtonsImageList(int size = 11); + + /*void AddTestItemsToTree(size_t numChildren, size_t depth);*/ + /*void DoSortChildren(const wxTreeItemId& item, bool reverse = false) + { m_reverseSort = reverse; wxTreeCtrl::SortChildren(item); }*/ + /*void DoEnsureVisible() { if (m_lastItem.IsOk()) EnsureVisible(m_lastItem); }*/ + /*void DoToggleIcon(const wxTreeItemId& item);*/ + /*void ShowMenu(wxTreeItemId id, const wxPoint& pt);*/ + + int ImageSize(void) const { return m_imageSize; } + + void SetLastItem(wxTreeItemId id) { m_lastItem = id; } + +protected: + /*virtual int OnCompareItems(const wxTreeItemId& i1, const wxTreeItemId& i2);*/ + + // is this the test item which we use in several event handlers? + /*bool IsTestItem(const wxTreeItemId& item) + { + // the test item is the first child folder + return GetItemParent(item) == GetRootItem() && !GetPrevSibling(item); + }*/ + +private: + /*void AddItemsRecursively(const wxTreeItemId& idParent, + size_t nChildren, + size_t depth, + size_t folder);*/ + + void LogEvent(const wxChar *name, const wxTreeEvent& event); + + int m_imageSize; // current size of images + bool m_reverseSort; // flag for OnCompareItems + wxTreeItemId m_lastItem, // for OnEnsureVisible() + m_draggedItem; // item being dragged right now + + // NB: due to an ugly wxMSW hack you _must_ use DECLARE_DYNAMIC_CLASS() + // if you want your overloaded OnCompareItems() to be called. + // OTOH, if you don't want it you may omit the next line - this will + // make default (alphabetical) sorting much faster under wxMSW. + DECLARE_DYNAMIC_CLASS(OPJMarkerTree) + DECLARE_EVENT_TABLE() +}; + +// this hash map stores all the trees of currently opened images, with an integer key +WX_DECLARE_HASH_MAP(int, OPJMarkerTree*, wxIntegerHash, wxIntegerEqual, OPJMarkerTreeHash); + +// this hash map stores all the children of currently opened images, with an integer key +WX_DECLARE_HASH_MAP(int, OPJChildFrame*, wxIntegerHash, wxIntegerEqual, OPJChildFrameHash); + +// Define a new frame +class OPJFrame: public wxMDIParentFrame +{ + public: + + OPJFrame(wxWindow *parent, const wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, const long style); + + ~OPJFrame(void); + void OnSize(wxSizeEvent& event); + void OnAbout(wxCommandEvent& WXUNUSED(event)); + void OnFileOpen(wxCommandEvent& WXUNUSED(event)); + void OnQuit(wxCommandEvent& WXUNUSED(event)); + void OnToggleWindow(wxCommandEvent& WXUNUSED(event)); + void OnSashDrag(wxSashEvent& event); + void OpenFiles(wxArrayString paths, wxArrayString filenames); + void OnNotebook(wxNotebookEvent& event); + + OPJMarkerTreeHash m_treehash; + OPJChildFrameHash m_childhash; + wxSashLayoutWindow* markerTreeWindow; + wxSashLayoutWindow* loggingWindow; + void Resize(int number); + wxNotebook *m_bookCtrl; + wxNotebook *m_bookCtrlbottom; + wxTextCtrl *m_textCtrlbrowse; + + private: + void TogStyle(int id, long flag); + + void DoSort(bool reverse = false); + + wxPanel *m_panel; + wxTextCtrl *m_textCtrl; + + void DoSetBold(bool bold = true); + +protected: + wxSashLayoutWindow* m_topWindow; + wxSashLayoutWindow* m_leftWindow2; + +DECLARE_EVENT_TABLE() +}; + +class OPJChildFrame: public wxMDIChildFrame +{ + public: + OPJCanvas *m_canvas; + OPJChildFrame(OPJFrame *parent, wxFileName fname, int winnumber, const wxString& title, const wxPoint& pos, const wxSize& size, const long style); + ~OPJChildFrame(void); + void OnActivate(wxActivateEvent& event); + /*void OnQuit(wxCommandEvent& WXUNUSED(event));*/ + void OnClose(wxCloseEvent& event); + void OnGotFocus(wxFocusEvent& event); + /*void OnLostFocus(wxFocusEvent& event);*/ + OPJFrame *m_frame; + wxFileName m_fname; + int m_winnumber; + +DECLARE_EVENT_TABLE() +}; + +#define SASHTEST_QUIT wxID_EXIT +#define SASHTEST_NEW_WINDOW 2 +#define SASHTEST_REFRESH 3 +#define SASHTEST_CHILD_QUIT 4 +#define SASHTEST_ABOUT wxID_ABOUT +#define SASHTEST_TOGGLE_WINDOW 6 + +#define ID_WINDOW_TOP 100 +#define ID_WINDOW_LEFT1 101 +#define ID_WINDOW_LEFT2 102 +#define ID_WINDOW_BOTTOM 103 + +// menu and control ids +enum +{ + TreeTest_Quit = wxID_EXIT, + TreeTest_About = wxID_ABOUT, + TreeTest_TogButtons = wxID_HIGHEST, + TreeTest_TogTwist, + TreeTest_TogLines, + TreeTest_TogEdit, + TreeTest_TogHideRoot, + TreeTest_TogRootLines, + TreeTest_TogBorder, + TreeTest_TogFullHighlight, + TreeTest_SetFgColour, + TreeTest_SetBgColour, + TreeTest_ResetStyle, + TreeTest_Highlight, + TreeTest_Dump, + TreeTest_DumpSelected, + TreeTest_Count, + TreeTest_CountRec, + TreeTest_Sort, + TreeTest_SortRev, + TreeTest_SetBold, + TreeTest_ClearBold, + TreeTest_Rename, + TreeTest_Delete, + TreeTest_DeleteChildren, + TreeTest_DeleteAll, + TreeTest_Recreate, + TreeTest_ToggleImages, + TreeTest_ToggleButtons, + TreeTest_SetImageSize, + TreeTest_ToggleSel, + TreeTest_CollapseAndReset, + TreeTest_EnsureVisible, + TreeTest_AddItem, + TreeTest_InsertItem, + TreeTest_IncIndent, + TreeTest_DecIndent, + TreeTest_IncSpacing, + TreeTest_DecSpacing, + TreeTest_ToggleIcon, + TreeTest_Select, + TreeTest_Unselect, + TreeTest_SelectRoot, + TreeTest_Ctrl = 1000, + BOTTOM_NOTEBOOK_ID, + LEFT_NOTEBOOK_ID +}; + +class OPJDecoThread : public wxThread +{ +public: + OPJDecoThread(OPJCanvas *canvas); + + // thread execution starts here + virtual void *Entry(); + + // called when the thread exits - whether it terminates normally or is + // stopped with Delete() (but not when it is Kill()ed!) + virtual void OnExit(); + + // write something to the text control + void WriteText(const wxString& text); + +public: + unsigned m_count; + OPJCanvas *m_canvas; +}; + +class OPJParseThread : public wxThread +{ +public: + OPJParseThread(OPJMarkerTree *tree, wxTreeItemId parentid = 0x00); + + // thread execution starts here + virtual void *Entry(); + + // called when the thread exits - whether it terminates normally or is + // stopped with Delete() (but not when it is Kill()ed!) + virtual void OnExit(); + + // write something to the text control + void WriteText(const wxString& text); + void LoadFile(wxFileName fname); + void ParseJ2KFile(wxFile *m_file, wxFileOffset offset, wxFileOffset length, wxTreeItemId parentid); + void ParseJP2File(wxFile *fileid, wxFileOffset filepoint, wxFileOffset filelimit, wxTreeItemId parentid); + + unsigned m_count; + OPJMarkerTree *m_tree; + wxTreeItemId m_parentid; + +private: + int jpeg2000parse(wxFile *fileid, wxFileOffset filepoint, wxFileOffset filelimit, + wxTreeItemId parentid, int level, char *scansign, unsigned long int *scanpoint); + int box_handler_function(int boxtype, wxFile *fileid, wxFileOffset filepoint, wxFileOffset filelimit, + wxTreeItemId parentid, int level, char *scansign, unsigned long int *scanpoint); + +}; + +#endif //__OPJ_VIEWER_H__ diff --git a/OPJViewer/source/OPJViewer.ico b/OPJViewer/source/OPJViewer.ico new file mode 100644 index 0000000000000000000000000000000000000000..931d5e021191a3fd17610e14bec8405796abfb57 GIT binary patch literal 1078 zcmcIjy-ou$40Z|<%7QLq7U)F#6orkAmtg1vbVa(`x*)iSDNFk*hlJE3Rn03@q5~t{ zm?+=pP^p#5KqY+V*p5FtKXycnw4~iGg!JALxqvK+Yw>5)hmb8YYy*vK(PkqX%T zRKW>PRb_z@sx(alNyl1$S+A*q@o|d7zmu=U*EU8M#q*5LLB>K%_1=8kaY-~##k#u4j_eDE{ZNy=jKO#9-!Bqkov9D}%;ll|%u$NXd zn^x1+aQXT%Tu!C)GHW{Xn^s@JX*=YrT-=qHlU_M~9F^nos7&MeIrtjfPia0#>0yxG z&Ti9Z?_?*ES=i?|vG)3=&zoP5Q=!M02=(wj=Y5m(ULmysA%o?XP!0gRR+4pB yH0$f&BZBQpNj8{d>4fFdV66}}rTpIT<|bP_g#IM*jAwWc9+kU1gT25!W4{3rvE}0c literal 0 HcmV?d00001 diff --git a/OPJViewer/source/OPJViewer.rc b/OPJViewer/source/OPJViewer.rc new file mode 100644 index 00000000..56e5b698 --- /dev/null +++ b/OPJViewer/source/OPJViewer.rc @@ -0,0 +1,2 @@ +OPJViewer16 ICON OPJViewer.ico +#include "wx/msw/wx.rc" \ No newline at end of file diff --git a/OPJViewer/source/OPJViewer16.xpm b/OPJViewer/source/OPJViewer16.xpm new file mode 100644 index 00000000..27e522b1 --- /dev/null +++ b/OPJViewer/source/OPJViewer16.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static char *OPJViewer16[] = { +/* columns rows colors chars-per-pixel */ +"16 16 4 1", +" c black", +". c #800000", +"X c red", +"o c None", +/* pixels */ +"oooooooooooooooo", +"ooo.XXXXoooooooo", +"ooXXoo .Xooooooo", +"o..oooo .ooooooo", +"oX.oooo ooooooo", +"oX.oooo .ooooooo", +"oXXoooo .ooooooo", +"o.XXoo .oooooooo", +"oo.XXXXooooooooo", +"ooooooooo.Xo .oo", +"ooooooooo X. ooo", +"oooooooooo...ooo", +"oooooooooo XXooo", +"oooooooooo .Xooo", +"oooooooooooooooo", +"oooooooooooooooo" +}; diff --git a/OPJViewer/source/icon1.xpm b/OPJViewer/source/icon1.xpm new file mode 100644 index 00000000..fbc605b5 --- /dev/null +++ b/OPJViewer/source/icon1.xpm @@ -0,0 +1,79 @@ +/* XPM */ +static char *icon1_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 41 1", +"> c #97C4E7", +"# c #4381AA", +"d c #FFFFFF", +"< c #71B2DE", +"+ c #538BB1", +"& c #D1E5F5", +"q c #63B3DE", +"6 c #F1F4F7", +"* c #CAE1F3", +"y c #7AC4E5", +"= c #C3DDF1", +"X c #74A1BD", +"- c #BCD9EF", +"5 c #619BC4", +"3 c #E6EAF1", +"2 c #4B8EBF", +"o c #6B97B6", +". c #4B82A8", +" c None", +"w c #54A6D8", +"1 c #71A8D1", +", c #85BBE2", +"t c #EFF6FC", +"7 c #DEEDF8", +"@ c #4388B4", +"a c #F7FBFD", +"$ c #D7E0E9", +"r c #FAFCFE", +"4 c #DAEAF7", +"e c #E9F3FA", +"0 c #76BAE2", +"% c #7FA6C0", +"s c #FDFDFE", +"O c #5896BE", +"p c #B6D5EE", +"8 c #87ABC3", +": c #A5CCEA", +"9 c #E5F0F9", +"; c #AFD1EC", +"i c #F4F9FD", +"u c #8FB0C3", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" .XXXooOO++@#$ ", +" %&*=-;:>>,<123 ", +" %4&*=-;:>>,1>56 ", +" %74&*=-;:>>1*>56 ", +" 89700qqqqwq1e*>X ", +" 8e974&*=-;:1re*>8 ", +" 8te974&*=-;11111# ", +" 8tty000qqqqqww>,+ ", +" uitte974&*=-p:>>+ ", +" uaitte974&*=-p:>O ", +" uaayyyy000qqqqp:O ", +" uraaitte974&*=-po ", +" urraaitte974&*=-o ", +" usryyyyyyy000q*=X ", +" ussrraaitte974&*X ", +" udssrraaitte974&X ", +" uddyyyyyyyyyy074% ", +" udddssrraaitte97% ", +" uddddssrraaitte9% ", +" udddddssrraaitte8 ", +" uddddddssrraaitt8 ", +" uuuuuuuuuuuuuu88u ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/OPJViewer/source/icon2.xpm b/OPJViewer/source/icon2.xpm new file mode 100644 index 00000000..7ae8c92c --- /dev/null +++ b/OPJViewer/source/icon2.xpm @@ -0,0 +1,53 @@ +/* XPM */ +static char *icon2_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 15 1", +". c Black", +"O c #97C4E7", +"$ c #63B3DE", +"@ c #CAE1F3", +"; c #7AC4E5", +"* c #74A1BD", +"+ c #619BC4", +"o c #4B8EBF", +" c None", +"% c #54A6D8", +"= c #FAFCFE", +"& c #E9F3FA", +"# c #76BAE2", +"X c #C00000", +"- c #87ABC3", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ............. ", +" .XXXXXXXXXX.o. ", +" .XXXXXXXXXX.O+. ", +" .XXXXXXXXXX.@O+. ", +" .XX##$$$$%$.&@O* ", +" .XXXXXXXXXX.=&@O- ", +" .XXXXXXXXXX...... ", +" .XX;###$$$$$%%XX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" .XX;;;;###$$$$XX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" .XX;;;;;;;###$XX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" .XX;;;;;;;;;;#XX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" ................. ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/OPJViewer/source/icon3.xpm b/OPJViewer/source/icon3.xpm new file mode 100644 index 00000000..722de6b1 --- /dev/null +++ b/OPJViewer/source/icon3.xpm @@ -0,0 +1,79 @@ +/* XPM */ +static char *icon3_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 41 1", +"6 c #EDF2FB", +"- c #AAC1E8", +": c #B9CDED", +"X c #295193", +", c #C6D6F0", +"a c #4A7CCE", +"u c #779DDB", +"y c #7FA2DD", +"$ c #3263B4", +"5 c #EAF0FA", +". c #2D59A3", +"o c #6E96D8", +"* c #356AC1", +"r c #F7F9FD", +"> c #BED0EE", +"3 c #E1E9F7", +"7 c #F0F5FC", +"< c #CBD9F1", +"2 c #DAE5F6", +"# c #3161B1", +" c None", +"0 c #FDFEFF", +"= c #9FB9E5", +"e c #AEC5EA", +"t c #89A9DF", +"q c #98B5E4", +"p c #5584D1", +"d c #3A70CA", +"@ c #305FAC", +"i c #5D89D3", +"1 c #D2DFF4", +"% c #3366B9", +"9 c #FAFCFE", +"8 c #F5F8FD", +"s c #4075CC", +"O c #638ED5", +"w c #90AFE2", +"& c #3467BC", +"+ c #2F5DA9", +"; c #B3C8EB", +"4 c #E5EDF9", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ", +" ......X ", +" .oooooO+ ", +" .ooooooo. ", +" .+@@@##$%%&&&&&****. ", +" .=-;:>,<12345678900. ", +" .q=-;:>,<1234567890. ", +" .wq=-e:>,<12345678r. ", +" .twq=-e:>,<12345678. ", +" .ytwq=-e:>,<1234567. ", +" .uytwq=-e:>,<123456. ", +" .ouytwq=-e:>,<12345. ", +" .Oouytwq=-e;>,<1234. ", +" .iOouytwq=-e;>,<123. ", +" .piOouytwq=-e;>,<12. ", +" .apiOouytwq=-e;>,<1. ", +" .sapiOouytwq=-e;>,<. ", +" .dsapiOouytwq=-e;>,. ", +" ...................# ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/OPJViewer/source/icon4.xpm b/OPJViewer/source/icon4.xpm new file mode 100644 index 00000000..a18e1a70 --- /dev/null +++ b/OPJViewer/source/icon4.xpm @@ -0,0 +1,43 @@ +/* XPM */ +static char *icon4_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 5 1", +". c Black", +"o c #8399B4", +"X c #8DA0B9", +" c None", +"O c #800000", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ", +" ....... ", +" .XXXXXo. ", +" .XXXXXXX. ", +" .................... ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .................... ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/OPJViewer/source/icon5.xpm b/OPJViewer/source/icon5.xpm new file mode 100644 index 00000000..9f63c310 --- /dev/null +++ b/OPJViewer/source/icon5.xpm @@ -0,0 +1,79 @@ +/* XPM */ +static char *icon5_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 41 1", +"0 c #AAC1E8", +"q c #B9CDED", +"X c #295193", +"e c #C6D6F0", +"a c #4A7CCE", +"& c #779DDB", +"* c #7FA2DD", +"2 c #EAF0FA", +"@ c #2D59A3", +"o c #6E96D8", +"y c #356AC1", +"d c #214279", +"w c #BED0EE", +"= c #85A7DF", +"< c #E1E9F7", +"3 c #F0F5FC", +"s c #CBD9F1", +", c #DAE5F6", +"7 c #3161B1", +" c None", +". c #274D8B", +"6 c #FDFEFF", +"i c #E7EEF9", +"9 c #9FB9E5", +"- c #89A9DF", +"8 c #98B5E4", +"$ c #5584D1", +"+ c #3569BF", +"% c #305FAC", +"O c #5D89D3", +"> c #D2DFF4", +"p c #3366B9", +"5 c #FAFCFE", +"4 c #F5F8FD", +"t c #4075CC", +"u c #638ED5", +"r c #CEDCF2", +"; c #90AFE2", +"# c #2F5DA9", +": c #B3C8EB", +"1 c #E5EDF9", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ......X ", +" XoooooO. ", +" Xoooooo+. ", +" Xooooooo@XXXXXXXXXX# ", +" Xoooooooooooooooooo# ", +" Xoooooooooooooooooo# ", +" Xoo$################### ", +" Xoo%O&*=-;:>,<123445667 ", +" XooX890:qwer>,<123445q# ", +" Xoty;890:qwer>,<12344# ", +" Xo%u-;890:qwer>,,,,<# ", +" XX$Ouo&*-;890:qwer>s# ", +" d%a$Ouo&*-;890:qwer# ", +" d+ta$Ouo&*-;890:qwe# ", +" d..................# ", +" ", +" ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/OPJViewer/source/imagj2k.cpp b/OPJViewer/source/imagj2k.cpp new file mode 100644 index 00000000..b58c7a51 --- /dev/null +++ b/OPJViewer/source/imagj2k.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: imagj2k.cpp +// Purpose: wxImage JPEG 2000 codestream handler +// Author: Giuseppe Baruffa - based on imagjpeg.cpp, Vaclav Slavik +// RCS-ID: $Id: imagj2k.cpp,v 0.00 2007/02/08 23:59:00 MW Exp $ +// Copyright: (c) Giuseppe Baruffa +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_LIBOPENJPEG + +#include "imagj2k.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/bitmap.h" + #include "wx/module.h" +#endif + + +#include "libopenjpeg/openjpeg.h" + + +#include "wx/filefn.h" +#include "wx/wfstream.h" + +// ---------------------------------------------------------------------------- +// types +// ---------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// wxJ2KHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxJ2KHandler,wxImageHandler) + +#if wxUSE_STREAMS + +//------------- JPEG 2000 Data Source Manager + +#define J2K_CFMT 0 +#define JP2_CFMT 1 +#define JPT_CFMT 2 +#define MJ2_CFMT 3 +#define PXM_DFMT 0 +#define PGX_DFMT 1 +#define BMP_DFMT 2 +#define YUV_DFMT 3 + +#define MAX_MESSAGE_LEN 200 + +/* sample error callback expecting a FILE* client object */ +void j2k_error_callback(const char *msg, void *client_data) { + char m_msg[MAX_MESSAGE_LEN]; + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; + sprintf(m_msg, "[ERROR] %.*s", message_len, msg); + wxMutexGuiEnter(); + wxLogMessage(m_msg); + wxMutexGuiLeave(); +} +/* sample warning callback expecting a FILE* client object */ +void j2k_warning_callback(const char *msg, void *client_data) { + char m_msg[MAX_MESSAGE_LEN]; + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; + sprintf(m_msg, "[WARNING] %.*s", message_len, msg); + wxMutexGuiEnter(); + wxLogMessage(m_msg); + wxMutexGuiLeave(); +} +/* sample debug callback expecting no client object */ +void j2k_info_callback(const char *msg, void *client_data) { + char m_msg[MAX_MESSAGE_LEN]; + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; + sprintf(m_msg, "[INFO] %.*s", message_len, msg); + wxMutexGuiEnter(); + wxLogMessage(m_msg); + wxMutexGuiLeave(); +} + +// load the j2k codestream +bool wxJ2KHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int index) +{ + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *opjimage = NULL; + FILE *fsrc = NULL; + unsigned char *src = NULL; + unsigned char *ptr; + int file_length; + int shiftbpp; + + // destroy the image + image->Destroy(); + + /* handle to a decompressor */ + opj_dinfo_t* dinfo = NULL; + opj_cio_t *cio = NULL; + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = j2k_error_callback; + event_mgr.warning_handler = j2k_warning_callback; + event_mgr.info_handler = j2k_info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + /* prepare parameters */ + parameters.decod_format = J2K_CFMT; + parameters.cod_format = BMP_DFMT; + + /* JPWL only */ +#ifdef USE_JPWL + parameters.jpwl_exp_comps = 3; + parameters.jpwl_max_tiles = 100; + parameters.jpwl_correct = true; +#endif /* USE_JPWL */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_J2K); + + /* find length of the stream */ + stream.SeekI(0, wxFromEnd); + file_length = (int) stream.TellI(); + + /* get data */ + stream.SeekI(0, wxFromStart); + src = (unsigned char *) malloc(file_length); + stream.Read(src, file_length); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + opjimage = opj_decode(dinfo, cio); + if (!opjimage) { + wxMutexGuiEnter(); + wxLogError("J2K: failed to decode image!"); + wxMutexGuiLeave(); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + opj_image_destroy(opjimage); + free(src); + return false; + } + + // check image components + if ((opjimage->numcomps != 1) && (opjimage->numcomps != 3)) { + wxMutexGuiEnter(); + wxLogError("J2K: weird number of components"); + wxMutexGuiLeave(); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + free(src); + return false; + } + + // check image depth (only on the first one, for now) + shiftbpp = opjimage->comps[0].prec - 8; + + // prepare image size + image->Create(opjimage->comps[0].w, opjimage->comps[0].h, true ); + + // access image raw data + image->SetMask( false ); + ptr = image->GetData(); + + // RGB color picture + if (opjimage->numcomps == 3) { + int row, col; + int *r = opjimage->comps[0].data; + int *g = opjimage->comps[1].data; + int *b = opjimage->comps[2].data; + if (shiftbpp > 0) { + for (row = 0; row < opjimage->comps[0].h; row++) { + for (col = 0; col < opjimage->comps[0].w; col++) { + + *(ptr++) = (*(r++)) >> shiftbpp; + *(ptr++) = (*(g++)) >> shiftbpp; + *(ptr++) = (*(b++)) >> shiftbpp; + + } + } + } else { + for (row = 0; row < opjimage->comps[0].h; row++) { + for (col = 0; col < opjimage->comps[0].w; col++) { + + *(ptr++) = *(r++); + *(ptr++) = *(g++); + *(ptr++) = *(b++); + + } + } + } + } + + // B/W picture + if (opjimage->numcomps == 1) { + int row, col; + int *y = opjimage->comps[0].data; + if (shiftbpp > 0) { + for (row = 0; row < opjimage->comps[0].h; row++) { + for (col = 0; col < opjimage->comps[0].w; col++) { + + *(ptr++) = (*(y)) >> shiftbpp; + *(ptr++) = (*(y)) >> shiftbpp; + *(ptr++) = (*(y++)) >> shiftbpp; + + } + } + } else { + for (row = 0; row < opjimage->comps[0].h; row++) { + for (col = 0; col < opjimage->comps[0].w; col++) { + + *(ptr++) = *(y); + *(ptr++) = *(y); + *(ptr++) = *(y++); + + } + } + } + } + + wxMutexGuiEnter(); + wxLogMessage(wxT("J2K: image loaded.")); + wxMutexGuiLeave(); + + /* close openjpeg structs */ + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + opj_image_destroy(opjimage); + free(src); + + if (!image->Ok()) + return false; + else + return true; + +} + +// save the j2k codestream +bool wxJ2KHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) +{ + wxLogError(wxT("J2K: Couldn't save image -> not implemented.")); + return false; +} + +#ifdef __VISUALC__ + #pragma warning(default:4611) +#endif /* VC++ */ + +// recognize the 0xFF4F JPEG 2000 SOC marker +bool wxJ2KHandler::DoCanRead( wxInputStream& stream ) +{ + unsigned char hdr[2]; + + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + return hdr[0] == 0xFF && hdr[1] == 0x4F; +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_LIBOPENJPEG diff --git a/OPJViewer/source/imagj2k.h b/OPJViewer/source/imagj2k.h new file mode 100644 index 00000000..c98fdd2e --- /dev/null +++ b/OPJViewer/source/imagj2k.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: imagj2k.h +// Purpose: wxImage JPEG 2000 raw codestream handler +// Author: G. Baruffa - based on imagjpeg.h, Vaclav Slavik +// RCS-ID: $Id: imagj2k.h,v 0.0 2007/02/08 23:45:00 VZ Exp $ +// Copyright: (c) Giuseppe Baruffa +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_IMAGJ2K_H_ +#define _WX_IMAGJ2K_H_ + +#include "wx/defs.h" + +//----------------------------------------------------------------------------- +// wxJ2KHandler +//----------------------------------------------------------------------------- + +#if wxUSE_LIBOPENJPEG + +#include "wx/image.h" + +#define wxBITMAP_TYPE_J2K 47 + +class WXDLLEXPORT wxJ2KHandler: public wxImageHandler +{ +public: + inline wxJ2KHandler() + { + m_name = wxT("JPEG 2000 codestream file"); + m_extension = wxT("j2k"); + m_type = wxBITMAP_TYPE_J2K; + m_mime = wxT("image/j2k"); + } + +#if wxUSE_STREAMS + virtual bool LoadFile( wxImage *image, wxInputStream& stream, bool verbose=true, int index=-1 ); + virtual bool SaveFile( wxImage *image, wxOutputStream& stream, bool verbose=true ); +protected: + virtual bool DoCanRead( wxInputStream& stream ); +#endif + +private: + DECLARE_DYNAMIC_CLASS(wxJ2KHandler) +}; + +#endif // wxUSE_LIBOPENJPEG + +#endif // _WX_IMAGJ2K_H_ + diff --git a/OPJViewer/source/imagjp2.cpp b/OPJViewer/source/imagjp2.cpp new file mode 100644 index 00000000..4b7437f8 --- /dev/null +++ b/OPJViewer/source/imagjp2.cpp @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: imagjp2.cpp +// Purpose: wxImage JPEG 2000 file format handler +// Author: Giuseppe Baruffa - based on imagjpeg.cpp, Vaclav Slavik +// RCS-ID: $Id: imagjp2.cpp,v 0.00 2007/02/08 23:59:00 MW Exp $ +// Copyright: (c) Giuseppe Baruffa +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_LIBOPENJPEG + +#include "imagjp2.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/bitmap.h" + #include "wx/module.h" +#endif + + +#include "libopenjpeg/openjpeg.h" + + +#include "wx/filefn.h" +#include "wx/wfstream.h" + +// ---------------------------------------------------------------------------- +// types +// ---------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// wxJP2Handler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxJP2Handler,wxImageHandler) + +#if wxUSE_STREAMS + +//------------- JPEG 2000 Data Source Manager + +#define J2K_CFMT 0 +#define JP2_CFMT 1 +#define JPT_CFMT 2 +#define MJ2_CFMT 3 +#define PXM_DFMT 0 +#define PGX_DFMT 1 +#define BMP_DFMT 2 +#define YUV_DFMT 3 + +#define MAX_MESSAGE_LEN 200 + +/* sample error callback expecting a FILE* client object */ +void jp2_error_callback(const char *msg, void *client_data) { + char m_msg[MAX_MESSAGE_LEN]; + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; + sprintf(m_msg, "[ERROR] %.*s", message_len, msg); + wxMutexGuiEnter(); + wxLogMessage(m_msg); + wxMutexGuiLeave(); +} +/* sample warning callback expecting a FILE* client object */ +void jp2_warning_callback(const char *msg, void *client_data) { + char m_msg[MAX_MESSAGE_LEN]; + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; + sprintf(m_msg, "[WARNING] %.*s", message_len, msg); + wxMutexGuiEnter(); + wxLogMessage(m_msg); + wxMutexGuiLeave(); +} +/* sample debug callback expecting no client object */ +void jp2_info_callback(const char *msg, void *client_data) { + char m_msg[MAX_MESSAGE_LEN]; + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; + sprintf(m_msg, "[INFO] %.*s", message_len, msg); + wxMutexGuiEnter(); + wxLogMessage(m_msg); + wxMutexGuiLeave(); +} + +// load the jp2 file format +bool wxJP2Handler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int index) +{ + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *opjimage = NULL; + FILE *fsrc = NULL; + unsigned char *src = NULL; + unsigned char *ptr; + int file_length; + + // destroy the image + image->Destroy(); + + /* handle to a decompressor */ + opj_dinfo_t* dinfo = NULL; + opj_cio_t *cio = NULL; + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = jp2_error_callback; + event_mgr.warning_handler = jp2_warning_callback; + event_mgr.info_handler = jp2_info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + /* prepare parameters */ + parameters.decod_format = JP2_CFMT; + parameters.cod_format = BMP_DFMT; + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_JP2); + + /* find length of the stream */ + stream.SeekI(0, wxFromEnd); + file_length = (int) stream.TellI(); + + /* get data */ + stream.SeekI(0, wxFromStart); + src = (unsigned char *) malloc(file_length); + stream.Read(src, file_length); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + opjimage = opj_decode(dinfo, cio); + if (!opjimage) { + wxMutexGuiEnter(); + wxLogError("JP2: failed to decode image!"); + wxMutexGuiLeave(); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + free(src); + return false; + } + + // check image size + if ((opjimage->numcomps != 1) && (opjimage->numcomps != 3)) { + wxMutexGuiEnter(); + wxLogError("JP2: weird number of components"); + wxMutexGuiLeave(); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + free(src); + return false; + } + + // prepare image size + image->Create(opjimage->comps[0].w, opjimage->comps[0].h, true ); + + // access image raw data + image->SetMask( false ); + ptr = image->GetData(); + + // RGB color picture + if (opjimage->numcomps == 3) { + int row, col; + int *r = opjimage->comps[0].data; + int *g = opjimage->comps[1].data; + int *b = opjimage->comps[2].data; + for (row = 0; row < opjimage->comps[0].h; row++) { + for (col = 0; col < opjimage->comps[0].w; col++) { + + *(ptr++) = *(r++); + *(ptr++) = *(g++); + *(ptr++) = *(b++); + + } + } + } + + // B/W picture + if (opjimage->numcomps == 1) { + int row, col; + int *y = opjimage->comps[0].data; + for (row = 0; row < opjimage->comps[0].h; row++) { + for (col = 0; col < opjimage->comps[0].w; col++) { + + *(ptr++) = *(y); + *(ptr++) = *(y); + *(ptr++) = *(y++); + + } + } + } + + wxMutexGuiEnter(); + wxLogMessage(wxT("JP2: image loaded.")); + wxMutexGuiLeave(); + + /* close openjpeg structs */ + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + opj_image_destroy(opjimage); + free(src); + + if (!image->Ok()) + return false; + else + return true; + +} + +// save the jp2 file format +bool wxJP2Handler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) +{ + wxLogError(wxT("JP2: Couldn't save image -> not implemented.")); + return false; +} + +#ifdef __VISUALC__ + #pragma warning(default:4611) +#endif /* VC++ */ + +// recognize the JPEG 2000 starting box +bool wxJP2Handler::DoCanRead( wxInputStream& stream ) +{ + unsigned char hdr[23]; + + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + return (hdr[0] == 0x00 && + hdr[1] == 0x00 && + hdr[2] == 0x00 && + hdr[3] == 0x0C && + hdr[4] == 0x6A && + hdr[5] == 0x50 && + hdr[6] == 0x20 && + hdr[7] == 0x20 && + hdr[20] == 0x6A && + hdr[21] == 0x70 && + hdr[22] == 0x32); +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_LIBOPENJPEG diff --git a/OPJViewer/source/imagjp2.h b/OPJViewer/source/imagjp2.h new file mode 100644 index 00000000..1ebad878 --- /dev/null +++ b/OPJViewer/source/imagjp2.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: imagjp2.h +// Purpose: wxImage JPEG 2000 file format handler +// Author: G. Baruffa - based on imagjpeg.h, Vaclav Slavik +// RCS-ID: $Id: imagjp2.h,v 0.0 2007/02/08 23:45:00 VZ Exp $ +// Copyright: (c) Giuseppe Baruffa +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_IMAGJP2_H_ +#define _WX_IMAGJP2_H_ + +#include "wx/defs.h" + +//----------------------------------------------------------------------------- +// wxJP2Handler +//----------------------------------------------------------------------------- + +#if wxUSE_LIBOPENJPEG + +#include "wx/image.h" + +#define wxBITMAP_TYPE_JP2 48 + +class WXDLLEXPORT wxJP2Handler: public wxImageHandler +{ +public: + inline wxJP2Handler() + { + m_name = wxT("JPEG 2000 file format"); + m_extension = wxT("jp2"); + m_type = wxBITMAP_TYPE_JP2; + m_mime = wxT("image/jp2"); + } + +#if wxUSE_STREAMS + virtual bool LoadFile( wxImage *image, wxInputStream& stream, bool verbose=true, int index=-1 ); + virtual bool SaveFile( wxImage *image, wxOutputStream& stream, bool verbose=true ); +protected: + virtual bool DoCanRead( wxInputStream& stream ); +#endif + +private: + DECLARE_DYNAMIC_CLASS(wxJP2Handler) +}; + +#endif // wxUSE_LIBOPENJPEG + +#endif // _WX_IMAGJP2_H_ + diff --git a/OPJViewer/source/imagmj2.cpp b/OPJViewer/source/imagmj2.cpp new file mode 100644 index 00000000..351621ea --- /dev/null +++ b/OPJViewer/source/imagmj2.cpp @@ -0,0 +1,785 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: imagmj2.cpp +// Purpose: wxImage Motion JPEG 2000 file format handler +// Author: Giuseppe Baruffa - based on imagjpeg.cpp, Vaclav Slavik +// RCS-ID: $Id: imagmj2.cpp,v 0.00 2007/02/18 23:59:00 MW Exp $ +// Copyright: (c) Giuseppe Baruffa +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_LIBOPENJPEG + +#include "imagmj2.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/bitmap.h" + #include "wx/module.h" +#endif + + +#include "libopenjpeg/openjpeg.h" + + +#include "wx/filefn.h" +#include "wx/wfstream.h" + +// ---------------------------------------------------------------------------- +// types +// ---------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// wxMJ2Handler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxMJ2Handler,wxImageHandler) + +#if wxUSE_STREAMS + +//------------- JPEG 2000 Data Source Manager + +#define J2K_CFMT 0 +#define JP2_CFMT 1 +#define JPT_CFMT 2 +#define MJ2_CFMT 3 +#define PXM_DFMT 0 +#define PGX_DFMT 1 +#define BMP_DFMT 2 +#define YUV_DFMT 3 + +#define MAX_MESSAGE_LEN 200 + +/* sample error callback expecting a FILE* client object */ +void mj2_error_callback(const char *msg, void *client_data) { + char m_msg[MAX_MESSAGE_LEN]; + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; + sprintf(m_msg, "[ERROR] %.*s", message_len, msg); + wxMutexGuiEnter(); + wxLogMessage(m_msg); + wxMutexGuiLeave(); +} +/* sample warning callback expecting a FILE* client object */ +void mj2_warning_callback(const char *msg, void *client_data) { + char m_msg[MAX_MESSAGE_LEN]; + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; + sprintf(m_msg, "[WARNING] %.*s", message_len, msg); + wxMutexGuiEnter(); + wxLogMessage(m_msg); + wxMutexGuiLeave(); +} +/* sample debug callback expecting no client object */ +void mj2_info_callback(const char *msg, void *client_data) { + char m_msg[MAX_MESSAGE_LEN]; + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; + sprintf(m_msg, "[INFO] %.*s", message_len, msg); + wxMutexGuiEnter(); + wxLogMessage(m_msg); + wxMutexGuiLeave(); +} + +/* macro functions */ +/* From little endian to big endian, 2 and 4 bytes */ +#define BYTE_SWAP2(X) ((X & 0x00FF) << 8) | ((X & 0xFF00) >> 8) +#define BYTE_SWAP4(X) ((X & 0x000000FF) << 24) | ((X & 0x0000FF00) << 8) | ((X & 0x00FF0000) >> 8) | ((X & 0xFF000000) >> 24) +#define BYTE_SWAP8(X) ((X & 0x00000000000000FF) << 56) | ((X & 0x000000000000FF00) << 40) | \ + ((X & 0x0000000000FF0000) << 24) | ((X & 0x00000000FF000000) << 8) | \ + ((X & 0x000000FF00000000) >> 8) | ((X & 0x0000FF0000000000) >> 24) | \ + ((X & 0x00FF000000000000) >> 40) | ((X & 0xFF00000000000000) >> 56) + +/* From codestream to int values */ +#define STREAM_TO_UINT32(C, P) (((unsigned long int) (C)[(P) + 0] << 24) + \ + ((unsigned long int) (C)[(P) + 1] << 16) + \ + ((unsigned long int) (C)[(P) + 2] << 8) + \ + ((unsigned long int) (C)[(P) + 3] << 0)) + +#define STREAM_TO_UINT16(C, P) (((unsigned long int) (C)[(P) + 0] << 8) + \ + ((unsigned long int) (C)[(P) + 1] << 0)) + +/* defines */ +#define SHORT_DESCR_LEN 32 +#define LONG_DESCR_LEN 256 + +/* enumeration for file formats */ +#define J2FILENUM 4 +typedef enum { + + JP2_FILE, + J2K_FILE, + MJ2_FILE, + UNK_FILE + +} my_j2filetype; + +/* enumeration for the box types */ +#define J2BOXNUM 23 +typedef enum { + + FILE_BOX, + JP_BOX, + FTYP_BOX, + JP2H_BOX, + IHDR_BOX, + COLR_BOX, + JP2C_BOX, + JP2I_BOX, + XML_BOX, + UUID_BOX, + UINF_BOX, + MOOV_BOX, + MVHD_BOX, + TRAK_BOX, + TKHD_BOX, + MDIA_BOX, + MINF_BOX, + STBL_BOX, + STSD_BOX, + MJP2_BOX, + MDAT_BOX, + ANY_BOX, + UNK_BOX + +} my_j2boxtype; + +/* jp2 family box signatures */ +#define FILE_SIGN "" +#define JP_SIGN "jP\040\040" +#define FTYP_SIGN "ftyp" +#define JP2H_SIGN "jp2h" +#define IHDR_SIGN "ihdr" +#define COLR_SIGN "colr" +#define JP2C_SIGN "jp2c" +#define JP2I_SIGN "jp2i" +#define XML_SIGN "xml\040" +#define UUID_SIGN "uuid" +#define UINF_SIGN "uinf" +#define MOOV_SIGN "moov" +#define MVHD_SIGN "mvhd" +#define TRAK_SIGN "trak" +#define TKHD_SIGN "tkhd" +#define MDIA_SIGN "mdia" +#define MINF_SIGN "minf" +#define STBL_SIGN "stbl" +#define STSD_SIGN "stsd" +#define MJP2_SIGN "mjp2" +#define MDAT_SIGN "mdat" +#define ANY_SIGN "" +#define UNK_SIGN "" + +/* the box structure itself */ +struct my_boxdef { + + char value[5]; /* hexadecimal value/string*/ + char name[SHORT_DESCR_LEN]; /* short description */ + char descr[LONG_DESCR_LEN]; /* long description */ + int sbox; /* is it a superbox? */ + int req[J2FILENUM]; /* mandatory box */ + my_j2boxtype ins; /* contained in box... */ + +}; + +/* the possible boxes */ +struct my_boxdef j2box[] = +{ +/* sign */ {FILE_SIGN, +/* short */ "placeholder for nothing", +/* long */ "Nothing to say", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {JP_SIGN, +/* short */ "JPEG 2000 Signature box", +/* long */ "This box uniquely identifies the file as being part of the JPEG 2000 family of files", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {FTYP_SIGN, +/* short */ "File Type box", +/* long */ "This box specifies file type, version and compatibility information, including specifying if this file " + "is a conforming JP2 file or if it can be read by a conforming JP2 reader", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {JP2H_SIGN, +/* short */ "JP2 Header box", +/* long */ "This box contains a series of boxes that contain header-type information about the file", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {IHDR_SIGN, +/* short */ "Image Header box", +/* long */ "This box specifies the size of the image and other related fields", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ JP2H_BOX}, + +/* sign */ {COLR_SIGN, +/* short */ "Colour Specification box", +/* long */ "This box specifies the colourspace of the image", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ JP2H_BOX}, + +/* sign */ {JP2C_SIGN, +/* short */ "Contiguous Codestream box", +/* long */ "This box contains the codestream as defined by Annex A", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {JP2I_SIGN, +/* short */ "Intellectual Property box", +/* long */ "This box contains intellectual property information about the image", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {XML_SIGN, +/* short */ "XML box", +/* long */ "This box provides a tool by which vendors can add XML formatted information to a JP2 file", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {UUID_SIGN, +/* short */ "UUID box", +/* long */ "This box provides a tool by which vendors can add additional information to a file " + "without risking conflict with other vendors", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {UINF_SIGN, +/* short */ "UUID Info box", +/* long */ "This box provides a tool by which a vendor may provide access to additional information associated with a UUID", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {MOOV_SIGN, +/* short */ "Movie box", +/* long */ "This box contains the media data. In video tracks, this box would contain JPEG2000 video frames", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {MVHD_SIGN, +/* short */ "Movie Header box", +/* long */ "This box defines overall information which is media-independent, and relevant to the entire presentation " + "considered as a whole", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MOOV_BOX}, + +/* sign */ {TRAK_SIGN, +/* short */ "Track box", +/* long */ "This is a container box for a single track of a presentation. A presentation may consist of one or more tracks", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ MOOV_BOX}, + +/* sign */ {TKHD_SIGN, +/* short */ "Track Header box", +/* long */ "This box specifies the characteristics of a single track. Exactly one Track Header Box is contained in a track", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ TRAK_BOX}, + +/* sign */ {MDIA_SIGN, +/* short */ "Media box", +/* long */ "The media declaration container contains all the objects which declare information about the media data " + "within a track", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ TRAK_BOX}, + +/* sign */ {MINF_SIGN, +/* short */ "Media Information box", +/* long */ "This box contains all the objects which declare characteristic information of the media in the track", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ MDIA_BOX}, + +/* sign */ {STBL_SIGN, +/* short */ "Sample Table box", +/* long */ "The sample table contains all the time and data indexing of the media samples in a track", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {STSD_SIGN, +/* short */ "Sample Description box", +/* long */ "The sample description table gives detailed information about the coding type used, and any initialization " + "information needed for that coding", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {MJP2_SIGN, +/* short */ "MJP2 Sample Description box", +/* long */ "The MJP2 sample description table gives detailed information about the coding type used, and any initialization " + "information needed for that coding", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {MDAT_SIGN, +/* short */ "Media Data box", +/* long */ "The meta-data for a presentation is stored in the single Movie Box which occurs at the top-level of a file", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {ANY_SIGN, +/* short */ "Any box", +/* long */ "All the existing boxes", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {UNK_SIGN, +/* short */ "Unknown Type box", +/* long */ "The signature is not recognised to be that of an existing box", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ ANY_BOX} + +}; + +/* declaration */ +int +my_box_handler_function(my_j2boxtype boxtype, wxInputStream& stream, unsigned long int filepoint, unsigned long int filelimit, int level, + char *scansign, unsigned long int *scanpoint); + +/* internal mini-search for a box signature */ +int +my_jpeg2000parse(wxInputStream& stream, unsigned long int filepoint, unsigned long int filelimit, int level, + char *scansign, unsigned long int *scanpoint) +{ + unsigned long int LBox = 0x00000000; + int LBox_read; + char TBox[5] = "\0\0\0\0"; + int TBox_read; + __int64 XLBox = 0x0000000000000000; + int XLBox_read; + unsigned long int box_length = 0; + int last_box = 0, box_num = 0; + int box_type = ANY_BOX; + unsigned char onebyte[1], twobytes[2], fourbytes[4]; + int box_number = 0; + + /* cycle all over the file */ + box_num = 0; + last_box = 0; + while (!last_box) { + + /* do not exceed file limit */ + if (filepoint >= filelimit) + return (0); + + /* seek on file */ + if (stream.SeekI(filepoint, wxFromStart) == wxInvalidOffset) + return (-1); + + /* read the mandatory LBox, 4 bytes */ + if (!stream.Read(fourbytes, 4)) { + (wxT("Problem reading LBox from the file (file ended?)")); + return -1; + }; + LBox = STREAM_TO_UINT32(fourbytes, 0); + + /* read the mandatory TBox, 4 bytes */ + if (!stream.Read(TBox, 4)) { + wxLogError(wxT("Problem reading TBox from the file (file ended?)")); + return -1; + }; + + /* look if scansign is got */ + if ((scansign != NULL) && (memcmp(TBox, scansign, 4) == 0)) { + /* hack/exploit */ + // stop as soon as you find the level-th codebox + if (box_number == level) { + memcpy(scansign, " ", 4); + *scanpoint = filepoint; + return (0); + } else + box_number++; + + }; + + + /* determine the box type */ + for (box_type = JP_BOX; box_type < UNK_BOX; box_type++) + if (memcmp(TBox, j2box[box_type].value, 4) == 0) + break; + + /* read the optional XLBox, 8 bytes */ + if (LBox == 1) { + + if (!stream.Read(&XLBox, 8)) { + wxLogError(wxT("Problem reading XLBox from the file (file ended?)")); + return -1; + }; + box_length = (unsigned long int) BYTE_SWAP8(XLBox); + + } else if (LBox == 0x00000000) { + + /* last box in file */ + last_box = 1; + box_length = filelimit - filepoint; + + } else + + box_length = LBox; + + + /* go deep in the box */ + my_box_handler_function((my_j2boxtype) box_type, stream, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), filepoint + box_length, level, + scansign, scanpoint); + + /* if it's a superbox go inside it */ + if (j2box[box_type].sbox) + my_jpeg2000parse(stream, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), filepoint + box_length, + level, scansign, scanpoint); + + /* increment box number and filepoint*/ + box_num++; + filepoint += box_length; + + }; + + /* all good */ + return (0); +} + +// search first contiguos codestream box in an mj2 file +unsigned long int +searchfirstjp2c(wxInputStream& stream, unsigned long int fsize) +{ + char scansign[] = "jp2c"; + unsigned long int scanpoint = 0L; + + wxLogMessage("MJ2: searching jp2c box... "); + + /* do the parsing */ + if (my_jpeg2000parse(stream, 0, fsize, 0, scansign, &scanpoint) < 0) + wxLogMessage("MJ2: Unrecoverable error during file parsing: stopping"); + + if (strcmp(scansign, " ")) + wxLogMessage("MJ2: not found"); + else { + + wxLogMessage(wxString::Format("MJ2: found at byte %d", scanpoint)); + + }; + + + return (scanpoint); +} + +// search the jp2h box in the file +unsigned long int +searchjpegheaderbox(wxInputStream& stream, unsigned long int fsize) +{ + char scansign[] = "jp2h"; + unsigned long int scanpoint = 0L; + + wxLogMessage("MJ2: searching jp2h box... "); + + /* do the parsing */ + if (my_jpeg2000parse(stream, 0, fsize, 0, scansign, &scanpoint) < 0) + wxLogMessage("Unrecoverable error during file parsing: stopping"); + + if (strcmp(scansign, " ")) + wxLogMessage("MJ2: not found"); + else + wxLogMessage(wxString::Format("MJ2: found at byte %d", scanpoint)); + + return (scanpoint); +} + +/* handling functions */ +#define ITEM_PER_ROW 10 + +/* Box handler function */ +int +my_box_handler_function(my_j2boxtype boxtype, wxInputStream& stream, unsigned long int filepoint, unsigned long int filelimit, int level, + char *scansign, unsigned long int *scanpoint) +{ + switch (boxtype) { + + /* Sample Description box */ + case (STSD_BOX): + my_jpeg2000parse(stream, filepoint + 8, filelimit, level, scansign, scanpoint); + break; + + /* MJP2 Sample Description box */ + case (MJP2_BOX): + my_jpeg2000parse(stream, filepoint + 78, filelimit, level, scansign, scanpoint); + break; + + /* not yet implemented */ + default: + break; + + }; + + return (0); +} + +// the jP and ftyp parts of the header +#define my_jPheadSIZE 32 +unsigned char my_jPhead[my_jPheadSIZE] = { + 0x00, 0x00, 0x00, 0x0C, 'j', 'P', ' ', ' ', + 0x0D, 0x0A, 0x87, 0x0A, 0x00, 0x00, 0x00, 0x14, + 'f', 't', 'y', 'p', 'j', 'p', '2', ' ', + 0x00, 0x00, 0x00, 0x00, 'j', 'p', '2', ' ' +}; + +///////////////////////////////////////////////// +///////////////////////////////////////////////// + +// load the mj2 file format +bool wxMJ2Handler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int index) +{ + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *opjimage = NULL; + FILE *fsrc = NULL; + unsigned char *src = NULL; + unsigned char *ptr; + int file_length, jp2c_point, jp2h_point; + unsigned long int jp2hboxlen, jp2cboxlen; + + // destroy the image + image->Destroy(); + + /* handle to a decompressor */ + opj_dinfo_t* dinfo = NULL; + opj_cio_t *cio = NULL; + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = mj2_error_callback; + event_mgr.warning_handler = mj2_warning_callback; + event_mgr.info_handler = mj2_info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + /* prepare parameters */ + parameters.decod_format = JP2_CFMT; + parameters.cod_format = BMP_DFMT; + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_JP2); + + /* find length of the stream */ + stream.SeekI(0, wxFromEnd); + file_length = (int) stream.TellI(); + + /* search for the first codestream box and the movie header box */ + jp2c_point = searchfirstjp2c(stream, file_length); + jp2h_point = searchjpegheaderbox(stream, file_length); + + // read the jp2h box and store it + stream.SeekI(jp2h_point, wxFromStart); + stream.Read(&jp2hboxlen, sizeof(unsigned long int)); + jp2hboxlen = BYTE_SWAP4(jp2hboxlen); + + // read the jp2c box and store it + stream.SeekI(jp2c_point, wxFromStart); + stream.Read(&jp2cboxlen, sizeof(unsigned long int)); + jp2cboxlen = BYTE_SWAP4(jp2cboxlen); + + // malloc memory source + src = (unsigned char *) malloc(my_jPheadSIZE + jp2hboxlen + jp2cboxlen); + + // copy the jP and ftyp + memcpy(src, my_jPhead, my_jPheadSIZE); + + // copy the jp2h + stream.SeekI(jp2h_point, wxFromStart); + stream.Read(&src[my_jPheadSIZE], jp2hboxlen); + + // copy the jp2c + stream.SeekI(jp2c_point, wxFromStart); + stream.Read(&src[my_jPheadSIZE + jp2hboxlen], jp2cboxlen); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, my_jPheadSIZE + jp2hboxlen + jp2cboxlen); + + /* decode the stream and fill the image structure */ + opjimage = opj_decode(dinfo, cio); + if (!opjimage) { + wxMutexGuiEnter(); + wxLogError("MJ2: failed to decode image!"); + wxMutexGuiLeave(); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + free(src); + return false; + } + + // check image size + if ((opjimage->numcomps != 1) && (opjimage->numcomps != 3)) { + wxMutexGuiEnter(); + wxLogError("MJ2: weird number of components"); + wxMutexGuiLeave(); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + free(src); + return false; + } + + // prepare image size + image->Create(opjimage->comps[0].w, opjimage->comps[0].h, true ); + + // access image raw data + image->SetMask( false ); + ptr = image->GetData(); + + // RGB color picture + // does not handle comps. subsampling, + // so simply render the first component + if (opjimage->numcomps == 3) { + int row, col; + int *r = opjimage->comps[0].data; + /* + int *g = opjimage->comps[1].data; + int *b = opjimage->comps[2].data; + */ + for (row = 0; row < opjimage->comps[0].h; row++) { + for (col = 0; col < opjimage->comps[0].w; col++) { + + /* + *(ptr++) = *(r++); + *(ptr++) = *(g++); + *(ptr++) = *(b++); + */ + *(ptr++) = *(r); + *(ptr++) = *(r); + *(ptr++) = *(r++); + + } + } + } + + // B/W picture + if (opjimage->numcomps == 1) { + int row, col; + int *y = opjimage->comps[0].data; + for (row = 0; row < opjimage->comps[0].h; row++) { + for (col = 0; col < opjimage->comps[0].w; col++) { + + *(ptr++) = *(y); + *(ptr++) = *(y); + *(ptr++) = *(y++); + + } + } + } + + wxMutexGuiEnter(); + wxLogMessage(wxT("MJ2: image loaded.")); + wxMutexGuiLeave(); + + /* close openjpeg structs */ + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + opj_image_destroy(opjimage); + free(src); + + if (!image->Ok()) + return false; + else + return true; + +} + +// save the mj2 file format +bool wxMJ2Handler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) +{ + wxLogError(wxT("MJ2: Couldn't save movie -> not implemented.")); + return false; +} + +#ifdef __VISUALC__ + #pragma warning(default:4611) +#endif /* VC++ */ + +// recognize the Motion JPEG 2000 starting box +bool wxMJ2Handler::DoCanRead( wxInputStream& stream ) +{ + unsigned char hdr[24]; + + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + return (hdr[0] == 0x00 && + hdr[1] == 0x00 && + hdr[2] == 0x00 && + hdr[3] == 0x0C && + hdr[4] == 0x6A && + hdr[5] == 0x50 && + hdr[6] == 0x20 && + hdr[7] == 0x20 && + hdr[20] == 0x6D && + hdr[21] == 0x6A && + hdr[22] == 0x70 && + hdr[23] == 0x32); +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_LIBOPENJPEG diff --git a/OPJViewer/source/imagmj2.h b/OPJViewer/source/imagmj2.h new file mode 100644 index 00000000..1c9667f8 --- /dev/null +++ b/OPJViewer/source/imagmj2.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: imagmj2.h +// Purpose: wxImage Motion JPEG 2000 file format handler +// Author: G. Baruffa - based on imagjpeg.h, Vaclav Slavik +// RCS-ID: $Id: imagmj2.h,v 0.0 2007/02/18 23:45:00 VZ Exp $ +// Copyright: (c) Giuseppe Baruffa +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_IMAGMJ2_H_ +#define _WX_IMAGMJ2_H_ + +#include "wx/defs.h" + +//----------------------------------------------------------------------------- +// wxMJ2Handler +//----------------------------------------------------------------------------- + +#if wxUSE_LIBOPENJPEG + +#include "wx/image.h" + +#define wxBITMAP_TYPE_MJ2 49 + +class WXDLLEXPORT wxMJ2Handler: public wxImageHandler +{ +public: + inline wxMJ2Handler() + { + m_name = wxT("Motion JPEG 2000 file format"); + m_extension = wxT("mj2"); + m_type = wxBITMAP_TYPE_MJ2; + m_mime = wxT("image/mj2"); + } + +#if wxUSE_STREAMS + virtual bool LoadFile( wxImage *image, wxInputStream& stream, bool verbose=true, int index=-1 ); + virtual bool SaveFile( wxImage *image, wxOutputStream& stream, bool verbose=true ); +protected: + virtual bool DoCanRead( wxInputStream& stream ); +#endif + +private: + DECLARE_DYNAMIC_CLASS(wxMJ2Handler) +}; + +#endif // wxUSE_LIBOPENJPEG + +#endif // _WX_IMAGMJ2_H_ + diff --git a/OPJViewer/source/wxj2kparser.cpp b/OPJViewer/source/wxj2kparser.cpp new file mode 100644 index 00000000..7e189d7b --- /dev/null +++ b/OPJViewer/source/wxj2kparser.cpp @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "OPJViewer.h" + +/* From little endian to big endian, 2 bytes */ +#define BYTE_SWAP2(X) ((X & 0x00FF) << 8) | ((X & 0xFF00) >> 8) +#define BYTE_SWAP4(X) ((X & 0x000000FF) << 24) | ((X & 0x0000FF00) << 8) | ((X & 0x00FF0000) >> 8) | ((X & 0xFF000000) >> 24) + +/* From codestream to int values */ +#define STREAM_TO_UINT32(C, P) (((unsigned long int) (C)[(P) + 0] << 24) + \ + ((unsigned long int) (C)[(P) + 1] << 16) + \ + ((unsigned long int) (C)[(P) + 2] << 8) + \ + ((unsigned long int) (C)[(P) + 3] << 0)) + +#define STREAM_TO_UINT16(C, P) (((unsigned long int) (C)[(P) + 0] << 8) + \ + ((unsigned long int) (C)[(P) + 1] << 0)) + + +/* Markers values */ +enum { + SOC_VAL = 0xFF4F, + SOT_VAL = 0xFF90, + SOD_VAL = 0xFF93, + EOC_VAL = 0xFFD9, + SIZ_VAL = 0xFF51, + COD_VAL = 0xFF52, + COC_VAL = 0xFF53, + RGN_VAL = 0xFF5E, + QCD_VAL = 0xFF5C, + QCC_VAL = 0xFF5D, + POD_VAL = 0xFF5F, + TLM_VAL = 0xFF55, + PLM_VAL = 0xFF57, + PLT_VAL = 0xFF58, + PPM_VAL = 0xFF60, + PPT_VAL = 0xFF61, + SOP_VAL = 0xFF91, + EPH_VAL = 0xFF92, + CME_VAL = 0xFF64, +#ifndef USEOLDJPWL + EPB_VAL = 0xFF66, + ESD_VAL = 0xFF67, + EPC_VAL = 0xFF68, + RED_VAL = 0xFF69 +#else + EPB_VAL = 0xFF96, + ESD_VAL = 0xFF98, + EPC_VAL = 0xFF97, + RED_VAL = 0xFF99 +#endif +}; + +// All the markers in one vector +unsigned short int marker_val[] = { + SOC_VAL, SOT_VAL, SOD_VAL, EOC_VAL, + SIZ_VAL, + COD_VAL, COC_VAL, RGN_VAL, QCD_VAL, QCC_VAL, POD_VAL, + TLM_VAL, PLM_VAL, PLT_VAL, PPM_VAL, PPT_VAL, + SOP_VAL, EPH_VAL, + CME_VAL, + EPB_VAL, ESD_VAL, EPC_VAL, RED_VAL +}; + +// Marker names +char *marker_name[] = { + "SOC", "SOT", "SOD", "EOC", + "SIZ", + "COD", "COC", "RGN", "QCD", "QCC", "POD", + "TLM", "PLM", "PLT", "PPM", "PPT", + "SOP", "EPH", + "CME", + "EPB", "ESD", "EPC", "RED" +}; + +// Marker descriptions +char *marker_descr[] = { + "Start of codestream", "Start of tile-part", "Start of data", "End of codestream", + "Image and tile size", + "Coding style default", "Coding style component", "Region-of-interest", "Quantization default", + "Quantization component", "Progression order change, default", + "Tile-part lengths, main header", "Packet length, main header", "Packets length, tile-part header", + "Packed packet headers, main header", "Packed packet headers, tile-part header", + "Start of packet", "End of packet header", + "Comment and extension", + "Error Protection Block", "Error Sensitivity Descriptor", "Error Protection Capability", + "Residual Errors Descriptor" +}; + +void OPJParseThread::ParseJ2KFile(wxFile *m_file, wxFileOffset offset, wxFileOffset length, wxTreeItemId parentid) +{ + // check if the file is opened + if (m_file->IsOpened()) + WriteText(wxT("File OK")); + else + return; + + // position at the beginning + m_file->Seek(offset, wxFromStart); + + //WriteText(wxString::Format(wxT("from to %d"), length)); + + // navigate the file + int m, inside_sod = 0, nmarks = 0, maxmarks = 10000, done = 0; + unsigned char onebyte[1]; + unsigned char twobytes[2]; + unsigned char fourbytes[4]; + unsigned short int currmark; + unsigned short int currlen; + int lastPsot = 0, lastsotpos = 0; + + WriteText(wxT("Start search...")); + while ((offset < length) && (!m_file->Eof())) { + + done = 0; + + // read da marka + if (m_file->Read(twobytes, 2) != 2) + break; + currmark = (((unsigned short int) twobytes[0]) << 8) + (unsigned short int) twobytes[1]; + + // Markers cycle + for (m = 0; m < 23; m++) { + + // check the marker + if (currmark == marker_val[m]) { + + if (currmark == SOD_VAL) { + + // we enter SOD + currlen = 0; + inside_sod = 1; + + } else if ((currmark == SOC_VAL) || (currmark == EOC_VAL) || (currmark == EPH_VAL)) + + currlen = 0; + + else { + + // read length + if (m_file->Read(twobytes, 2) != 2) + break; + currlen = (((unsigned short int) twobytes[0]) << 8) + (unsigned short int) twobytes[1]; + + } + + // inside SOD, only some markers are allowed + if (inside_sod && (currmark != SOD_VAL) && (currmark != SOT_VAL) + && (currmark != EOC_VAL) && (currmark != SOP_VAL) && (currmark != EPH_VAL)) + break; /*randomly marker coincident data */ + + if (inside_sod && (currmark == SOT_VAL) && (lastPsot == 0)) + inside_sod = 0; /* random data coincident with SOT, but last SOT was the last one */ + + if (inside_sod && (currmark == SOT_VAL)) + inside_sod = 0; /* new tile part */ + + // here we pass to AppendItem() normal and selected item images (we + // suppose that selected image follows the normal one in the enum) + int image, imageSel; + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + + // append the marker + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("%03d: %s (0x%04X)"), nmarks, marker_name[m], marker_val[m]), + image, imageSel, + new OPJMarkerData(wxT("MARK"), m_tree->m_fname.GetFullPath(), offset, offset + currlen + 1) + ); + + // append some info + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + // marker name + wxTreeItemId subcurrid1 = m_tree->AppendItem(currid, + wxT("*** ") + wxString(marker_descr[m]) + wxT(" ***"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + m_tree->SetItemFont(subcurrid1, *wxITALIC_FONT); + + // position and length + wxTreeItemId subcurrid2 = m_tree->AppendItem(currid, + wxLongLong(offset).ToString() + wxT(" > ") + wxLongLong(offset + currlen + 1).ToString() + + wxT(", ") + wxString::Format(wxT("%d + 2 (%d)"), currlen, currlen + 2), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + // give additional info on markers + switch (currmark) { + + case SOP_VAL: + { + // read packet number + if (m_file->Read(twobytes, 2) != 2) + break; + int packnum = STREAM_TO_UINT16(twobytes, 0);; + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("Pack. no. %d"), packnum), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + } + break; + + case SIZ_VAL: + { + m_file->Seek(2, wxFromCurrent); + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int xsiz = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int ysiz = STREAM_TO_UINT32(fourbytes, 0); + + m_file->Seek(24, wxFromCurrent); + if (m_file->Read(twobytes, 2) != 2) + break; + unsigned short int csiz = STREAM_TO_UINT16(twobytes, 0); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char ssiz = onebyte[0]; + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("%d x %d, %d comps. @ %d bpp"), xsiz, ysiz, csiz, (ssiz + 1) & 0xEF), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + break; + + case SOT_VAL: + { + if (m_file->Read(twobytes, 2) != 2) + break; + unsigned short int isot = STREAM_TO_UINT16(twobytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int psot = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char tpsot = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char tnsot = onebyte[0]; + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("tile %d, psot = %d, part %d of %d"), isot, psot, tpsot, tnsot), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + lastPsot = psot; + lastsotpos = offset; + }; + break; + + case CME_VAL: + { + #define showlen 25 + unsigned char comment[showlen]; + + m_file->Seek(2, wxFromCurrent); + if (m_file->Read(comment, showlen) != showlen) + break; + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("%.*s%s"), wxMin(showlen, currlen - 4), comment, + (((currlen - 4) > showlen) ? "..." : "")), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + } + break; + + default: + break; + } + + + // increment number of markers + nmarks++; + if (nmarks >= maxmarks) + break; + + // increment offset + if (currmark == SOD_VAL) + offset += lastPsot - (offset - lastsotpos); + else + offset += (2 + currlen); + + m_file->Seek(offset, wxFromStart); + done = 1; + + break; + } + } + + if (done) + continue; + else { + offset++; + m_file->Seek(offset, wxFromStart); + } + } + +} diff --git a/OPJViewer/source/wxjp2parser.cpp b/OPJViewer/source/wxjp2parser.cpp new file mode 100644 index 00000000..7d8f3447 --- /dev/null +++ b/OPJViewer/source/wxjp2parser.cpp @@ -0,0 +1,851 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "OPJViewer.h" + +/* defines */ +#define SHORT_DESCR_LEN 32 +#define LONG_DESCR_LEN 256 + +/* enumeration for file formats */ +#define J2FILENUM 4 +typedef enum { + + JP2_FILE, + J2K_FILE, + MJ2_FILE, + UNK_FILE + +} j2filetype; + +/* enumeration for the box types */ +#define J2BOXNUM 23 +typedef enum { + + FILE_BOX, + JP_BOX, + FTYP_BOX, + JP2H_BOX, + IHDR_BOX, + COLR_BOX, + JP2C_BOX, + JP2I_BOX, + XML_BOX, + UUID_BOX, + UINF_BOX, + MOOV_BOX, + MVHD_BOX, + TRAK_BOX, + TKHD_BOX, + MDIA_BOX, + MINF_BOX, + STBL_BOX, + STSD_BOX, + MJP2_BOX, + MDAT_BOX, + ANY_BOX, + UNK_BOX + +} j2boxtype; + +/* the box structure itself */ +struct boxdef { + + char value[5]; /* hexadecimal value/string*/ + char name[SHORT_DESCR_LEN]; /* short description */ + char descr[LONG_DESCR_LEN]; /* long description */ + int sbox; /* is it a superbox? */ + int req[J2FILENUM]; /* mandatory box */ + j2boxtype ins; /* contained in box... */ + +}; + +/* the possible boxes */ +struct boxdef j2box[]; + +/* macro functions */ +/* From little endian to big endian, 2 and 4 bytes */ +#define BYTE_SWAP2(X) ((X & 0x00FF) << 8) | ((X & 0xFF00) >> 8) +#define BYTE_SWAP4(X) ((X & 0x000000FF) << 24) | ((X & 0x0000FF00) << 8) | ((X & 0x00FF0000) >> 8) | ((X & 0xFF000000) >> 24) +#define BYTE_SWAP8(X) (((X & 0x00000000000000FF) << 56) | ((X & 0x000000000000FF00) << 40) | \ + ((X & 0x0000000000FF0000) << 24) | ((X & 0x00000000FF000000) << 8) | \ + ((X & 0x000000FF00000000) >> 8) | ((X & 0x0000FF0000000000) >> 24) | \ + ((X & 0x00FF000000000000) >> 40) | ((X & 0xFF00000000000000) >> 56)) + +/* From codestream to int values */ +#define STREAM_TO_UINT32(C, P) (((unsigned long int) (C)[(P) + 0] << 24) + \ + ((unsigned long int) (C)[(P) + 1] << 16) + \ + ((unsigned long int) (C)[(P) + 2] << 8) + \ + ((unsigned long int) (C)[(P) + 3] << 0)) + +#define STREAM_TO_UINT16(C, P) (((unsigned long int) (C)[(P) + 0] << 8) + \ + ((unsigned long int) (C)[(P) + 1] << 0)) + +#define OPJREAD_LONG(F,L,N) { \ + if (F->Read(fourbytes, 4) < 4) { \ + wxLogMessage(wxT("Problem reading " N " from the file (file ended?)")); \ + return -1; \ + }; \ + L = STREAM_TO_UINT32(fourbytes, 0); \ + } + +/* handling functions */ +#define ITEM_PER_ROW 10 + +//#define indprint if (0) printf("%.*s", 2 * level + 9, indent), printf +char indent[] = " " + " " + " " + " "; + +void indprint(wxString printout, int level) +{ + wxLogMessage(/*wxString::Format(wxT("%.*s"), 2 * level + 9, indent) + */printout); +} + +/* Box handler function */ +int OPJParseThread::box_handler_function(int boxtype, wxFile *fileid, wxFileOffset filepoint, wxFileOffset filelimit, + wxTreeItemId parentid, int level, char *scansign, unsigned long int *scanpoint) +{ + switch ((j2boxtype) boxtype) { + + + /* JPEG 2000 Signature box */ + case (JP_BOX): { + + unsigned long int checkdata = 0; + fileid->Read(&checkdata, sizeof(unsigned long int)); + checkdata = BYTE_SWAP4(checkdata); + + // add info + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Check data: %X -> %s"), checkdata, (checkdata == 0x0D0A870A) ? wxT("OK") : wxT("KO")), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + }; + break; + + + /* JPEG 2000 codestream box */ + case (JP2C_BOX): { + + // add info + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString(wxT("Codestream")), + m_tree->TreeCtrlIcon_Folder, m_tree->TreeCtrlIcon_Folder + 1, + new OPJMarkerData(wxT("INFO-CSTREAM"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + + m_tree->SetItemHasChildren(currid); + + // parse the file + //ParseJ2KFile(fileid, filepoint, filelimit, currid); + + }; + break; + + + + + + /* File Type box */ + case (FTYP_BOX): { + + char BR[4], CL[4]; + unsigned long int MinV, numCL, i; + fileid->Read(BR, sizeof(char) * 4); + fileid->Read(&MinV, sizeof(unsigned long int)); + MinV = BYTE_SWAP4(MinV); + numCL = (filelimit - fileid->Tell()) / 4; + + // add info + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Brand/Minor version: %.4s/%d"), BR, MinV), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Compatibility list")), + m_tree->TreeCtrlIcon_Folder, m_tree->TreeCtrlIcon_Folder + 1, + new OPJMarkerData(wxT("INFO")) + ); + + for (i = 0; i < numCL; i++) { + fileid->Read(CL, sizeof(char) * 4); + m_tree->AppendItem(currid, + wxString::Format(wxT("%.4s"), CL), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + }; + + }; + break; + + + + /* JP2 Header box */ + case (IHDR_BOX): { + + unsigned long int height, width; + unsigned short int nc; + unsigned char bpc, C, UnkC, IPR; + fileid->Read(&height, sizeof(unsigned long int)); + height = BYTE_SWAP4(height); + fileid->Read(&width, sizeof(unsigned long int)); + width = BYTE_SWAP4(width); + fileid->Read(&nc, sizeof(unsigned short int)); + nc = BYTE_SWAP2(nc); + fileid->Read(&bpc, sizeof(unsigned char)); + fileid->Read(&C, sizeof(unsigned char)); + fileid->Read(&UnkC, sizeof(unsigned char)); + fileid->Read(&IPR, sizeof(unsigned char)); + + // add info + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Dimensions: %d x %d x %d @ %d bpc"), width, height, nc, bpc + 1), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Compression type: %d"), C), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Colourspace unknown: %d"), UnkC), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Intellectual Property Rights: %d"), IPR), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + }; + break; + + + + /* Colour Specification box */ + case (COLR_BOX): { + + unsigned char METH, PREC, APPROX; + char methdescr[80], enumcsdescr[80]; + unsigned long int EnumCS; + fileid->Read(&METH, sizeof(unsigned char)); + switch (METH) { + case 1: + strcpy(methdescr, "Enumerated Colourspace"); + break; + case 2: + strcpy(methdescr, "Restricted ICC profile"); + break; + default: + strcpy(methdescr, "Unknown"); + break; + }; + fileid->Read(&PREC, sizeof(unsigned char)); + fileid->Read(&APPROX, sizeof(unsigned char)); + if (METH != 2) { + fileid->Read(&EnumCS, sizeof(unsigned long int)); + EnumCS = BYTE_SWAP4(EnumCS); + switch (EnumCS) { + case 16: + strcpy(enumcsdescr, "sRGB"); + break; + case 17: + strcpy(enumcsdescr, "greyscale"); + break; + case 18: + strcpy(enumcsdescr, "sYCC"); + break; + default: + strcpy(enumcsdescr, "Unknown"); + break; + }; + }; + + // add info + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Specification method: %d (%s)"), METH, methdescr), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Precedence: %d"), PREC), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Colourspace approximation: %d"), APPROX), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + if (METH != 2) + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Enumerated colourspace: %d (%s)"), EnumCS, enumcsdescr), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + if (METH != 1) + currid = m_tree->AppendItem(parentid, + wxString::Format("ICC profile: there is one"), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + + }; + break; + + + + + + + /* Movie Header Box */ + case (MVHD_BOX): { + + unsigned long int version, rate, matrix[9], next_track_ID; + unsigned short int volume; + fileid->Read(&version, sizeof(unsigned long int)); + version = BYTE_SWAP4(version); + if (version == 0) { + unsigned long int creation_time, modification_time, timescale, duration; + fileid->Read(&creation_time, sizeof(unsigned long int)); + creation_time = BYTE_SWAP4(creation_time); + fileid->Read(&modification_time, sizeof(unsigned long int)); + modification_time = BYTE_SWAP4(modification_time); + fileid->Read(×cale, sizeof(unsigned long int)); + timescale = BYTE_SWAP4(timescale); + fileid->Read(&duration, sizeof(unsigned long int)); + duration = BYTE_SWAP4(duration); + const long unix_time = creation_time - 2082844800L; + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Creation time: %u (%.24s)"), creation_time, ctime(&unix_time)), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + const long unix_time1 = modification_time - 2082844800L; + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Modification time: %u (%.24s)"), modification_time, ctime(&unix_time1)), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Timescale: %u (%.6fs)"), timescale, 1.0 / (float) timescale), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Duration: %u (%.3fs)"), duration, (float) duration / (float) timescale), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + } else { + unsigned __int64 creation_time, modification_time, duration; + unsigned long int timescale; + fileid->Read(&creation_time, sizeof(unsigned __int64)); + creation_time = BYTE_SWAP8(creation_time); + fileid->Read(&modification_time, sizeof(unsigned __int64)); + modification_time = BYTE_SWAP8(modification_time); + fileid->Read(×cale, sizeof(unsigned long int)); + timescale = BYTE_SWAP4(timescale); + fileid->Read(&duration, sizeof(unsigned __int64)); + duration = BYTE_SWAP8(duration); + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Creation time: %u"), creation_time), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Modification time: %u"), modification_time), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Timescale: %u"), timescale), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Duration: %u"), duration), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + }; + fileid->Read(&rate, sizeof(unsigned long int)); + rate = BYTE_SWAP4(rate); + fileid->Read(&volume, sizeof(unsigned short int)); + volume = BYTE_SWAP2(volume); + fileid->Seek(6, wxFromCurrent); + fileid->Read(&matrix, sizeof(unsigned char) * 9); + fileid->Seek(4, wxFromCurrent); + fileid->Read(&next_track_ID, sizeof(unsigned long int)); + next_track_ID = BYTE_SWAP4(next_track_ID); + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Rate: %d (%d.%d)"), rate, rate >> 16, rate & 0x0000FFFF), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Volume: %d (%d.%d)"), volume, volume >> 8, volume & 0x00FF), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Next track ID: %d"), next_track_ID), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + }; + break; + + + /* Sample Description box */ + case (STSD_BOX): { + + unsigned long int version, entry_count; + fileid->Read(&version, sizeof(unsigned long int)); + version = BYTE_SWAP4(version); + fileid->Read(&entry_count, sizeof(unsigned long int)); + entry_count = BYTE_SWAP4(entry_count); + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Entry count: %d"), entry_count), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + jpeg2000parse(fileid, filepoint + 8, filelimit, parentid, level + 1, scansign, scanpoint); + }; + break; + + + + /* MJP2 Sample Description box */ + case (MJP2_BOX): { + + unsigned short int height, width, depth; + unsigned long int horizresolution, vertresolution; + char compressor_name[32]; + fileid->Seek(24, wxFromCurrent); + fileid->Read(&width, sizeof(unsigned short int)); + width = BYTE_SWAP2(width); + fileid->Read(&height, sizeof(unsigned short int)); + height = BYTE_SWAP2(height); + fileid->Read(&horizresolution, sizeof(unsigned long int)); + horizresolution = BYTE_SWAP4(horizresolution); + fileid->Read(&vertresolution, sizeof(unsigned long int)); + vertresolution = BYTE_SWAP4(vertresolution); + fileid->Seek(6, wxFromCurrent); + fileid->Read(compressor_name, sizeof(char) * 32); + fileid->Read(&depth, sizeof(unsigned short int)); + depth = BYTE_SWAP2(depth); + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Dimensions: %d x %d @ %d bpp"), width, height, depth), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Resolution: %d.%d x %d.%d"), horizresolution >> 16, horizresolution & 0x0000FFFF, + vertresolution >> 16, vertresolution & 0x0000FFFF), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Compressor: %.32s"), compressor_name), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + jpeg2000parse(fileid, filepoint + 78, filelimit, parentid, level + 1, scansign, scanpoint); + + }; + break; + + + /* not yet implemented */ + default: + break; + + + + }; + + return (0); +} + +/* jp2 family box signatures */ +#define FILE_SIGN "" +#define JP_SIGN "jP\040\040" +#define FTYP_SIGN "ftyp" +#define JP2H_SIGN "jp2h" +#define IHDR_SIGN "ihdr" +#define COLR_SIGN "colr" +#define JP2C_SIGN "jp2c" +#define JP2I_SIGN "jp2i" +#define XML_SIGN "xml\040" +#define UUID_SIGN "uuid" +#define UINF_SIGN "uinf" +#define MOOV_SIGN "moov" +#define MVHD_SIGN "mvhd" +#define TRAK_SIGN "trak" +#define TKHD_SIGN "tkhd" +#define MDIA_SIGN "mdia" +#define MINF_SIGN "minf" +#define STBL_SIGN "stbl" +#define STSD_SIGN "stsd" +#define MJP2_SIGN "mjp2" +#define MDAT_SIGN "mdat" +#define ANY_SIGN "" +#define UNK_SIGN "" + +/* the possible boxes */ +struct boxdef j2box[] = +{ +/* sign */ {FILE_SIGN, +/* short */ "placeholder for nothing", +/* long */ "Nothing to say", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {JP_SIGN, +/* short */ "JPEG 2000 Signature box", +/* long */ "This box uniquely identifies the file as being part of the JPEG 2000 family of files", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {FTYP_SIGN, +/* short */ "File Type box", +/* long */ "This box specifies file type, version and compatibility information, including specifying if this file " + "is a conforming JP2 file or if it can be read by a conforming JP2 reader", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {JP2H_SIGN, +/* short */ "JP2 Header box", +/* long */ "This box contains a series of boxes that contain header-type information about the file", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {IHDR_SIGN, +/* short */ "Image Header box", +/* long */ "This box specifies the size of the image and other related fields", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ JP2H_BOX}, + +/* sign */ {COLR_SIGN, +/* short */ "Colour Specification box", +/* long */ "This box specifies the colourspace of the image", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ JP2H_BOX}, + +/* sign */ {JP2C_SIGN, +/* short */ "Contiguous Codestream box", +/* long */ "This box contains the codestream as defined by Annex A", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {JP2I_SIGN, +/* short */ "Intellectual Property box", +/* long */ "This box contains intellectual property information about the image", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {XML_SIGN, +/* short */ "XML box", +/* long */ "This box provides a tool by which vendors can add XML formatted information to a JP2 file", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {UUID_SIGN, +/* short */ "UUID box", +/* long */ "This box provides a tool by which vendors can add additional information to a file " + "without risking conflict with other vendors", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {UINF_SIGN, +/* short */ "UUID Info box", +/* long */ "This box provides a tool by which a vendor may provide access to additional information associated with a UUID", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {MOOV_SIGN, +/* short */ "Movie box", +/* long */ "This box contains the media data. In video tracks, this box would contain JPEG2000 video frames", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {MVHD_SIGN, +/* short */ "Movie Header box", +/* long */ "This box defines overall information which is media-independent, and relevant to the entire presentation " + "considered as a whole", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MOOV_BOX}, + +/* sign */ {TRAK_SIGN, +/* short */ "Track box", +/* long */ "This is a container box for a single track of a presentation. A presentation may consist of one or more tracks", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ MOOV_BOX}, + +/* sign */ {TKHD_SIGN, +/* short */ "Track Header box", +/* long */ "This box specifies the characteristics of a single track. Exactly one Track Header Box is contained in a track", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ TRAK_BOX}, + +/* sign */ {MDIA_SIGN, +/* short */ "Media box", +/* long */ "The media declaration container contains all the objects which declare information about the media data " + "within a track", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ TRAK_BOX}, + +/* sign */ {MINF_SIGN, +/* short */ "Media Information box", +/* long */ "This box contains all the objects which declare characteristic information of the media in the track", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ MDIA_BOX}, + +/* sign */ {STBL_SIGN, +/* short */ "Sample Table box", +/* long */ "The sample table contains all the time and data indexing of the media samples in a track", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {STSD_SIGN, +/* short */ "Sample Description box", +/* long */ "The sample description table gives detailed information about the coding type used, and any initialization " + "information needed for that coding", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {MJP2_SIGN, +/* short */ "MJP2 Sample Description box", +/* long */ "The MJP2 sample description table gives detailed information about the coding type used, and any initialization " + "information needed for that coding", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {MDAT_SIGN, +/* short */ "Media Data box", +/* long */ "The meta-data for a presentation is stored in the single Movie Box which occurs at the top-level of a file", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {ANY_SIGN, +/* short */ "Any box", +/* long */ "All the existing boxes", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {UNK_SIGN, +/* short */ "Unknown Type box", +/* long */ "The signature is not recognised to be that of an existing box", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ ANY_BOX} + +}; + +void OPJParseThread::ParseJP2File(wxFile *fileid, wxFileOffset filepoint, wxFileOffset filelimit, wxTreeItemId parentid) +{ + unsigned long int scanpoint; + + jpeg2000parse(fileid, filepoint, filelimit, parentid, 0, NULL, &scanpoint); +} + +/* the parsing function itself */ +/* + fileid = fid of the file to scan (you should open it by yourself) + filepoint = first byte where to start to scan from (usually 0) + filelimit = first byte where to stop to scan from (usually the file size) + level = set this to 0 + scansign = signature to scan for (NULL avoids search, returns " " if successful) + scanpoint = point where the scan signature lies +*/ +int OPJParseThread::jpeg2000parse(wxFile *fileid, wxFileOffset filepoint, wxFileOffset filelimit, + wxTreeItemId parentid, int level, char *scansign, unsigned long int *scanpoint) +{ + unsigned long int LBox = 0x00000000; + int LBox_read; + char TBox[5] = "\0\0\0\0"; + int TBox_read; + __int64 XLBox = 0x0000000000000000; + int XLBox_read; + unsigned long int box_length = 0; + int last_box = 0, box_num = 0; + int box_type = ANY_BOX; + unsigned char onebyte[1], twobytes[2], fourbytes[4]; + + /* cycle all over the file */ + box_num = 0; + last_box = 0; + while (!last_box) { + + /* do not exceed file limit */ + if (filepoint >= filelimit) + return (0); + + /* seek on file */ + if (fileid->Seek(filepoint, wxFromStart) == wxInvalidOffset) + return (-1); + + /* read the mandatory LBox, 4 bytes */ + if (fileid->Read(fourbytes, 4) < 4) { + WriteText(wxT("Problem reading LBox from the file (file ended?)")); + return -1; + }; + LBox = STREAM_TO_UINT32(fourbytes, 0); + + /* read the mandatory TBox, 4 bytes */ + if (fileid->Read(TBox, 4) < 4) { + WriteText(wxT("Problem reading TBox from the file (file ended?)")); + return -1; + }; + + /* look if scansign is got */ + if ((scansign != NULL) && (memcmp(TBox, scansign, 4) == 0)) { + memcpy(scansign, " ", 4); + *scanpoint = filepoint; + + /* hack/exploit */ + // stop as soon as you find the codebox + return (0); + + }; + + /* determine the box type */ + for (box_type = JP_BOX; box_type < UNK_BOX; box_type++) + if (memcmp(TBox, j2box[box_type].value, 4) == 0) + break; + + /* read the optional XLBox, 8 bytes */ + if (LBox == 1) { + + if (fileid->Read(&XLBox, 8) < 8) { + WriteText(wxT("Problem reading XLBox from the file (file ended?)")); + return -1; + }; + box_length = (unsigned long int) BYTE_SWAP8(XLBox); + + } else if (LBox == 0x00000000) { + + /* last box in file */ + last_box = 1; + box_length = filelimit - filepoint; + + } else + + box_length = LBox; + + /* show box info */ + + // append the marker + int image, imageSel; + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("%03d: %s (0x%04X)"), box_num, TBox, + ((unsigned long int) TBox[3]) + ((unsigned long int) TBox[2] << 8) + + ((unsigned long int) TBox[1] << 16) + ((unsigned long int) TBox[0] << 24) + ), + image, imageSel, + new OPJMarkerData(wxT("BOX"), m_tree->m_fname.GetFullPath(), filepoint, filepoint + box_length) + ); + + // append some info + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + // box name + wxTreeItemId subcurrid1 = m_tree->AppendItem(currid, + wxT("*** ") + wxString(j2box[box_type].name) + wxT(" ***"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + m_tree->SetItemFont(subcurrid1, *wxITALIC_FONT); + + // position and length + wxTreeItemId subcurrid2 = m_tree->AppendItem(currid, + wxLongLong(filepoint).ToString() + wxT(" > ") + wxLongLong(filepoint + box_length - 1).ToString() + + wxT(", ") + wxString::Format(wxT("%d + 8 (%d)"), box_length, box_length + 8), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + /* go deep in the box */ + box_handler_function((int) box_type, fileid, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), filepoint + box_length, + currid, level, scansign, scanpoint); + + /* if it's a superbox go inside it */ + if (j2box[box_type].sbox) + jpeg2000parse(fileid, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), filepoint + box_length, + currid, level + 1, scansign, scanpoint); + + /* increment box number and filepoint*/ + box_num++; + filepoint += box_length; + + }; + + /* all good */ + return (0); +} +