1912 lines
46 KiB
C
1912 lines
46 KiB
C
/*
|
|
* MiniImage.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) 2006 Palm, Inc. or its subsidiaries.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
/** @ingroup MiniImage
|
|
*
|
|
**/
|
|
|
|
/** @file Main.c
|
|
* This file is the main source file for MiniImage
|
|
**/
|
|
|
|
/** @name
|
|
*
|
|
**/
|
|
/*@{*/
|
|
|
|
#include <PalmOS.h>
|
|
#include <VFSMgr.h>
|
|
#include <PalmOneCodecPluginMgr.h>
|
|
#include <PalmOneCodecFormat.h>
|
|
|
|
#include "Common.h"
|
|
#include "MiniImage.h"
|
|
#include "MiniImageRsc.h"
|
|
#include "FileBrowserForm.h"
|
|
#include "FileBrowserFormRsrc.h"
|
|
|
|
#include "HsNav.h"
|
|
|
|
#define ourMinVersion sysMakeROMVersion(3,0,0,sysROMStageDevelopment,0)
|
|
#define kPalmOS20Version sysMakeROMVersion(2,0,0,sysROMStageDevelopment,0)
|
|
|
|
#define appErr 0x8001
|
|
#define gifErr 0x8002
|
|
|
|
#define BUFFER_SIZE (4096)
|
|
#define ALL_FORMATS 0x0001
|
|
#define TRACK_TIME (sysTicksPerSecond / 10)
|
|
|
|
/** Holds basic encoder/decoder info. */
|
|
typedef struct {
|
|
Char inputFileName[256];
|
|
Char outputFileName[256];
|
|
|
|
FileRef inputFileRef;
|
|
FileRef outputFileRef;
|
|
|
|
UInt32 width;
|
|
UInt32 height;
|
|
UInt32 rowBytes;
|
|
UInt32 colorFormat;
|
|
UInt32 fileFormat;
|
|
|
|
Boolean encoding;
|
|
Boolean fitToScreen;
|
|
|
|
PalmCodecSession session;
|
|
|
|
} ImageInfo;
|
|
|
|
#if 0
|
|
#pragma mark Globals
|
|
#endif
|
|
|
|
/** Internal Globals. */
|
|
static ImageInfo gImageInfo;
|
|
static UInt32 gScreenDepth = 16;
|
|
static UInt32 gPreviousScreenDepth = 0;
|
|
static UInt16 gCodecMgrLibRefNum = sysInvalidRefNum;
|
|
static Char *gRunButtonLabel[] = { "Decode", "Encode" };
|
|
static Char* gColorTableP;
|
|
|
|
/** Offscreen global. */
|
|
static WinHandle gWinH = NULL;
|
|
static Int16 gWinWidth = 0;
|
|
static Int16 gWinHeight = 0;
|
|
static Int16 gImageX = 0;
|
|
static Int16 gImageY = 0;
|
|
static Boolean gPanning = false;
|
|
|
|
/** Current image formats. */
|
|
static UInt32 *gCurrentColorFormatList = NULL;
|
|
static Char **gCurrentColorFormatTextList = NULL;
|
|
static UInt32 gCurrentColorFormatCount = 0;
|
|
static UInt32 gCurrentColorFormatSelection = 0;
|
|
|
|
/** Current file formats. */
|
|
static UInt32 gCurrentFileFormatSelection = 0;
|
|
|
|
/** List of supported format. */
|
|
static UInt32 gJPEGDecodeFormatCount = 0;
|
|
static UInt32 gJPEGDecodeFormat[20]; // I really don't expect more than 20
|
|
static UInt32 gJPEGEncodeFormatCount = 0;
|
|
static UInt32 gJPEGEncodeFormat[20];
|
|
static UInt32 gWBMPDecodeFormatCount = 0;
|
|
static UInt32 gWBMPDecodeFormat[20];
|
|
static UInt32 gWBMPEncodeFormatCount = 0;
|
|
static UInt32 gWBMPEncodeFormat[20];
|
|
static UInt32 gGIF87DecodeFormatCount = 0;
|
|
static UInt32 gGIF87DecodeFormat[20];
|
|
static UInt32 gGIF89DecodeFormatCount = 0;
|
|
static UInt32 gGIF89DecodeFormat[20];
|
|
static UInt32 gTIFFDecodeFormatCount = 0;
|
|
static UInt32 gTIFFDecodeFormat[20];
|
|
|
|
/** The list of all supported formats. */
|
|
static UInt32 gAllColorFormatSupportedCount = 0;
|
|
static UInt32 gAllColorFormatSupported[40];
|
|
|
|
/**
|
|
* List of known supported encoding format.
|
|
*/
|
|
static Char *gFileFormatTextList[] =
|
|
{
|
|
"JPEG File",
|
|
"WBMP File"
|
|
};
|
|
|
|
static UInt32 gFileFormatList[] =
|
|
{
|
|
palmCodecImageJPEGFile,
|
|
palmCodecImageWBMPFile
|
|
};
|
|
|
|
/**
|
|
* List of Image format
|
|
*/
|
|
static Char *gColorFormatList[] =
|
|
{
|
|
"ImageARGB32",
|
|
"ImageRGBA32",
|
|
"ImageRGB32",
|
|
"ImageRGB888",
|
|
"ImageRGB888Planar",
|
|
"ImageRGB565",
|
|
"ImageRGB555",
|
|
"ImageBGRA32",
|
|
"ImageBGR32",
|
|
"ImageBGR888",
|
|
"ImageBGR565",
|
|
"ImageBGR555",
|
|
"ImageYUV444",
|
|
"ImageYUV422",
|
|
"ImageYUV420",
|
|
"ImageYUV411",
|
|
"ImageYUV211",
|
|
"ImageYUV444Planar",
|
|
"ImageYUV422Planar",
|
|
"ImageYUV420Planar",
|
|
"ImageYUV411Planar",
|
|
"ImageYUV211Planar",
|
|
"ImageYCbCr444",
|
|
"ImageYCbCr422",
|
|
"ImageYCbCr420",
|
|
"ImageYCbCr411",
|
|
"ImageYCbCr211",
|
|
"ImageYCbCr444Planar",
|
|
"ImageYCbCr422Planar",
|
|
"ImageYCbCr420Planar",
|
|
"ImageYCbCr411Planar",
|
|
"ImageYCbCr211Planar",
|
|
"ImageRGBIndex16",
|
|
"ImageRGBIndex8",
|
|
"ImageRGBIndex4",
|
|
"ImageRGBIndex2",
|
|
"ImageRGBIndex1",
|
|
"ImageRGBIndex",
|
|
"ImageGRAY8",
|
|
"ImageGRAY4",
|
|
"ImageGRAY2",
|
|
"ImageGRAY1",
|
|
"ImageGIFFrame",
|
|
"ImageCMY",
|
|
"ImageCMYK",
|
|
"ImageHSL",
|
|
"ImageHSI",
|
|
"ImageHSV",
|
|
"ImageHCI"
|
|
};
|
|
|
|
static Err PrvFileOpenInput();
|
|
|
|
/**
|
|
* Mass byte-swapping - all elments must be 32 bits
|
|
*/
|
|
/*
|
|
static void PrvSwapStructure(UInt32 *structP, UInt32 numElement)
|
|
{
|
|
while(numElement--) {
|
|
*structP = Swap32(*structP);
|
|
structP++;
|
|
}
|
|
}
|
|
*/
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
|
|
/**
|
|
* Returns the file format from the file name.
|
|
*/
|
|
static UInt32 PrvGetFileFormat(const Char *fileName, FileRef fileRef)
|
|
{
|
|
Err err = errNone;
|
|
UInt8 buffer[64];
|
|
UInt32 bytesRead = 0;
|
|
UInt32 fileFormat = 0;
|
|
|
|
// Read a few bytes from the file
|
|
err = VFSFileRead(fileRef, 64, buffer, &bytesRead);
|
|
if(err || bytesRead < 16) goto Done;
|
|
|
|
// Check for JPEG
|
|
if( StrCaselessCompare(fileName + StrLen(fileName) - 4, ".jpg") == 0
|
|
|| StrCaselessCompare(fileName + StrLen(fileName) - 5, ".jpeg") == 0
|
|
|| StrCaselessCompare(fileName + StrLen(fileName) - 4, ".jpe") == 0 )
|
|
{
|
|
// Just make sure it's a JPEG - Check the SOI
|
|
if(buffer[0] == 0xFF && buffer[1] == 0xD8)
|
|
fileFormat = palmCodecImageJPEGFile;
|
|
}
|
|
else if( StrCaselessCompare(fileName + StrLen(fileName) - 4, ".tif") == 0
|
|
||StrCaselessCompare(fileName + StrLen(fileName) - 5, ".tiff") == 0 )
|
|
{
|
|
// Just make sure it's a TIFF - Check for II or MM for the first 2 bytes
|
|
if((buffer[0] == 'I' && buffer[1] == 'I') || (buffer[0] == 'M' && buffer[1] == 'M'))
|
|
fileFormat = palmCodecImageTIFFFile;
|
|
}
|
|
else if ( StrCaselessCompare(fileName + StrLen(fileName) - 4, ".bmp") == 0 )
|
|
{
|
|
// Just make sure it's a BMP - Check for BM
|
|
if(buffer[0] == 'B' && buffer[1] == 'M')
|
|
fileFormat = palmCodecImageWBMPFile;
|
|
}
|
|
else if ( StrCaselessCompare(fileName + StrLen(fileName) - 4, ".gif") == 0 )
|
|
{
|
|
// Just make sure it's a GIF - Check for GIF
|
|
if(buffer[0] == 'G' && buffer[1] == 'I' && buffer[2] == 'F' && buffer[3] == '8')
|
|
{
|
|
if(buffer[4] == '7' && buffer[5] == 'a')
|
|
fileFormat = palmCodecImageGIF87aFile;
|
|
else if(buffer[4] == '9' && buffer[5] == 'a')
|
|
fileFormat = palmCodecImageGIF89aFile;
|
|
}
|
|
}
|
|
|
|
Done:
|
|
return fileFormat;
|
|
}
|
|
|
|
/**
|
|
* Add a color format to the big list of supported color formats.
|
|
*/
|
|
static void PrvAddColorFormat(UInt32 colorFormat)
|
|
{
|
|
UInt32 count = gAllColorFormatSupportedCount;
|
|
|
|
while(count)
|
|
if(gAllColorFormatSupported[--count] == colorFormat)
|
|
break;
|
|
|
|
if(!count)
|
|
gAllColorFormatSupported[gAllColorFormatSupportedCount++] = colorFormat;
|
|
}
|
|
|
|
/**
|
|
* Load all supported image formats and their respective
|
|
* supported color formats. This list is only for the known
|
|
* formats.
|
|
*/
|
|
static Err PrvLoadFormats()
|
|
{
|
|
Err err = errNone;
|
|
UInt32 iterator = palmCodecIteratorStart;
|
|
PalmCodecFormat inputFormat, outputFormat;
|
|
UInt32 creatorID, codecID;
|
|
|
|
// Reset current state
|
|
gJPEGDecodeFormatCount = 0;
|
|
gJPEGEncodeFormatCount = 0;
|
|
gWBMPDecodeFormatCount = 0;
|
|
gWBMPEncodeFormatCount = 0;
|
|
gGIF87DecodeFormatCount = 0;
|
|
gGIF89DecodeFormatCount = 0;
|
|
gTIFFDecodeFormatCount = 0;
|
|
gAllColorFormatSupportedCount = 0;
|
|
|
|
// Enumerate all formats
|
|
while(iterator != palmCodecIteratorStop)
|
|
{
|
|
err = CodecMgrEnumerateFormats(gCodecMgrLibRefNum, &iterator, &inputFormat, &outputFormat, &creatorID, &codecID);
|
|
if(err) goto Done;
|
|
|
|
switch(inputFormat)
|
|
{
|
|
case palmCodecImageJPEGFile:
|
|
gJPEGDecodeFormat[gJPEGDecodeFormatCount] = outputFormat;
|
|
gJPEGDecodeFormatCount++;
|
|
break;
|
|
|
|
case palmCodecImageWBMPFile:
|
|
gWBMPDecodeFormat[gWBMPDecodeFormatCount] = outputFormat;
|
|
gWBMPDecodeFormatCount++;
|
|
break;
|
|
|
|
case palmCodecImageGIF87aFile:
|
|
gGIF87DecodeFormat[gGIF87DecodeFormatCount] = outputFormat;
|
|
gGIF87DecodeFormatCount++;
|
|
break;
|
|
|
|
case palmCodecImageGIF89aFile:
|
|
gGIF89DecodeFormat[gGIF89DecodeFormatCount] = outputFormat;
|
|
gGIF89DecodeFormatCount++;
|
|
break;
|
|
|
|
case palmCodecImageTIFFFile:
|
|
gTIFFDecodeFormat[gTIFFDecodeFormatCount] = outputFormat;
|
|
gTIFFDecodeFormatCount++;
|
|
break;
|
|
}
|
|
|
|
switch(outputFormat)
|
|
{
|
|
case palmCodecImageJPEGFile:
|
|
PrvAddColorFormat(inputFormat);
|
|
gJPEGEncodeFormat[gJPEGEncodeFormatCount] = inputFormat;
|
|
gJPEGEncodeFormatCount++;
|
|
break;
|
|
|
|
case palmCodecImageWBMPFile:
|
|
PrvAddColorFormat(inputFormat);
|
|
gWBMPEncodeFormat[gWBMPEncodeFormatCount] = inputFormat;
|
|
gWBMPEncodeFormatCount++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Done:
|
|
return errNone; // Ignore any errors
|
|
}
|
|
|
|
/**
|
|
* Set the text array for the Image formats
|
|
*/
|
|
static void PrvSetColorFormatList(UInt32 format)
|
|
{
|
|
UInt32 oldColor = 0;
|
|
UInt32 formatCount = 0;
|
|
UInt32 *formatList = NULL;
|
|
|
|
if(gCurrentColorFormatList)
|
|
oldColor = gCurrentColorFormatList[gCurrentColorFormatSelection];
|
|
|
|
switch(format)
|
|
{
|
|
case palmCodecImageJPEGFile:
|
|
if(gImageInfo.encoding) {
|
|
formatList = gJPEGEncodeFormat;
|
|
formatCount = gJPEGEncodeFormatCount;
|
|
} else {
|
|
formatList = gJPEGDecodeFormat;
|
|
formatCount = gJPEGDecodeFormatCount;
|
|
}
|
|
break;
|
|
|
|
case palmCodecImageWBMPFile:
|
|
if(gImageInfo.encoding) {
|
|
formatList = gWBMPEncodeFormat;
|
|
formatCount = gWBMPEncodeFormatCount;
|
|
} else {
|
|
formatList = gWBMPDecodeFormat;
|
|
formatCount = gWBMPDecodeFormatCount;
|
|
}
|
|
break;
|
|
|
|
case palmCodecImageGIF87aFile:
|
|
formatList = gGIF87DecodeFormat;
|
|
formatCount = gGIF87DecodeFormatCount;
|
|
break;
|
|
|
|
case palmCodecImageGIF89aFile:
|
|
formatList = gGIF89DecodeFormat;
|
|
formatCount = gGIF89DecodeFormatCount;
|
|
break;
|
|
|
|
case palmCodecImageTIFFFile:
|
|
formatList = gTIFFDecodeFormat;
|
|
formatCount = gTIFFDecodeFormatCount;
|
|
break;
|
|
|
|
case ALL_FORMATS:
|
|
formatList = gAllColorFormatSupported;
|
|
formatCount = gAllColorFormatSupportedCount;
|
|
break;
|
|
|
|
default:
|
|
formatList = NULL;
|
|
formatCount = 0;
|
|
break;
|
|
}
|
|
|
|
// Quick clean-up
|
|
if(gCurrentColorFormatTextList) {
|
|
MemPtrFree(gCurrentColorFormatTextList);
|
|
gCurrentColorFormatTextList = NULL;
|
|
gCurrentColorFormatList = 0;
|
|
gCurrentColorFormatCount = 0;
|
|
gCurrentColorFormatSelection = 0;
|
|
}
|
|
|
|
// Populate our list
|
|
gCurrentColorFormatList = formatList;
|
|
gCurrentColorFormatCount = formatCount;
|
|
|
|
if(formatList==NULL) return;
|
|
|
|
if(gCurrentColorFormatCount)
|
|
{
|
|
gCurrentColorFormatTextList = MemPtrNew(formatCount * sizeof(Char*));
|
|
MemSet(gCurrentColorFormatTextList, sizeof(UInt32) * formatCount, 0);
|
|
while(formatCount--) {
|
|
gCurrentColorFormatTextList[formatCount] = gColorFormatList[formatList[formatCount] - palmCodecImageBase];
|
|
if(oldColor == formatList[formatCount])
|
|
gCurrentColorFormatSelection = formatCount;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static void PrvSetOutputExtension(Char *fileName, UInt32 fileFormat)
|
|
{
|
|
UInt32 appendPosition = StrLen(fileName);
|
|
|
|
// Check for old extension
|
|
if(*(fileName + appendPosition - 4) == '.')
|
|
appendPosition -= 3;
|
|
else
|
|
fileName[appendPosition++] = '.';
|
|
|
|
switch(fileFormat)
|
|
{
|
|
case palmCodecImageJPEGFile:
|
|
StrCopy(fileName + appendPosition, "jpg");
|
|
break;
|
|
|
|
case palmCodecImageWBMPFile:
|
|
StrCopy(fileName + appendPosition, "bmp");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remember current UI settings
|
|
*/
|
|
static Err PrvSaveCurrentValues(FormType *frmP)
|
|
{
|
|
//Err err = errNone;
|
|
FieldType *fldP = NULL;
|
|
Char* s;
|
|
|
|
// Read the file names
|
|
fldP = FrmGetPtr(frmP, MainInputField);
|
|
StrCopy(gImageInfo.inputFileName, FldGetTextPtr(fldP));
|
|
fldP = FrmGetPtr(frmP, MainOutputField);
|
|
StrCopy(gImageInfo.outputFileName, FldGetTextPtr(fldP));
|
|
|
|
// Read the width and height
|
|
fldP = FrmGetPtr(frmP, MainWidthField);
|
|
s = FldGetTextPtr(fldP) ;
|
|
if( s )
|
|
gImageInfo.width = StrAToI(s);
|
|
fldP = FrmGetPtr(frmP, MainHeightField);
|
|
s = FldGetTextPtr(fldP) ;
|
|
if( s )
|
|
gImageInfo.height = StrAToI(s);
|
|
|
|
return errNone;
|
|
}
|
|
|
|
/**
|
|
* Set a field Editable
|
|
*/
|
|
/*
|
|
static inline void PrvSetFieldEditable(FormType *frmP, UInt16 ObjID)
|
|
{
|
|
FieldType *fldP = NULL;
|
|
FieldAttrType fldAttr;
|
|
|
|
fldP = FrmGetPtr(frmP, ObjID);
|
|
FldGetAttributes(fldP, &fldAttr);
|
|
fldAttr.editable = 1;
|
|
FldSetAttributes(fldP, &fldAttr);
|
|
}
|
|
*/
|
|
|
|
/*
|
|
*
|
|
* Set a field Not Editable
|
|
*/
|
|
|
|
/*
|
|
static inline void PrvSetFieldNotEditable(FormType *frmP, UInt16 ObjID)
|
|
{
|
|
FieldType *fldP = NULL;
|
|
FieldAttrType fldAttr;
|
|
|
|
fldP = FrmGetPtr(frmP, ObjID);
|
|
FldReleaseFocus(fldP);
|
|
FldGetAttributes(fldP, &fldAttr);
|
|
fldAttr.editable = 0;
|
|
FldSetAttributes(fldP, &fldAttr);
|
|
}
|
|
*/
|
|
|
|
/**
|
|
* Show/Hide Encode specific controls.
|
|
*/
|
|
static void PrvEncodeUI(FormType *frmP, Boolean encoding)
|
|
{
|
|
if(encoding) {
|
|
FrmShowObject(frmP, FrmGetObjectIndex(frmP, MainFileFormatLabel));
|
|
FrmShowObject(frmP, FrmGetObjectIndex(frmP, MainFileFormatPopTrigger));
|
|
} else {
|
|
FrmHideObject(frmP, FrmGetObjectIndex(frmP, MainFileFormatLabel));
|
|
FrmHideObject(frmP, FrmGetObjectIndex(frmP, MainFileFormatPopTrigger));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Refreshes the color format list
|
|
*/
|
|
static void PrvRefreshColorFormatList(FormType *frmP)
|
|
{
|
|
ListType *lstP = FrmGetPtr(frmP, MainColorFormatList);
|
|
ControlType *ctlP = FrmGetPtr(frmP, MainColorFormatPopTrigger);
|
|
|
|
if(gCurrentColorFormatTextList && gCurrentColorFormatCount) {
|
|
LstSetListChoices(lstP, gCurrentColorFormatTextList, gCurrentColorFormatCount);
|
|
LstSetHeight(lstP, gCurrentColorFormatCount);
|
|
LstSetSelection(lstP, gCurrentColorFormatSelection);
|
|
CtlSetLabel(ctlP, gCurrentColorFormatTextList[gCurrentColorFormatSelection]);
|
|
} else {
|
|
LstSetListChoices(lstP, NULL, 0);
|
|
LstSetHeight(lstP, 0);
|
|
CtlSetLabel(ctlP, "");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Refreshes the file format list
|
|
*/
|
|
static void PrvRefreshFileFormatList(FormType *frmP)
|
|
{
|
|
ListType *lstP = NULL;
|
|
ControlType *ctlP = NULL;
|
|
|
|
lstP = FrmGetPtr(frmP, MainFileFormatList);
|
|
LstSetListChoices(lstP, gFileFormatTextList, 2);
|
|
LstSetHeight(lstP, 2);
|
|
LstSetSelection(lstP, gCurrentFileFormatSelection);
|
|
ctlP = FrmGetPtr(frmP, MainFileFormatPopTrigger);
|
|
CtlSetLabel(ctlP, gFileFormatTextList[gCurrentFileFormatSelection]);
|
|
}
|
|
|
|
/**
|
|
* Switch settings to encoder.
|
|
*/
|
|
static void PrvSwitchToEncode(FormType *frmP)
|
|
{
|
|
FieldType *fldP = NULL;
|
|
ControlType *ctlP = NULL;
|
|
|
|
gImageInfo.encoding = true;
|
|
|
|
if(gImageInfo.fileFormat != palmCodecImageJPEGFile && gImageInfo.fileFormat != palmCodecImageWBMPFile)
|
|
gImageInfo.fileFormat = palmCodecImageJPEGFile;
|
|
|
|
gCurrentFileFormatSelection = (gImageInfo.fileFormat == palmCodecImageJPEGFile) ? 0 : 1;
|
|
|
|
|
|
// Show Encode UI
|
|
PrvEncodeUI(frmP, true);
|
|
ctlP = FrmGetPtr(frmP, MainRunButton);
|
|
CtlSetLabel(ctlP, gRunButtonLabel[1]);
|
|
|
|
// Set the Color formats
|
|
PrvSetColorFormatList(gImageInfo.fileFormat);
|
|
PrvRefreshColorFormatList(frmP);
|
|
PrvRefreshFileFormatList(frmP);
|
|
|
|
// Set the old output file name as input
|
|
StrCopy(gImageInfo.inputFileName, gImageInfo.outputFileName);
|
|
StrCopy(gImageInfo.outputFileName, "/default");
|
|
PrvSetOutputExtension(gImageInfo.outputFileName, gImageInfo.fileFormat);
|
|
fldP = FrmGetPtr(frmP, MainInputField);
|
|
SetFieldTextFromStr(fldP, gImageInfo.inputFileName, true);
|
|
fldP = FrmGetPtr(frmP, MainOutputField);
|
|
SetFieldTextFromStr(fldP, gImageInfo.outputFileName, true);
|
|
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
* Switch settings to decoder.
|
|
*/
|
|
static void PrvSwitchToDecode(FormType *frmP)
|
|
{
|
|
FieldType *fldP = NULL;
|
|
ControlType *ctlP = NULL;
|
|
Err err=errNone;
|
|
|
|
gImageInfo.encoding = false;
|
|
gCurrentFileFormatSelection = 0;
|
|
gCurrentColorFormatSelection = 0;
|
|
|
|
// Show Encode UI
|
|
PrvEncodeUI(frmP, false);
|
|
ctlP = FrmGetPtr(frmP, MainRunButton);
|
|
CtlSetLabel(ctlP, gRunButtonLabel[0]);
|
|
|
|
// Set the old output file name as input
|
|
StrCopy(gImageInfo.inputFileName, gImageInfo.outputFileName);
|
|
StrCopy(gImageInfo.outputFileName, "/default.raw");
|
|
|
|
err = PrvFileOpenInput();
|
|
if(err!=errNone) {
|
|
// Oops!
|
|
FrmCustomAlert(ErrorAlert, "Error opening Input file", NULL ,NULL);
|
|
}
|
|
|
|
fldP = FrmGetPtr(frmP, MainInputField);
|
|
SetFieldTextFromStr(fldP, gImageInfo.inputFileName, true);
|
|
fldP = FrmGetPtr(frmP, MainOutputField);
|
|
SetFieldTextFromStr(fldP, gImageInfo.outputFileName, true);
|
|
|
|
|
|
// Set the Color formats
|
|
if(*gImageInfo.inputFileName)
|
|
gImageInfo.fileFormat = PrvGetFileFormat(gImageInfo.inputFileName, gImageInfo.inputFileRef);
|
|
|
|
PrvSetColorFormatList(gImageInfo.fileFormat);
|
|
PrvRefreshColorFormatList(frmP);
|
|
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
|
|
/**
|
|
* Open input file
|
|
*/
|
|
static Err PrvFileOpenInput()
|
|
{
|
|
Err err = errNone;
|
|
UInt32 volumeIterator = 0;
|
|
UInt16 firstVolume = 0;
|
|
|
|
// Get first card
|
|
volumeIterator = vfsIteratorStart;
|
|
err = VFSVolumeEnumerate(&firstVolume, &volumeIterator);
|
|
if( err == expErrEnumerationEmpty ) {
|
|
goto Done;
|
|
}
|
|
|
|
// If we have a file path, open the file
|
|
if(*gImageInfo.inputFileName)
|
|
{
|
|
// Make sure old references are closed
|
|
if(gImageInfo.inputFileRef)
|
|
VFSFileClose(gImageInfo.inputFileRef);
|
|
|
|
err = VFSFileOpen(firstVolume, gImageInfo.inputFileName, vfsModeRead, &gImageInfo.inputFileRef);
|
|
if( err ) goto Done;
|
|
} else
|
|
err = -1;
|
|
|
|
Done:
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Open output file
|
|
*/
|
|
static Err PrvFileOpenOutput()
|
|
{
|
|
Err err = errNone;
|
|
UInt32 volumeIterator = 0;
|
|
UInt16 firstVolume = 0;
|
|
FieldType *fldP = NULL;
|
|
FormType *frmP = NULL;
|
|
|
|
// Get first card
|
|
volumeIterator = vfsIteratorStart;
|
|
err = VFSVolumeEnumerate(&firstVolume, &volumeIterator);
|
|
if( err == expErrEnumerationEmpty ) {
|
|
goto Done;
|
|
}
|
|
|
|
// Read the file name
|
|
frmP = FrmGetActiveForm();
|
|
fldP = FrmGetPtr(frmP, MainOutputField);
|
|
StrCopy( gImageInfo.outputFileName, FldGetTextPtr(fldP));
|
|
|
|
// If we have a file path, open the file
|
|
if(*gImageInfo.outputFileName)
|
|
{
|
|
// Make sure old references are closed
|
|
if(gImageInfo.outputFileRef)
|
|
VFSFileClose(gImageInfo.outputFileRef);
|
|
|
|
err = VFSFileOpen(firstVolume, gImageInfo.outputFileName, vfsModeWrite|vfsModeCreate|vfsModeTruncate, &gImageInfo.outputFileRef);
|
|
if( err ) goto Done;
|
|
} else
|
|
err = -1;
|
|
|
|
Done:
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
volume; //to supress CW warning
|
|
|
|
// Create the full path name
|
|
StrCopy(gImageInfo.inputFileName, path);
|
|
|
|
// Internally, we expect full path
|
|
StrCat(gImageInfo.inputFileName, file);
|
|
|
|
// Open the selected file
|
|
err = PrvFileOpenInput();
|
|
if(err) {
|
|
// Oops!
|
|
FrmCustomAlert(ErrorAlert, "Error opening Input file", NULL ,NULL);
|
|
} else {
|
|
// Parse input file
|
|
gImageInfo.fileFormat = PrvGetFileFormat(gImageInfo.inputFileName, gImageInfo.inputFileRef);
|
|
PrvSetColorFormatList(gImageInfo.fileFormat);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
|
|
/**
|
|
* Start the decoder.
|
|
* 1. Uses the file specified in the In File field.
|
|
* 2. Decodes using the specified Color Format.
|
|
* 3. Writes the RAW image to Out File.
|
|
* Notes: If Out File is empty, just decodes with no output file.
|
|
*/
|
|
static Err PrvRunDecoder()
|
|
{
|
|
Char text[32];
|
|
Err err = errNone;
|
|
UInt8 *bufferP = NULL;
|
|
UInt32 inSize = 0;
|
|
UInt32 outSize = 0;
|
|
UInt32 written = 0;
|
|
UInt32 decodeFormat = 0;
|
|
UInt32 colorBits = 8, colorTablesize = 0;
|
|
Boolean useOutFile = true;
|
|
FormType *frmP = FrmGetActiveForm();
|
|
PalmImageParamType *imageParamP = NULL;
|
|
PalmFileFormatParamType *fileParamP = NULL;
|
|
PalmImageINDEXParamType* indexImageParamP = NULL;
|
|
|
|
// Open the input file
|
|
err = PrvFileOpenInput();
|
|
if(err) {
|
|
FrmCustomAlert(ErrorAlert, "Cannot Open Input File !", NULL, NULL);
|
|
goto Done;
|
|
}
|
|
|
|
// We don't do GIF decoding here theres a seperate sample for that
|
|
if(gImageInfo.fileFormat == palmCodecImageGIF87aFile || gImageInfo.fileFormat == palmCodecImageGIF89aFile)
|
|
{
|
|
FrmCustomAlert(ErrorAlert, "This sample code doesn't handle GIF decoding !\nCheck MiniGIF for a better GIF sample.", NULL, NULL);
|
|
goto Done;
|
|
}
|
|
|
|
// Open output file
|
|
err = PrvFileOpenOutput();
|
|
if(err) useOutFile = false;
|
|
|
|
// Always use MemPtrNew, so that we are sure the pointers are 4 byte aligned
|
|
fileParamP = MemPtrNew(sizeof(PalmFileFormatParamType)) ;
|
|
imageParamP = MemPtrNew(sizeof(PalmImageParamType));
|
|
|
|
// Output Buffer needs to be allocated depending on the output format type
|
|
bufferP = MemPtrNew(BUFFER_SIZE);
|
|
|
|
if(!fileParamP || !imageParamP || !bufferP) {
|
|
FrmCustomAlert(ErrorAlert, "Not Enough Memory !", NULL, NULL);
|
|
goto Done;
|
|
}
|
|
|
|
// Set File parameters
|
|
fileParamP->fileLocationType = Swap32(palmCodecVFSFile);
|
|
fileParamP->vfsFileRef = Swap32(gImageInfo.inputFileRef);
|
|
|
|
// Get curent width and height
|
|
// Note: width=0 and height=0 means that you want the correct
|
|
// image size to be returned from the session creation.
|
|
gImageInfo.width = StrAToI(FldGetTextPtr(FrmGetPtr(frmP, MainWidthField)));
|
|
gImageInfo.height = StrAToI(FldGetTextPtr(FrmGetPtr(frmP, MainHeightField)));
|
|
|
|
// Set Image parameters - For the offscreen window we use BGR since it's native.
|
|
imageParamP->width = Swap32(gImageInfo.width);
|
|
imageParamP->height = Swap32(gImageInfo.width);
|
|
imageParamP->rowByte = Swap32(0);
|
|
imageParamP->endianess = Swap32(palmCodecLITTLE_ENDIAN);
|
|
decodeFormat = gCurrentColorFormatList[gCurrentColorFormatSelection];
|
|
|
|
// Create Session
|
|
err = CodecMgrCreateSession(gCodecMgrLibRefNum,
|
|
gImageInfo.fileFormat, fileParamP,
|
|
decodeFormat, imageParamP,
|
|
&gImageInfo.session);
|
|
|
|
if(err) {
|
|
FrmCustomAlert(ErrorAlert, "Unable to create codec session !", NULL, NULL);
|
|
goto Done;
|
|
}
|
|
|
|
// Get the width and height of the image sent back.
|
|
gImageInfo.width = Swap32(imageParamP->width);
|
|
gImageInfo.height = Swap32(imageParamP->height);
|
|
gImageInfo.rowBytes = Swap32(imageParamP->rowByte);
|
|
|
|
// Update the UI
|
|
StrIToA(text, gImageInfo.width);
|
|
SetFieldTextFromStr(FrmGetPtr(frmP, MainWidthField), text, true);
|
|
StrIToA(text, gImageInfo.height);
|
|
SetFieldTextFromStr(FrmGetPtr(frmP, MainHeightField), text, true);
|
|
|
|
// Check if we are decoding to a Indexed Image
|
|
if( decodeFormat == palmCodecImageRGBIndex1
|
|
||decodeFormat == palmCodecImageRGBIndex4
|
|
||decodeFormat == palmCodecImageRGBIndex8 )
|
|
{
|
|
|
|
indexImageParamP = MemPtrNew( sizeof( PalmImageINDEXParamType ));
|
|
if( !indexImageParamP )
|
|
goto Done;
|
|
|
|
if( decodeFormat == palmCodecImageRGBIndex1)
|
|
colorBits = 1;
|
|
else if ( decodeFormat == palmCodecImageRGBIndex4 )
|
|
colorBits = 4;
|
|
|
|
indexImageParamP->colorBits = Swap32(colorBits);
|
|
colorTablesize = 4 * (1<< colorBits);
|
|
indexImageParamP->colorTable = (UInt8*)(MemPtrNew(colorTablesize ));
|
|
|
|
if( !indexImageParamP->colorTable )
|
|
{
|
|
err = memErrNotEnoughSpace;
|
|
goto Done;
|
|
}
|
|
indexImageParamP->colorTable = (UInt8*)Swap32 ( (UInt32)indexImageParamP->colorTable);
|
|
indexImageParamP->imageDataP = (UInt8*)Swap32( (UInt32)bufferP );
|
|
|
|
}
|
|
|
|
|
|
// Decode the image
|
|
// Note: Windows Bitmap are decoded from bottom to top.
|
|
while(true)
|
|
{
|
|
// Set the size for the input and output
|
|
inSize = sizeof(PalmFileFormatParamType);
|
|
|
|
outSize = BUFFER_SIZE;
|
|
|
|
if( decodeFormat == palmCodecImageRGBIndex1
|
|
||decodeFormat == palmCodecImageRGBIndex4
|
|
||decodeFormat == palmCodecImageRGBIndex8 )
|
|
{
|
|
|
|
err = CodecMgrEncodeDecode(gCodecMgrLibRefNum,
|
|
gImageInfo.session, fileParamP, &inSize, indexImageParamP, &outSize);
|
|
|
|
}
|
|
else
|
|
{
|
|
err = CodecMgrEncodeDecode(gCodecMgrLibRefNum,
|
|
gImageInfo.session, fileParamP, &inSize, bufferP, &outSize);
|
|
}
|
|
|
|
// Write it to the card
|
|
if(!err && useOutFile)
|
|
err = VFSFileWrite(gImageInfo.outputFileRef, outSize, bufferP, &written);
|
|
|
|
// If no more to read
|
|
if(!inSize || err)
|
|
break;
|
|
}
|
|
|
|
|
|
// Color table needs to be saved if the raw file which was decoded needs to be
|
|
// used for testing encoding, else you can pass in your own color table while
|
|
// encoding the raw data, this sample just takes the decoded color table.
|
|
if( decodeFormat == palmCodecImageRGBIndex1
|
|
||decodeFormat == palmCodecImageRGBIndex4
|
|
||decodeFormat == palmCodecImageRGBIndex8 )
|
|
{
|
|
// If no error save color table for encoding.
|
|
gColorTableP = MemPtrNew( colorTablesize );
|
|
if( gColorTableP )
|
|
MemMove( gColorTableP, (void*)Swap32(indexImageParamP->colorTable) , colorTablesize );
|
|
else
|
|
err = memErrNotEnoughSpace;
|
|
}
|
|
|
|
Done:
|
|
|
|
// Always close a session when you are done.
|
|
if(gImageInfo.session)
|
|
{
|
|
CodecMgrDeleteSession(gCodecMgrLibRefNum, &gImageInfo.session);
|
|
|
|
if( !err )
|
|
FrmCustomAlert( InfoAlert, "Decoding done succesfully","","");
|
|
else
|
|
FrmCustomAlert( ErrorAlert, "Some errors encountered Decoding","","");
|
|
}
|
|
|
|
|
|
if(gImageInfo.inputFileRef) {
|
|
VFSFileClose(gImageInfo.inputFileRef);
|
|
gImageInfo.inputFileRef = NULL;
|
|
}
|
|
if(gImageInfo.outputFileRef) {
|
|
VFSFileClose(gImageInfo.outputFileRef);
|
|
gImageInfo.outputFileRef = NULL;
|
|
}
|
|
|
|
|
|
if(indexImageParamP)
|
|
{
|
|
indexImageParamP->imageDataP = NULL; // We are freeing bufferP
|
|
if( indexImageParamP->colorTable )
|
|
MemPtrFree( (void*)Swap32( indexImageParamP->colorTable ));
|
|
|
|
MemPtrFree( indexImageParamP);
|
|
}
|
|
|
|
if(fileParamP)
|
|
MemPtrFree(fileParamP);
|
|
if(imageParamP)
|
|
MemPtrFree(imageParamP);
|
|
if(bufferP)
|
|
MemPtrFree(bufferP);
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Decode the image for display.
|
|
*/
|
|
static Err PrvDecodeForDisplay()
|
|
{
|
|
Err err = errNone;
|
|
UInt32 inSize = 0;
|
|
UInt32 outSize = 0;
|
|
UInt8 *winBufferP = NULL;
|
|
UInt8 *winBufferEndP = NULL;
|
|
BitmapType *winBmpP = NULL;
|
|
PalmImageParamType *imageParamP = NULL;
|
|
PalmFileFormatParamType *fileParamP = NULL;
|
|
Char msg[50];
|
|
|
|
// Open the input file
|
|
err = PrvFileOpenInput();
|
|
if(err) {
|
|
FrmCustomAlert(ErrorAlert, "Cannot Open Input File !", NULL, NULL);
|
|
goto Done;
|
|
}
|
|
|
|
// We don't do GIF decoding here theres a seperate sample for that
|
|
if(gImageInfo.fileFormat == palmCodecImageGIF87aFile || gImageInfo.fileFormat == palmCodecImageGIF89aFile)
|
|
{
|
|
FrmCustomAlert(ErrorAlert, "This sample code doesn't handle GIF decoding !\nCheck MiniGIF for a better GIF sample.", NULL, NULL);
|
|
err = gifErr;
|
|
goto Done;
|
|
}
|
|
|
|
|
|
// Always use MemPtrNew, so that we are sure the pointers are 4 byte aligned
|
|
fileParamP = MemPtrNew(sizeof(PalmFileFormatParamType)) ;
|
|
imageParamP = MemPtrNew(sizeof(PalmImageParamType));
|
|
|
|
|
|
if(!fileParamP || !imageParamP ) {
|
|
FrmCustomAlert(ErrorAlert, "Not Enough Memory !", NULL, NULL);
|
|
goto Done;
|
|
}
|
|
|
|
// Set File parameters
|
|
fileParamP->fileLocationType = Swap32(palmCodecVFSFile);
|
|
fileParamP->vfsFileRef = (FileRef)Swap32(gImageInfo.inputFileRef);
|
|
|
|
// Set Image parameters - For the offscreen window we use BGR since it's native.
|
|
imageParamP->width = Swap32(gWinWidth);
|
|
imageParamP->height = Swap32(gWinHeight);
|
|
imageParamP->rowByte = Swap32(0);
|
|
imageParamP->endianess = Swap32(palmCodecLITTLE_ENDIAN);
|
|
|
|
// Create Session
|
|
err = CodecMgrCreateSession(gCodecMgrLibRefNum,
|
|
gImageInfo.fileFormat, fileParamP,
|
|
palmCodecImageBGR565, imageParamP,
|
|
&gImageInfo.session);
|
|
|
|
if(err) {
|
|
StrIToA(msg, err);
|
|
FrmCustomAlert(ErrorAlert, msg, NULL, NULL);
|
|
FrmCustomAlert(ErrorAlert, "Unable to create codec session !", NULL, NULL);
|
|
goto Done;
|
|
}
|
|
|
|
// Get the width and height of the image sent back
|
|
gWinWidth = Swap32(imageParamP->width);
|
|
gWinHeight = Swap32(imageParamP->height);
|
|
|
|
// Create offscreen window (+1 to get ceil value)
|
|
gWinH = WinCreateOffscreenWindow((gWinWidth+1) / 2, (gWinHeight+1) / 2, nativeFormat, &err);
|
|
if(err) {
|
|
FrmCustomAlert(ErrorAlert, "Not Enough Memory !", NULL, NULL);
|
|
goto Done;
|
|
}
|
|
|
|
// Get bits - Assume rowByte is always width * 2
|
|
winBmpP = WinGetBitmap(gWinH);
|
|
winBufferP = BmpGetBits(winBmpP);
|
|
winBufferEndP = winBufferP + (UInt32)(gWinWidth) * (UInt32)(gWinHeight) * 2;
|
|
|
|
// Decode the image
|
|
inSize = sizeof(PalmFileFormatParamType);
|
|
outSize = (UInt32)(gWinWidth) * (UInt32)(gWinHeight) * 2;
|
|
|
|
err = CodecMgrEncodeDecode(gCodecMgrLibRefNum,
|
|
gImageInfo.session, fileParamP, &inSize, winBufferP, &outSize);
|
|
|
|
if(gImageInfo.session)
|
|
CodecMgrDeleteSession(gCodecMgrLibRefNum, &gImageInfo.session);
|
|
|
|
Done:
|
|
|
|
if(gImageInfo.inputFileRef) {
|
|
VFSFileClose(gImageInfo.inputFileRef);
|
|
gImageInfo.inputFileRef = NULL;
|
|
}
|
|
if(gImageInfo.outputFileRef) {
|
|
VFSFileClose(gImageInfo.outputFileRef);
|
|
gImageInfo.outputFileRef = NULL;
|
|
}
|
|
|
|
if(fileParamP)
|
|
MemPtrFree(fileParamP);
|
|
if(imageParamP)
|
|
MemPtrFree(imageParamP);
|
|
|
|
return err;
|
|
}
|
|
|
|
static UInt32 PrvGetBytesPerPixel(UInt32 format)
|
|
{
|
|
switch(format)
|
|
{
|
|
case palmCodecImageARGB32:
|
|
case palmCodecImageRGBA32:
|
|
case palmCodecImageRGB32:
|
|
case palmCodecImageBGRA32:
|
|
case palmCodecImageBGR32:
|
|
return 4;
|
|
|
|
case palmCodecImageRGB888:
|
|
case palmCodecImageBGR888:
|
|
case palmCodecImageYUV444:
|
|
case palmCodecImageYCbCr444:
|
|
return 3;
|
|
|
|
case palmCodecImageRGB565:
|
|
case palmCodecImageRGB555:
|
|
case palmCodecImageBGR565:
|
|
case palmCodecImageBGR555:
|
|
case palmCodecImageYUV422:
|
|
case palmCodecImageYCbCr422:
|
|
return 2;
|
|
|
|
case palmCodecImageGRAY8:
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Start the encoder.
|
|
* 1. Uses the RAW image file specified in the In File field.
|
|
* 2. Encodes using the specified Color Format and File Format.
|
|
* 3. Writes the encoded image to Out File.
|
|
* Notes: If Out File is empty, just encodes with no output file.
|
|
* File Format and Color Format are inter-related. Changing
|
|
* one will affect the other.
|
|
* Make sure the width and height are correct.
|
|
*/
|
|
static void PrvRunEncoder()
|
|
{
|
|
Err err = errNone;
|
|
UInt8 *bufferP = NULL;
|
|
UInt32 inSize = 0;
|
|
UInt32 outSize = 0;
|
|
UInt32 read = 0;
|
|
UInt32 encodeFormat = 0;
|
|
UInt32 bytesPerPixels = 0;
|
|
UInt32 bufferSize = 0;
|
|
UInt32 colorBits = 8, colorTablesize = 0;
|
|
//Boolean useOutFile = true;
|
|
FormType *frmP = FrmGetActiveForm();
|
|
PalmImageParamType *imageParamP = NULL;
|
|
PalmFileFormatParamType *fileParamP = NULL;
|
|
PalmImageBMPParamType *bmpEncodeParamP = NULL;
|
|
PalmImageJPEGEncodeParamType *jpgEncodeParamP = NULL;
|
|
PalmImageINDEXParamType* indexImageParamP = NULL;
|
|
|
|
// Open the input file
|
|
err = PrvFileOpenInput();
|
|
if(err) {
|
|
FrmCustomAlert(ErrorAlert, "Cannot Open Input File !", NULL, NULL);
|
|
goto Done;
|
|
}
|
|
|
|
// Get the actual File name and Open output file
|
|
err = PrvFileOpenOutput();
|
|
|
|
// Always use MemPtrNew, so that we are sure the pointers are 4 byte aligned
|
|
fileParamP = MemPtrNew(sizeof(PalmFileFormatParamType)) ;
|
|
imageParamP = MemPtrNew(sizeof(PalmImageParamType));
|
|
jpgEncodeParamP = MemPtrNew(sizeof(PalmImageJPEGEncodeParamType));
|
|
bmpEncodeParamP = MemPtrNew(sizeof(PalmImageBMPParamType));
|
|
|
|
if(!fileParamP || !imageParamP || !jpgEncodeParamP || !bmpEncodeParamP) {
|
|
FrmCustomAlert(ErrorAlert, "Not Enough Memory !", NULL, NULL);
|
|
goto Done;
|
|
}
|
|
|
|
// Set File parameters
|
|
fileParamP->fileLocationType = Swap32(palmCodecVFSFile);
|
|
fileParamP->vfsFileRef = Swap32(gImageInfo.outputFileRef);
|
|
|
|
// Get curent width and height
|
|
// Note: width=0 and height=0 means that you want the correct
|
|
// image size to be returned from the session creation.
|
|
gImageInfo.width = StrAToI(FldGetTextPtr(FrmGetPtr(frmP, MainWidthField)));
|
|
gImageInfo.height = StrAToI(FldGetTextPtr(FrmGetPtr(frmP, MainHeightField)));
|
|
|
|
// Get teh number of bytes per pixels
|
|
encodeFormat = gCurrentColorFormatList[gCurrentColorFormatSelection];
|
|
bytesPerPixels = PrvGetBytesPerPixel(encodeFormat);
|
|
|
|
// Allocate the buffer
|
|
bufferSize = gImageInfo.rowBytes * 2;
|
|
bufferP = MemPtrNew(bufferSize);
|
|
if(!bufferP) {
|
|
FrmCustomAlert(ErrorAlert, "Not Enough Memory !", NULL, NULL);
|
|
goto Done;
|
|
}
|
|
|
|
// Set Image parameters
|
|
imageParamP->width = Swap32(gImageInfo.width);
|
|
imageParamP->height = Swap32(gImageInfo.height);
|
|
imageParamP->rowByte = Swap32(gImageInfo.rowBytes );
|
|
imageParamP->endianess = Swap32(palmCodecLITTLE_ENDIAN);
|
|
|
|
|
|
// Encode JPEG
|
|
if(gImageInfo.fileFormat == palmCodecImageJPEGFile)
|
|
{
|
|
jpgEncodeParamP->quality = Swap32(100);
|
|
jpgEncodeParamP->restartInterval = 0; /* ignored */
|
|
jpgEncodeParamP->JPEGMode = Swap32(0); /* baseline only */
|
|
jpgEncodeParamP->subSampling = 0; /* ignored */
|
|
|
|
// Create Session
|
|
err = CodecMgrCreateSession(gCodecMgrLibRefNum,
|
|
encodeFormat, imageParamP,
|
|
gImageInfo.fileFormat, jpgEncodeParamP,
|
|
&gImageInfo.session);
|
|
}
|
|
// Encode WBMP
|
|
else
|
|
{
|
|
|
|
if (encodeFormat == palmCodecImageRGBIndex8)
|
|
bmpEncodeParamP->compression = palmCodecBMP_RLE8;
|
|
else if (encodeFormat == palmCodecImageRGBIndex4)
|
|
bmpEncodeParamP->compression = palmCodecBMP_RLE4;
|
|
|
|
// Create Session
|
|
err = CodecMgrCreateSession(gCodecMgrLibRefNum,
|
|
encodeFormat, imageParamP,
|
|
gImageInfo.fileFormat, bmpEncodeParamP,
|
|
&gImageInfo.session);
|
|
}
|
|
|
|
if(err) {
|
|
FrmCustomAlert(ErrorAlert, "Unable to create codec session !", NULL, NULL);
|
|
goto Done;
|
|
}
|
|
|
|
// If its an IndexImage we are encoding ( currently only for BMP )
|
|
// Check if we are decoding to a Indexed Image
|
|
if( encodeFormat == palmCodecImageRGBIndex1
|
|
||encodeFormat == palmCodecImageRGBIndex4
|
|
||encodeFormat == palmCodecImageRGBIndex8 )
|
|
{
|
|
|
|
indexImageParamP = MemPtrNew( sizeof( PalmImageINDEXParamType ));
|
|
if( !indexImageParamP )
|
|
goto Done;
|
|
|
|
indexImageParamP->width = Swap32(gImageInfo.width);
|
|
indexImageParamP->height = Swap32(gImageInfo.height);;
|
|
indexImageParamP->rowByte = Swap32(gImageInfo.rowBytes);
|
|
indexImageParamP->endianess = 0;
|
|
if( encodeFormat == palmCodecImageRGBIndex1)
|
|
colorBits = 1;
|
|
else if ( encodeFormat == palmCodecImageRGBIndex4 )
|
|
colorBits = 4;
|
|
|
|
indexImageParamP->colorBits = Swap32(colorBits);
|
|
colorTablesize = 4 * (1<< colorBits);
|
|
indexImageParamP->colorTable = (UInt8*)(MemPtrNew(colorTablesize ));
|
|
|
|
if( !indexImageParamP->colorTable )
|
|
goto Done;
|
|
|
|
// The color table was saved during decoding
|
|
MemMove( indexImageParamP->colorTable, gColorTableP, colorTablesize );
|
|
|
|
indexImageParamP->colorTable = (UInt8*)Swap32 ( (UInt32)indexImageParamP->colorTable);
|
|
indexImageParamP->imageDataP = (UInt8*)Swap32( (UInt32)bufferP );
|
|
|
|
}
|
|
|
|
// Encode the image
|
|
outSize = sizeof(PalmFileFormatParamType);
|
|
|
|
while(true)
|
|
{
|
|
inSize = read;
|
|
|
|
// Write it to the card
|
|
err = VFSFileRead(gImageInfo.inputFileRef, bufferSize - inSize, bufferP + inSize, &read);
|
|
|
|
// Set the size for the input and output
|
|
inSize += read;
|
|
read = inSize;
|
|
|
|
if( encodeFormat == palmCodecImageRGBIndex1
|
|
||encodeFormat == palmCodecImageRGBIndex4
|
|
||encodeFormat == palmCodecImageRGBIndex8 )
|
|
{
|
|
err = CodecMgrEncodeDecode(gCodecMgrLibRefNum,
|
|
gImageInfo.session, indexImageParamP, &inSize, fileParamP, &outSize);
|
|
}
|
|
else
|
|
{
|
|
err = CodecMgrEncodeDecode(gCodecMgrLibRefNum,
|
|
gImageInfo.session, bufferP, &inSize, fileParamP, &outSize);
|
|
}
|
|
|
|
// If no more to read
|
|
if(!outSize || err)
|
|
break;
|
|
|
|
// Move leftover
|
|
read -= inSize;
|
|
MemMove(bufferP, bufferP + inSize, read);
|
|
}
|
|
|
|
|
|
Done:
|
|
|
|
// Do this first before you close the file, DeleteSession writes some
|
|
// into the file esp bmp headers.
|
|
if(gImageInfo.session)
|
|
{
|
|
CodecMgrDeleteSession(gCodecMgrLibRefNum, &gImageInfo.session);
|
|
|
|
if( !err )
|
|
FrmCustomAlert( InfoAlert, "Encoding done succesfully","","");
|
|
else
|
|
FrmCustomAlert( ErrorAlert, "Some errors encountered Encoding","","");
|
|
}
|
|
|
|
|
|
if(gImageInfo.inputFileRef) {
|
|
VFSFileClose(gImageInfo.inputFileRef);
|
|
gImageInfo.inputFileRef = NULL;
|
|
}
|
|
if(gImageInfo.outputFileRef) {
|
|
VFSFileClose(gImageInfo.outputFileRef);
|
|
gImageInfo.outputFileRef = NULL;
|
|
}
|
|
|
|
if(indexImageParamP)
|
|
{
|
|
indexImageParamP->imageDataP = NULL; // We are freeing bufferP
|
|
|
|
if( indexImageParamP->colorTable )
|
|
MemPtrFree( (void*)Swap32( indexImageParamP->colorTable ));
|
|
|
|
MemPtrFree( indexImageParamP);
|
|
|
|
}
|
|
|
|
if(fileParamP)
|
|
MemPtrFree(fileParamP);
|
|
if(imageParamP)
|
|
MemPtrFree(imageParamP);
|
|
if(bufferP)
|
|
MemPtrFree(bufferP);
|
|
if(bmpEncodeParamP)
|
|
MemPtrFree(bmpEncodeParamP);
|
|
if(jpgEncodeParamP)
|
|
MemPtrFree(jpgEncodeParamP);
|
|
if( gColorTableP )
|
|
{
|
|
MemPtrFree( gColorTableP );
|
|
gColorTableP = NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Display an image
|
|
*/
|
|
static void PrvDisplayImage()
|
|
{
|
|
Err err = errNone;
|
|
|
|
// Temp - Don't do anything in this case
|
|
if(gImageInfo.encoding)
|
|
return;
|
|
|
|
if(gImageInfo.fitToScreen)
|
|
WinGetDisplayExtent(&gWinWidth, &gWinHeight);
|
|
|
|
gWinWidth *= 2;
|
|
gWinHeight *= 2;
|
|
|
|
// Decode the image
|
|
err = PrvDecodeForDisplay();
|
|
if(err) {
|
|
// if(gWinH) WinDeleteWindow(gWinH, false);
|
|
// gWinH = NULL;
|
|
return;
|
|
}
|
|
|
|
// Display the offscreen window
|
|
FrmGotoForm(DisplayForm);
|
|
}
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
|
|
/**
|
|
* Initialize the display form
|
|
*/
|
|
static void DisplayFormInit()
|
|
{
|
|
Coord x, y;
|
|
RectangleType rect = { { 0, 0 }, { 0, 0 } };
|
|
|
|
gImageX = 0;
|
|
gImageY = 0;
|
|
|
|
// Check if we can pan in the image
|
|
if(gWinWidth > 320 || gWinHeight > 320)
|
|
gPanning = true;
|
|
else
|
|
gPanning = false;
|
|
|
|
// Image size
|
|
rect.extent.x = gWinWidth / 2;
|
|
if(rect.extent.x > 160) rect.extent.x = 160;
|
|
rect.extent.y = gWinHeight / 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;
|
|
|
|
// Display the capture image
|
|
WinCopyRectangle(gWinH, WinGetDisplayWindow(), &rect, x, y, winPaint);
|
|
}
|
|
|
|
/**
|
|
* Track teh pen and move the image
|
|
*/
|
|
static void PrvTrackPenDown(EventType *eventP)
|
|
{
|
|
UInt32 startTick = TimGetTicks();
|
|
Int16 oldX, oldY, newX, newY;
|
|
Boolean penIsDown = eventP->penDown;
|
|
oldX = eventP->screenX;
|
|
oldY = eventP->screenY;
|
|
|
|
while(penIsDown)
|
|
{
|
|
EvtGetPen(&newX, &newY, &penIsDown);
|
|
|
|
if(newX == oldX && newY == oldY)
|
|
continue;
|
|
|
|
gImageX += (oldX - newX);
|
|
gImageY += (oldY - newY);
|
|
|
|
if(gImageX < 0) gImageX = 0;
|
|
if(gImageX > (gWinWidth / 2 - 160)) gImageX = gWinWidth / 2 - 160;
|
|
if(gImageY < 0) gImageY = 0;
|
|
if(gImageY > (gWinHeight / 2 - 160)) gImageY = gWinHeight / 2 - 160;
|
|
|
|
// If panning is enabled
|
|
if(gPanning) {
|
|
RectangleType rect = { { 0, 0 }, { 160, 160 } };
|
|
|
|
// Image Coord
|
|
rect.topLeft.x = gImageX;
|
|
rect.topLeft.y = gImageY;
|
|
|
|
// Display the capture image
|
|
WinCopyRectangle(gWinH, WinGetDisplayWindow(), &rect, 0, 0, winPaint);
|
|
}
|
|
|
|
oldX = newX;
|
|
oldY = newY;
|
|
}
|
|
|
|
if(TimGetTicks() - startTick < TRACK_TIME) {
|
|
FrmGotoForm(MainForm);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* FUNCTION: PrvHandleMenu
|
|
*
|
|
* DESCRIPTION: Deals with menu commands issued
|
|
*
|
|
* PARAMETERS: itemID -> ID of the Menu which has been selected
|
|
*
|
|
* RETURNED: Nothing
|
|
*
|
|
* REVISION HISTORY:
|
|
*
|
|
*
|
|
***********************************************************************/
|
|
|
|
static void PrvHandleMenu(UInt16 itemID)
|
|
{
|
|
//Err err = errNone;
|
|
FormType *frmAboutP = NULL;
|
|
const RGBColorType black = { 0, 0, 0 ,0 };
|
|
const RGBColorType white = { 0, 255, 255 ,255 };
|
|
const RectangleType currentColorRect = { {27, 142}, { 19, 17} };
|
|
|
|
|
|
switch(itemID)
|
|
{
|
|
case HelpAboutMiniImage:
|
|
frmAboutP = FrmInitForm(AboutForm);
|
|
FrmDoDialog(frmAboutP); // Display the About Box.
|
|
FrmDeleteForm(frmAboutP);
|
|
|
|
WinSetForeColorRGB(&white, NULL);
|
|
WinSetTextColorRGB(&black, NULL);
|
|
WinDrawRectangle(¤tColorRect, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* DisplayFormHandleEvent
|
|
*/
|
|
static Boolean DisplayFormHandleEvent(EventType *eventP)
|
|
{
|
|
//Err err = errNone;
|
|
Boolean handled = false;
|
|
FormType *frmP = FrmGetActiveForm();
|
|
|
|
switch(eventP->eType)
|
|
{
|
|
case frmOpenEvent:
|
|
FrmDrawForm(frmP);
|
|
DisplayFormInit();
|
|
handled = true;
|
|
break;
|
|
|
|
case frmCloseEvent:
|
|
if(gWinH) WinDeleteWindow(gWinH, false);
|
|
break;
|
|
|
|
case penDownEvent:
|
|
PrvTrackPenDown(eventP);
|
|
handled = true;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
|
|
/**
|
|
* Initialize the form
|
|
*/
|
|
static void MainFormInit(FormType *frmP)
|
|
{
|
|
Char text[32];
|
|
FieldType *fldP = NULL;
|
|
ControlType *ctlP = NULL;
|
|
|
|
// Set files
|
|
fldP = FrmGetPtr(frmP, MainInputField);
|
|
SetFieldTextFromStr(fldP, gImageInfo.inputFileName, false);
|
|
fldP = FrmGetPtr(frmP, MainOutputField);
|
|
SetFieldTextFromStr(fldP, gImageInfo.outputFileName, false);
|
|
|
|
// Set the current mode
|
|
if(gImageInfo.encoding) {
|
|
ctlP = FrmGetPtr(frmP, MainEncodePushButton);
|
|
CtlSetValue(ctlP, true);
|
|
ctlP = FrmGetPtr(frmP, MainRunButton);
|
|
CtlSetLabel(ctlP, gRunButtonLabel[1]);
|
|
PrvEncodeUI(frmP, true);
|
|
} else {
|
|
ctlP = FrmGetPtr(frmP, MainDecodePushButton);
|
|
CtlSetValue(ctlP, true);
|
|
ctlP = FrmGetPtr(frmP, MainRunButton);
|
|
CtlSetLabel(ctlP, gRunButtonLabel[0]);
|
|
|
|
if(gImageInfo.width)
|
|
StrIToA(text, gImageInfo.width);
|
|
else
|
|
StrCopy(text, "MAX");
|
|
SetFieldTextFromStr(FrmGetPtr(frmP, MainWidthField), text, true);
|
|
if(gImageInfo.height)
|
|
StrIToA(text, gImageInfo.height);
|
|
else
|
|
StrCopy(text, "MAX");
|
|
SetFieldTextFromStr(FrmGetPtr(frmP, MainHeightField), text, true);
|
|
}
|
|
|
|
// Fit to Screen
|
|
ctlP = FrmGetPtr(frmP, MainFitToScreenCheckbox);
|
|
CtlSetValue(ctlP, gImageInfo.fitToScreen);
|
|
|
|
// Populate the Color formats
|
|
PrvRefreshColorFormatList(frmP);
|
|
PrvRefreshFileFormatList(frmP);
|
|
}
|
|
|
|
/**
|
|
* MainFormHandleEvent
|
|
*/
|
|
static Boolean MainFormHandleEvent(EventType * eventP)
|
|
{
|
|
Boolean handled = false;
|
|
//ControlType *ctlP = NULL;
|
|
FormType *frmP = FrmGetActiveForm();
|
|
|
|
switch(eventP->eType)
|
|
{
|
|
case frmOpenEvent:
|
|
MainFormInit(frmP);
|
|
|
|
// Make sure empty text field is added to navigation order and set focus to encode button
|
|
FrmSetNavEntry(frmP, MainInputField, MainEncodePushButton, MainEncodePushButton, MainDisplayButton, 0);
|
|
//Setting focus on MainDisplayButton
|
|
FrmNavObjectTakeFocus(frmP, MainDisplayButton);
|
|
FrmDrawForm(frmP);
|
|
handled = true;
|
|
break;
|
|
|
|
case frmUpdateEvent:
|
|
break;
|
|
|
|
case frmCloseEvent:
|
|
PrvSaveCurrentValues(frmP);
|
|
break;
|
|
|
|
case popSelectEvent:
|
|
switch(eventP->data.popSelect.controlID)
|
|
{
|
|
case MainColorFormatPopTrigger:
|
|
gCurrentColorFormatSelection = eventP->data.popSelect.selection;
|
|
gImageInfo.colorFormat = gCurrentColorFormatList[gCurrentColorFormatSelection];
|
|
break;
|
|
|
|
case MainFileFormatPopTrigger:
|
|
gCurrentFileFormatSelection = eventP->data.popSelect.selection;
|
|
gImageInfo.fileFormat = gFileFormatList[gCurrentFileFormatSelection];
|
|
PrvSetColorFormatList(gImageInfo.fileFormat);
|
|
PrvRefreshColorFormatList(frmP);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case ctlSelectEvent:
|
|
switch(eventP->data.ctlSelect.controlID)
|
|
{
|
|
case MainInputGraphicButton:
|
|
// Sets the callback function and return form
|
|
FileBrowserSetCallback(&PrvGetInputFileInfoCallback, MainForm);
|
|
FrmGotoForm(FileBrowserForm);
|
|
handled = true;
|
|
break;
|
|
|
|
case MainDisplayButton:
|
|
PrvDisplayImage();
|
|
handled = true;
|
|
break;
|
|
|
|
case MainRunButton:
|
|
if(gImageInfo.encoding)
|
|
PrvRunEncoder();
|
|
else
|
|
PrvRunDecoder();
|
|
handled = true;
|
|
break;
|
|
|
|
case MainDecodePushButton:
|
|
if(gImageInfo.encoding)
|
|
PrvSwitchToDecode(frmP);
|
|
break;
|
|
|
|
case MainEncodePushButton:
|
|
if(!gImageInfo.encoding)
|
|
PrvSwitchToEncode(frmP);
|
|
break;
|
|
|
|
case MainFitToScreenCheckbox:
|
|
gImageInfo.fitToScreen = eventP->data.ctlSelect.on;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case menuEvent:
|
|
PrvHandleMenu(eventP->data.menu.itemID);
|
|
FrmDrawForm(frmP);
|
|
handled = true;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
|
|
/**
|
|
* 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:
|
|
FrmNavObjectTakeFocus(frmP, MainDecodePushButton);
|
|
FrmSetEventHandler(frmP, MainFormHandleEvent);
|
|
break;
|
|
|
|
case DisplayForm:
|
|
FrmNavObjectTakeFocus(frmP, MainDecodePushButton);
|
|
FrmSetEventHandler(frmP, DisplayFormHandleEvent);
|
|
break;
|
|
|
|
case FileBrowserForm:
|
|
FrmSetEventHandler(frmP, FileBrowserFormHandleEvent);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* AppEventLoop
|
|
*/
|
|
static void AppEventLoop(void)
|
|
{
|
|
UInt16 error = errNone;
|
|
EventType event;
|
|
|
|
do
|
|
{
|
|
EvtGetEvent(&event, evtWaitForever);
|
|
|
|
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(&gImageInfo, sizeof(ImageInfo), 0);
|
|
|
|
// Try to find the hardware utils library
|
|
err = SysLibFind(kCodecMgrLibName, &gCodecMgrLibRefNum);
|
|
if(err != errNone)
|
|
err = SysLibLoad(kCodecMgrLibType, kCodecMgrLibCreator, &gCodecMgrLibRefNum);
|
|
|
|
if(err == errNone)
|
|
err = CodecMgrOpen(gCodecMgrLibRefNum);
|
|
|
|
if(err) {
|
|
FrmAlert(NoCPMLibAlert);
|
|
goto Done;
|
|
}
|
|
|
|
// Load known formats
|
|
PrvLoadFormats();
|
|
|
|
// Set default values
|
|
gImageInfo.inputFileRef = NULL;
|
|
gImageInfo.outputFileRef = NULL;
|
|
gImageInfo.session = NULL;
|
|
|
|
gImageInfo.width = 0;
|
|
gImageInfo.height = 0;
|
|
gImageInfo.fitToScreen = true;
|
|
gImageInfo.encoding = false;
|
|
|
|
StrCopy(gImageInfo.outputFileName, "/default.raw");
|
|
|
|
// 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 files
|
|
if(gImageInfo.inputFileRef)
|
|
VFSFileClose(gImageInfo.inputFileRef);
|
|
if(gImageInfo.outputFileRef)
|
|
VFSFileClose(gImageInfo.outputFileRef);
|
|
|
|
// Close the library
|
|
if(gCodecMgrLibRefNum != sysInvalidRefNum)
|
|
{
|
|
err = CodecMgrClose(gCodecMgrLibRefNum);
|
|
if (err == errNone)
|
|
err = SysLibRemove(gCodecMgrLibRefNum);
|
|
}
|
|
|
|
// Restore previous color mode
|
|
WinScreenMode(winScreenModeSet, NULL, NULL, &gPreviousScreenDepth, NULL);
|
|
|
|
// Clean memory
|
|
if( gColorTableP )
|
|
MemPtrFree( gColorTableP );
|
|
|
|
if(gCurrentColorFormatTextList)
|
|
MemPtrFree(gCurrentColorFormatTextList);
|
|
|
|
|
|
}
|
|
|
|
#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;
|
|
cmdPBP; //to supress CW warning
|
|
|
|
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;
|
|
}
|
|
|
|
return errNone;
|
|
}
|
|
|
|
#pragma warn_a5_access reset
|
|
|
|
|
|
/*@}*/
|