691 lines
14 KiB
C
691 lines
14 KiB
C
/*
|
|
* MiniGIF.c
|
|
*
|
|
*
|
|
*
|
|
* This wizard-generated code is based on code adapted from the
|
|
* stationery files distributed as part of the Palm OS SDK 4.0.
|
|
*
|
|
* Copyright (c) 1999-2004 PalmOne, Inc. or its subsidiaries.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include <PalmOS.h>
|
|
#include <VFSMgr.h>
|
|
#include <MemGlue.h>
|
|
#include "Common.h"
|
|
#include "MiniGIFRsc.h"
|
|
#include "FileBrowserForm.h"
|
|
#include "FileBrowserFormRsrc.h"
|
|
#include <PalmOneCodecPluginMgr.h>
|
|
#include <PalmOneCodecFormat.h>
|
|
#include <HsNav.h>
|
|
|
|
#define ourMinVersion sysMakeROMVersion(3,0,0,sysROMStageDevelopment,0)
|
|
#define kPalmOS20Version sysMakeROMVersion(2,0,0,sysROMStageDevelopment,0)
|
|
|
|
#define TRACK_TIME (sysTicksPerSecond / 10)
|
|
|
|
/**
|
|
* GIF info.
|
|
*/
|
|
typedef struct
|
|
{
|
|
UInt32 top;
|
|
UInt32 left;
|
|
UInt32 width;
|
|
UInt32 height;
|
|
UInt32 delay;
|
|
WinHandle winHandle;
|
|
|
|
struct GIFFrame *nextP;
|
|
|
|
} GIFFrame;
|
|
|
|
/**
|
|
* File Info
|
|
*/
|
|
typedef struct
|
|
{
|
|
Char filePath[256]; // Contains filename + full path
|
|
|
|
FileRef fileRef; // File ref
|
|
UInt32 fileSize; // File size
|
|
UInt32 fileDataSize; // Dile data size (=fileEndOffset-fileStartOffset)
|
|
UInt32 fileStartOffset;// File start offset
|
|
UInt32 fileEndOffset; // File end offset
|
|
|
|
} FileInfo;
|
|
|
|
/**
|
|
* Mini info structure.
|
|
*
|
|
*/
|
|
typedef struct
|
|
{
|
|
UInt16 codecMgrLibRefNum;
|
|
PalmCodecSession session; //
|
|
|
|
FileInfo fileInfo; // File info
|
|
UInt32 imageWidth;
|
|
UInt32 imageHeight;
|
|
UInt32 rowByte;
|
|
GIFFrame *gifImageP;
|
|
|
|
UInt16 cardNo;
|
|
LocalID dbID;
|
|
} MiniInfo;
|
|
|
|
/**
|
|
* Globals
|
|
*/
|
|
static MiniInfo gMiniInfo;
|
|
static UInt32 gScreenDepth = 16;
|
|
static UInt32 gPreviousScreenDepth = 0;
|
|
static UInt32 gLastTick = 0;
|
|
static GIFFrame *gCurrentImageP = NULL;
|
|
static Char gAlertString[85];
|
|
static Boolean gPen = false;
|
|
|
|
/**
|
|
* Byte-swapping function
|
|
*/
|
|
static void PrvSwapStructure(UInt32 *structP, UInt32 numElement)
|
|
{
|
|
while(numElement--) {
|
|
*structP = Swap32(*structP);
|
|
structP++;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Load the GIF file
|
|
*/
|
|
static Err PrvLoadGIF()
|
|
{
|
|
Err err = errNone;
|
|
UInt32 inSize = 0;
|
|
UInt32 outSize = 0;
|
|
// UInt32 written = 0;
|
|
UInt8 *bufferP = NULL;
|
|
UInt32 bufferSize = 0;
|
|
GIFFrame **gifFramePP = NULL;
|
|
PalmCodecSession gifSession = NULL;
|
|
PalmImageParamType *imageParamP = NULL;
|
|
PalmFileFormatParamType *fileParamP = NULL;
|
|
PalmImageGIFFrameParamType *gifParamP = NULL;
|
|
|
|
// Always use MemPtrNew, so that we are sure the pointers are 4 byte aligned
|
|
fileParamP = MemPtrNew(sizeof(PalmFileFormatParamType)) ;
|
|
imageParamP = MemPtrNew(sizeof(PalmImageParamType));
|
|
gifParamP = MemPtrNew(sizeof(PalmImageGIFFrameParamType));
|
|
|
|
if(!fileParamP || !imageParamP || !gifParamP) {
|
|
FrmCustomAlert(InfoAlert, "Not Enough Memory !", NULL, NULL);
|
|
err = 1;
|
|
goto Done;
|
|
}
|
|
|
|
// Set File parameters
|
|
fileParamP->fileLocationType = Swap32(palmCodecVFSFile);
|
|
fileParamP->vfsFileRef = (FileRef)Swap32(gMiniInfo.fileInfo.fileRef);
|
|
|
|
imageParamP->width = Swap32(0);
|
|
imageParamP->height = Swap32(0);
|
|
imageParamP->rowByte = Swap32(0);
|
|
imageParamP->endianess = Swap32(palmCodecLITTLE_ENDIAN);
|
|
|
|
// Create Session
|
|
err = CodecMgrCreateSession(gMiniInfo.codecMgrLibRefNum,
|
|
palmCodecImageGIF89aFile, fileParamP,
|
|
palmCodecImageBGR565, imageParamP,
|
|
&gifSession);
|
|
|
|
if(err) {
|
|
FrmCustomAlert(InfoAlert, "Unable to create codec session !", NULL, NULL);
|
|
goto Done;
|
|
}
|
|
|
|
// Get the width and height of the image sent back
|
|
gMiniInfo.imageWidth = Swap32(imageParamP->width);
|
|
gMiniInfo.imageHeight = Swap32(imageParamP->height);
|
|
gMiniInfo.rowByte = Swap32(imageParamP->rowByte);
|
|
|
|
gifFramePP = &gMiniInfo.gifImageP;
|
|
|
|
// Allocate buffer
|
|
bufferSize = gMiniInfo.rowByte * gMiniInfo.imageHeight;
|
|
bufferP = MemPtrNew(bufferSize); //MemGluePtrNew(bufferSize);
|
|
if(!bufferP) {
|
|
FrmCustomAlert(InfoAlert, "Not Enough Memory !", NULL, NULL);
|
|
err = 1;
|
|
goto Done;
|
|
}
|
|
|
|
// Decode the image
|
|
while(true)
|
|
{
|
|
// Set the size for the input and output
|
|
inSize = sizeof(PalmFileFormatParamType);
|
|
outSize = sizeof(PalmImageGIFFrameParamType); //outSize = bufferSize;
|
|
|
|
// Gif Params
|
|
gifParamP->imageDataSize = Swap32(bufferSize);
|
|
gifParamP->imageDataP = (UInt8*)Swap32(bufferP);
|
|
|
|
// Decode 1 frame
|
|
err = CodecMgrEncodeDecode(gMiniInfo.codecMgrLibRefNum,
|
|
gifSession, fileParamP, &inSize, gifParamP, &outSize);
|
|
|
|
// If no more to read
|
|
if(!inSize || err)
|
|
{
|
|
if(outSize == 0)
|
|
err = errNone;//Hack, because the last encode decode may return error
|
|
break;
|
|
}
|
|
|
|
// We have a frame!
|
|
if(outSize) {
|
|
UInt8 *winBufferP = NULL;
|
|
BitmapType *winBmpP = NULL;
|
|
|
|
// Swap the returned structure - only the first 11 elements
|
|
PrvSwapStructure((UInt32*)gifParamP, 11);
|
|
gifParamP->imageDataSize = Swap32(gifParamP->imageDataSize);
|
|
|
|
// Create new gif frame in out list
|
|
*gifFramePP = MemPtrNew(sizeof(GIFFrame));
|
|
MemSet(*gifFramePP, sizeof(GIFFrame), 0);
|
|
|
|
(*gifFramePP)->top = gifParamP->topPosition;
|
|
(*gifFramePP)->left = gifParamP->leftPosition;
|
|
(*gifFramePP)->width = gifParamP->imageWidth;
|
|
(*gifFramePP)->height = gifParamP->imageHeight;
|
|
(*gifFramePP)->delay = gifParamP->delayTime * 100 / sysTicksPerSecond;
|
|
|
|
// Create offscreen buffer and copy data into it
|
|
(*gifFramePP)->winHandle = WinCreateOffscreenWindow((gifParamP->imageWidth+1) / 2, (gifParamP->imageHeight+1) / 2, nativeFormat, &err);
|
|
winBmpP = WinGetBitmap((*gifFramePP)->winHandle);
|
|
winBufferP = BmpGetBits(winBmpP);
|
|
MemMove(winBufferP, bufferP, gifParamP->imageDataSize);
|
|
|
|
gifFramePP = (GIFFrame**)&((*gifFramePP)->nextP);
|
|
}
|
|
}
|
|
|
|
Done:
|
|
gCurrentImageP = gMiniInfo.gifImageP;
|
|
|
|
if(gifSession)
|
|
CodecMgrDeleteSession(gMiniInfo.codecMgrLibRefNum, &gifSession);
|
|
if(fileParamP)
|
|
MemPtrFree(fileParamP);
|
|
if(imageParamP)
|
|
MemPtrFree(imageParamP);
|
|
if(gifParamP)
|
|
MemPtrFree(gifParamP);
|
|
if(bufferP)
|
|
MemPtrFree(bufferP);
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Draw image on the screen
|
|
*/
|
|
static void PrvDrawCurrentImage()
|
|
{
|
|
Coord x, y;
|
|
RectangleType rect = { { 0, 0 }, { 0, 0 } };
|
|
RectangleType rect2;
|
|
|
|
// Image size
|
|
rect.extent.x = gMiniInfo.imageWidth / 2;
|
|
if(rect.extent.x > 160) rect.extent.x = 160;
|
|
rect.extent.y = gMiniInfo.imageHeight / 2;
|
|
if(rect.extent.y > 160) rect.extent.y = 160;
|
|
|
|
// Center the image
|
|
x = 80 - rect.extent.x / 2;
|
|
y = 80 - rect.extent.y / 2;
|
|
|
|
MemMove(&rect2, &rect, sizeof(RectangleType));
|
|
rect2.topLeft.x = x;
|
|
rect2.topLeft.y = y;
|
|
|
|
// Display the capture image
|
|
if(gCurrentImageP && gCurrentImageP->winHandle)
|
|
WinCopyRectangle(gCurrentImageP->winHandle, WinGetDisplayWindow(), &rect, x, y, winPaint);
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
|
|
/**
|
|
* Shows Alert Box
|
|
*/
|
|
static void PrvAlert( Char* string)
|
|
{
|
|
|
|
FrmCustomAlert( InfoAlert, string,"","");
|
|
|
|
}
|
|
|
|
/**
|
|
* Open a file
|
|
*/
|
|
static Err PrvFileOpen()
|
|
{
|
|
Err err = errNone;
|
|
UInt32 volumeIterator = 0;
|
|
UInt16 firstVolume = 0;
|
|
|
|
|
|
volumeIterator = vfsIteratorStart;
|
|
err = VFSVolumeEnumerate(&firstVolume, &volumeIterator);
|
|
if( err == expErrEnumerationEmpty ) {
|
|
StrCopy( gAlertString, "Error enumerating Volume");
|
|
goto Done;
|
|
}
|
|
|
|
// If we have a file path, open the file
|
|
if( gMiniInfo.fileInfo.filePath[0]!=NULL )
|
|
{
|
|
err = VFSFileOpen(firstVolume, (Char*)gMiniInfo.fileInfo.filePath, vfsModeRead, &gMiniInfo.fileInfo.fileRef);
|
|
if( err )
|
|
{
|
|
StrCopy( gAlertString, "File Open err. Select a gif file");
|
|
goto Done;
|
|
}
|
|
|
|
// Store the file size
|
|
err = VFSFileSize(gMiniInfo.fileInfo.fileRef , &gMiniInfo.fileInfo.fileSize);
|
|
if( err )
|
|
{
|
|
StrCopy( gAlertString, "File Size Error");
|
|
goto Done;
|
|
}
|
|
gMiniInfo.fileInfo.fileStartOffset = 0;
|
|
gMiniInfo.fileInfo.fileEndOffset = gMiniInfo.fileInfo.fileSize;
|
|
}
|
|
|
|
Done:
|
|
|
|
if(err)
|
|
PrvAlert( gAlertString );
|
|
return err;
|
|
}
|
|
|
|
|
|
/**
|
|
* Memory clean up after we are done displaying the images
|
|
*
|
|
*/
|
|
static void PrvCleanImages()
|
|
{
|
|
GIFFrame *gifFrameP = gMiniInfo.gifImageP;
|
|
|
|
while(gifFrameP)
|
|
{
|
|
GIFFrame *nextP = (GIFFrame *)gifFrameP->nextP;
|
|
if(gifFrameP->winHandle)
|
|
WinDeleteWindow(gifFrameP->winHandle, false);
|
|
MemPtrFree(gifFrameP);
|
|
gifFrameP = nextP;
|
|
}
|
|
|
|
// Seek the file to beginning, if folks wanna click on Display again.
|
|
VFSFileSeek ( gMiniInfo.fileInfo.fileRef,vfsOriginBeginning, 0);
|
|
gMiniInfo.gifImageP = NULL;
|
|
gCurrentImageP = NULL;
|
|
}
|
|
|
|
/**
|
|
* File info callback.
|
|
* This function is called by the file browser
|
|
*/
|
|
static void PrvGetInputFileInfoCallback(UInt16 volume, const Char* path, const Char* file)
|
|
{
|
|
Err err = errNone;
|
|
|
|
// Create the full path name
|
|
StrCopy(gMiniInfo.fileInfo.filePath, path);
|
|
|
|
// Internally, we expect full path
|
|
StrCat(gMiniInfo.fileInfo.filePath, file);
|
|
|
|
// Open the selected file
|
|
err = PrvFileOpen();
|
|
if(err) {
|
|
// Oops!
|
|
FrmCustomAlert(InfoAlert, "Error opening Input file", "" ,"");
|
|
}
|
|
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
|
|
/*
|
|
* FUNCTION: MainFormDoCommand
|
|
*
|
|
* DESCRIPTION: This routine performs the menu command specified.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* command
|
|
* menu item id
|
|
*/
|
|
|
|
static Boolean MainFormDoCommand(UInt16 command)
|
|
{
|
|
Boolean handled = false;
|
|
FormType *frmAboutP = NULL;
|
|
|
|
switch (command)
|
|
{
|
|
case HelpAboutMiniGIF:
|
|
frmAboutP = FrmInitForm(HelpAboutMiniGIF);
|
|
FrmDoDialog(frmAboutP); // Display the About Box.
|
|
FrmDeleteForm(frmAboutP);
|
|
|
|
handled = true;
|
|
break;
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
/**
|
|
* MainFormHandleEvent
|
|
*/
|
|
static Boolean MainFormHandleEvent(EventType * eventP)
|
|
{
|
|
Boolean handled = false;
|
|
FormType *frmP = FrmGetActiveForm();
|
|
|
|
switch (eventP->eType)
|
|
{
|
|
case menuEvent:
|
|
handled = MainFormDoCommand(eventP->data.menu.itemID);
|
|
break;
|
|
|
|
case frmOpenEvent:
|
|
|
|
FrmDrawForm(frmP);
|
|
FrmNavObjectTakeFocus(frmP, MainFileButton);
|
|
handled = true;
|
|
break;
|
|
|
|
|
|
case ctlSelectEvent:
|
|
if(eventP->data.ctlSelect.controlID == MainFileButton)
|
|
{
|
|
FileBrowserSetCallback(&PrvGetInputFileInfoCallback, MainForm);
|
|
FrmGotoForm(FileBrowserForm);
|
|
handled = true;
|
|
|
|
}
|
|
else if(eventP->data.ctlSelect.controlID == MainDisplayButton)
|
|
{
|
|
FrmGotoForm( DisplayForm );
|
|
handled = true;
|
|
}
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
Done:
|
|
return handled;
|
|
}
|
|
|
|
/**
|
|
* DisplayFormHandleEvent
|
|
*/
|
|
static Boolean DisplayFormHandleEvent(EventType *eventP)
|
|
{
|
|
Err err = errNone;
|
|
Boolean handled = false;
|
|
FormType *frmP = FrmGetActiveForm();
|
|
|
|
switch(eventP->eType)
|
|
{
|
|
case frmOpenEvent:
|
|
FrmDrawForm(frmP);
|
|
err = PrvLoadGIF();
|
|
if( !err )
|
|
PrvDrawCurrentImage();
|
|
else
|
|
FrmGotoForm( MainForm );
|
|
|
|
gLastTick = TimGetTicks();
|
|
|
|
handled = true;
|
|
break;
|
|
|
|
case frmCloseEvent:
|
|
PrvCleanImages();
|
|
handled = true;
|
|
break;
|
|
|
|
case penDownEvent:
|
|
gPen = true;
|
|
break;
|
|
|
|
case penUpEvent:
|
|
if( gPen == true ){
|
|
gPen = false;
|
|
FrmGotoForm(MainForm);
|
|
}
|
|
|
|
handled = true;
|
|
break;
|
|
|
|
case nilEvent:
|
|
if(gCurrentImageP && (TimGetTicks() - gLastTick >= gCurrentImageP->delay))
|
|
{
|
|
gCurrentImageP = (GIFFrame*)gCurrentImageP->nextP;
|
|
if(!gCurrentImageP)
|
|
gCurrentImageP = gMiniInfo.gifImageP;
|
|
PrvDrawCurrentImage();
|
|
gLastTick = TimGetTicks();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
/**
|
|
* AppHandleEvent
|
|
*/
|
|
static Boolean AppHandleEvent(EventType * eventP)
|
|
{
|
|
UInt16 formId;
|
|
FormType * frmP;
|
|
|
|
if (eventP->eType == frmLoadEvent)
|
|
{
|
|
formId = eventP->data.frmLoad.formID;
|
|
frmP = FrmInitForm(formId);
|
|
FrmSetActiveForm(frmP);
|
|
|
|
switch (formId)
|
|
{
|
|
case MainForm:
|
|
FrmSetEventHandler(frmP, MainFormHandleEvent);
|
|
break;
|
|
|
|
case FileBrowserForm:
|
|
FrmSetEventHandler(frmP, FileBrowserFormHandleEvent);
|
|
break;
|
|
|
|
case DisplayForm:
|
|
FrmSetEventHandler(frmP, DisplayFormHandleEvent);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* AppEventLoop
|
|
*/
|
|
static void AppEventLoop(void)
|
|
{
|
|
UInt16 error = errNone;
|
|
EventType event;
|
|
|
|
do
|
|
{
|
|
EvtGetEvent(&event, 0);
|
|
|
|
if (! SysHandleEvent(&event)) {
|
|
if (! MenuHandleEvent(0, &event, &error)) {
|
|
if (! AppHandleEvent(&event)) {
|
|
FrmDispatchEvent(&event);
|
|
}
|
|
}
|
|
}
|
|
} while (event.eType != appStopEvent);
|
|
}
|
|
|
|
/**
|
|
* AppStart
|
|
* Called when the application starts.
|
|
*/
|
|
static Err AppStart(void)
|
|
{
|
|
Err err = errNone;
|
|
|
|
// Clear the global
|
|
MemSet(&gMiniInfo, sizeof(MiniInfo), 0);
|
|
|
|
// Try to find the hardware utils library
|
|
err = SysLibFind(kCodecMgrLibName, &gMiniInfo.codecMgrLibRefNum);
|
|
if (err != errNone)
|
|
{
|
|
err = SysLibLoad(kCodecMgrLibType, kCodecMgrLibCreator, &gMiniInfo.codecMgrLibRefNum);
|
|
if(err == errNone)
|
|
err = CodecMgrOpen(gMiniInfo.codecMgrLibRefNum);
|
|
}
|
|
|
|
if(err) {
|
|
FrmCustomAlert(InfoAlert, "Codec Plugin Manager not found !", NULL, NULL);
|
|
goto Done;
|
|
}
|
|
|
|
|
|
// Switch to 16 bit color
|
|
WinScreenMode(winScreenModeGet, NULL, NULL, &gPreviousScreenDepth, NULL);
|
|
WinScreenMode(winScreenModeSet, NULL, NULL, &gScreenDepth, NULL);
|
|
|
|
Done:
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* AppStop
|
|
* Called when the application stops.
|
|
*/
|
|
static void AppStop(void)
|
|
{
|
|
Err err = errNone;
|
|
|
|
FrmCloseAllForms();
|
|
|
|
// Close the library
|
|
err = CodecMgrClose(gMiniInfo.codecMgrLibRefNum);
|
|
if (err == errNone)
|
|
err = SysLibRemove(gMiniInfo.codecMgrLibRefNum);
|
|
|
|
|
|
// Restore previous color mode
|
|
WinScreenMode(winScreenModeSet, NULL, NULL, &gPreviousScreenDepth, NULL);
|
|
}
|
|
|
|
#pragma warn_a5_access on
|
|
|
|
//
|
|
// RomVersionCompatible
|
|
//
|
|
static Err RomVersionCompatible(UInt32 requiredVersion, UInt16 launchFlags)
|
|
{
|
|
UInt32 romVersion;
|
|
|
|
FtrGet(sysFtrCreator, sysFtrNumROMVersion, &romVersion);
|
|
if (romVersion < requiredVersion)
|
|
{
|
|
if ((launchFlags &
|
|
(sysAppLaunchFlagNewGlobals | sysAppLaunchFlagUIApp)) ==
|
|
(sysAppLaunchFlagNewGlobals | sysAppLaunchFlagUIApp))
|
|
{
|
|
FrmAlert (RomIncompatibleAlert);
|
|
|
|
if (romVersion < kPalmOS20Version)
|
|
{
|
|
AppLaunchWithCommand(
|
|
sysFileCDefaultApp,
|
|
sysAppLaunchCmdNormalLaunch, NULL);
|
|
}
|
|
}
|
|
|
|
return sysErrRomIncompatible;
|
|
}
|
|
|
|
return errNone;
|
|
}
|
|
|
|
//
|
|
// PilotMain
|
|
//
|
|
UInt32 PilotMain(UInt16 cmd, MemPtr cmdPBP, UInt16 launchFlags)
|
|
{
|
|
Err error;
|
|
SysNotifyParamType *notifyParamP = NULL;
|
|
|
|
error = RomVersionCompatible (ourMinVersion, launchFlags);
|
|
if (error) return (error);
|
|
|
|
switch (cmd)
|
|
{
|
|
case sysAppLaunchCmdNormalLaunch:
|
|
error = AppStart();
|
|
if (error)
|
|
return error;
|
|
|
|
FrmGotoForm(MainForm);
|
|
AppEventLoop();
|
|
|
|
AppStop();
|
|
break;
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
Done:
|
|
return errNone;
|
|
}
|
|
|
|
#pragma warn_a5_access reset
|