mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-16 12:30:13 +01:00
2650 lines
67 KiB
C++
2650 lines
67 KiB
C++
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||
|
*
|
||
|
* ***** BEGIN LICENSE BLOCK *****
|
||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||
|
*
|
||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||
|
* the License. You may obtain a copy of the License at
|
||
|
* http://www.mozilla.org/MPL/
|
||
|
*
|
||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||
|
* for the specific language governing rights and limitations under the
|
||
|
* License.
|
||
|
*
|
||
|
* The Original Code is mozilla.org Code.
|
||
|
*
|
||
|
* The Initial Developer of the Original Code is
|
||
|
* Netscape Communications Corporation.
|
||
|
* Portions created by the Initial Developer are Copyright (C) 2001
|
||
|
* the Initial Developer. All Rights Reserved.
|
||
|
*
|
||
|
* Contributor(s):
|
||
|
*
|
||
|
* Alternatively, the contents of this file may be used under the terms of
|
||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||
|
* of those above. If you wish to allow use of your version of this file only
|
||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||
|
* use your version of this file under the terms of the MPL, indicate your
|
||
|
* decision by deleting the provisions above and replace them with the notice
|
||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||
|
* the provisions above, a recipient may use your version of this file under
|
||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||
|
*
|
||
|
* ***** END LICENSE BLOCK ***** */
|
||
|
/*
|
||
|
* Implements the nsSanePluginInterface for the SANE plugin
|
||
|
*/
|
||
|
|
||
|
#include <unistd.h>
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <errno.h>
|
||
|
#include <setjmp.h>
|
||
|
#include <gdk/gdk.h>
|
||
|
#include <gdk/gdkprivate.h>
|
||
|
#include <gtk/gtk.h>
|
||
|
#include <sys/mman.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include "nsIIOService.h"
|
||
|
#include "nsSanePlugin.h"
|
||
|
#include "plstr.h"
|
||
|
#include "prmem.h"
|
||
|
#include "nsIEventQueueService.h"
|
||
|
#include "nsIEventQueue.h"
|
||
|
|
||
|
extern "C"
|
||
|
{
|
||
|
#include "jpeglib.h"
|
||
|
#include "sane/sane.h"
|
||
|
#include "sane/sanei.h"
|
||
|
#include "sane/saneopts.h"
|
||
|
}
|
||
|
|
||
|
#define MAX_OPT_SIZE (1024 * 2)
|
||
|
|
||
|
struct my_JPEG_error_mgr
|
||
|
{
|
||
|
struct jpeg_error_mgr pub;
|
||
|
sigjmp_buf setjmp_buffer;
|
||
|
};
|
||
|
typedef struct my_JPEG_error_mgr *emptr;
|
||
|
|
||
|
static void PR_CALLBACK ThreadedDestroyEvent(PLEvent* aEvent);
|
||
|
static void PR_CALLBACK ThreadedHandleEvent(PLEvent* aEvent);
|
||
|
|
||
|
//static void PR_CALLBACK scanimage_thread_routine( void * arg );
|
||
|
|
||
|
static void store_filename(GtkFileSelection *selector, gpointer user_data);
|
||
|
static nsresult optioncat( char ** dest, const char * src,
|
||
|
const char * ending );
|
||
|
static void my_jpeg_error_exit (j_common_ptr cinfo);
|
||
|
static unsigned char* jpeg_file_to_rgb (FILE * f, int *w, int *h);
|
||
|
static gboolean draw (GtkWidget *widget, GdkEventExpose *event, gpointer data);
|
||
|
static unsigned char * crop_image(unsigned char *rgb_data, int *rgb_width,
|
||
|
int *rgb_height, gint x, gint y,
|
||
|
gint w, gint h);
|
||
|
static unsigned char * scale_image(unsigned char *rgb_data, int rgb_width,
|
||
|
int rgb_height, int w, int h);
|
||
|
|
||
|
static PRInt32 gPluginObjectCount = 0;
|
||
|
|
||
|
static NS_DEFINE_CID(kCPluginManagerCID, NS_PLUGINMANAGER_CID );
|
||
|
static NS_DEFINE_CID(kEventQueueService, NS_EVENTQUEUESERVICE_CID );
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// Plugin Instance API Methods
|
||
|
|
||
|
nsSanePluginInstance::nsSanePluginInstance( void )
|
||
|
: fPeer( NULL ), fWindow( NULL ), fMode( nsPluginMode_Embedded )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginInstance::nsSanePluginInstance()\n");
|
||
|
#endif
|
||
|
|
||
|
PR_AtomicIncrement(&gPluginObjectCount);
|
||
|
|
||
|
// set default jpeg compression attributes
|
||
|
mCompQuality = 10;
|
||
|
mCompMethod = JDCT_FASTEST;
|
||
|
|
||
|
// Initialize sane interface
|
||
|
mSaneDevice = nsnull;
|
||
|
mSaneOpen = SANE_FALSE;
|
||
|
mRGBData = nsnull;
|
||
|
mBottomRightXChange = mBottomRightYChange =
|
||
|
mTopLeftXChange = mTopLeftYChange = 0;
|
||
|
|
||
|
// initialize JavaScript callback members
|
||
|
mOnScanCompleteScript = nsnull;
|
||
|
mOnInitCompleteScript = nsnull;
|
||
|
mScanThread = nsnull;
|
||
|
mUIThread = PR_GetCurrentThread();
|
||
|
|
||
|
mState = 0; // idle
|
||
|
mSuccess = 1; // success
|
||
|
mFileSelection = nsnull;
|
||
|
|
||
|
// initialize gtk widgets
|
||
|
fPlatform.widget = nsnull;
|
||
|
mEvent_box = nsnull;
|
||
|
mDrawing_area = nsnull;
|
||
|
|
||
|
if (NS_FAILED(CallCreateInstance(kCPluginManagerCID, &mPluginManager))) {
|
||
|
NS_ERROR("Error trying to create plugin manager!");
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
nsSanePluginInstance::~nsSanePluginInstance(void)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginInstance::~nsSanePluginInstance(%i)\n",
|
||
|
gPluginObjectCount );
|
||
|
#endif
|
||
|
|
||
|
PR_AtomicDecrement(&gPluginObjectCount);
|
||
|
PlatformDestroy(); // Perform platform specific cleanup
|
||
|
|
||
|
if (mPluginManager) {
|
||
|
mPluginManager->Release();
|
||
|
mPluginManager = nsnull;
|
||
|
}
|
||
|
|
||
|
sane_exit();
|
||
|
|
||
|
// cleanup old widgets
|
||
|
if (fPlatform.widget)
|
||
|
gtk_widget_destroy(fPlatform.widget);
|
||
|
if (mEvent_box)
|
||
|
gtk_widget_destroy(mEvent_box);
|
||
|
if (mDrawing_area)
|
||
|
gtk_widget_destroy(mDrawing_area);
|
||
|
|
||
|
NS_IF_RELEASE(fPeer);
|
||
|
PR_FREEIF(mSaneDevice);
|
||
|
PR_FREEIF(mOnScanCompleteScript);
|
||
|
PR_FREEIF(mOnInitCompleteScript);
|
||
|
|
||
|
}
|
||
|
|
||
|
// This macro produces simple versions of QueryInterface, AddRef and Release
|
||
|
// See the nsISupports.h header file for details.
|
||
|
NS_IMPL_ISUPPORTS2(nsSanePluginInstance,
|
||
|
nsIPluginInstance,
|
||
|
nsISanePluginInstance)
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginInstance::Initialize( nsIPluginInstancePeer* peer )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginInstance::Initialize()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(peer != NULL, "null peer");
|
||
|
|
||
|
nsIPluginTagInfo * taginfo;
|
||
|
const char * const * names = nsnull;
|
||
|
const char * const * values = nsnull;
|
||
|
PRUint16 count = 0;
|
||
|
nsresult result;
|
||
|
|
||
|
gdk_rgb_init();
|
||
|
|
||
|
fPeer = peer;
|
||
|
peer->AddRef();
|
||
|
result = peer->GetMode( &fMode );
|
||
|
|
||
|
if ( NS_FAILED( result ) )
|
||
|
return result;
|
||
|
|
||
|
result = peer->QueryInterface( nsIPluginTagInfo::GetIID(),
|
||
|
( void ** )&taginfo );
|
||
|
|
||
|
if ( NS_SUCCEEDED( result ) )
|
||
|
{
|
||
|
taginfo->GetAttributes( count, names, values );
|
||
|
NS_IF_RELEASE( taginfo );
|
||
|
}
|
||
|
|
||
|
// Initialize default line attribute info
|
||
|
mLineWidth = 5;
|
||
|
mLineStyle = GDK_LINE_ON_OFF_DASH;
|
||
|
mCapStyle = GDK_CAP_BUTT;
|
||
|
mJoinStyle = GDK_JOIN_MITER;
|
||
|
|
||
|
// Get user requested attribute info
|
||
|
for (int i=0; i < count; i++) {
|
||
|
|
||
|
if (PL_strcasecmp(names[i], "line_width") == 0) {
|
||
|
//////////////
|
||
|
// Line width
|
||
|
sscanf(values[i], "%i", &mLineWidth);
|
||
|
|
||
|
} else if (PL_strcasecmp(names[i], "line_style") == 0) {
|
||
|
//////////////
|
||
|
// Line style
|
||
|
if (PL_strcasecmp(values[i], "dash") == 0)
|
||
|
mLineStyle = GDK_LINE_ON_OFF_DASH;
|
||
|
else if (PL_strcasecmp(values[i], "solid") == 0)
|
||
|
mLineStyle = GDK_LINE_SOLID;
|
||
|
else if (PL_strcasecmp(values[i], "double_dash") == 0)
|
||
|
mLineStyle = GDK_LINE_DOUBLE_DASH;
|
||
|
|
||
|
} else if (PL_strcasecmp(names[i], "cap_style") == 0) {
|
||
|
/////////////
|
||
|
// Cap style
|
||
|
if (PL_strcasecmp(values[i], "round") == 0)
|
||
|
mCapStyle = GDK_CAP_ROUND;
|
||
|
else if (PL_strcasecmp(values[i], "projecting") == 0)
|
||
|
mCapStyle = GDK_CAP_PROJECTING;
|
||
|
else if (PL_strcasecmp(values[i], "butt") == 0)
|
||
|
mCapStyle = GDK_CAP_BUTT;
|
||
|
else if (PL_strcasecmp(values[i], "not_last") == 0)
|
||
|
mCapStyle = GDK_CAP_NOT_LAST;
|
||
|
|
||
|
} else if (PL_strcasecmp(names[i], "join_style") == 0) {
|
||
|
//////////////
|
||
|
// Join style
|
||
|
if (PL_strcasecmp(values[i], "miter") == 0)
|
||
|
mJoinStyle = GDK_JOIN_MITER;
|
||
|
else if (PL_strcasecmp(values[i], "round") == 0)
|
||
|
mJoinStyle = GDK_JOIN_ROUND;
|
||
|
else if (PL_strcasecmp(values[i], "bevel") == 0)
|
||
|
mJoinStyle = GDK_JOIN_BEVEL;
|
||
|
|
||
|
} else if (PL_strcasecmp(names[i], "device") == 0) {
|
||
|
//////////
|
||
|
// Device
|
||
|
PR_FREEIF(mSaneDevice);
|
||
|
mSaneDevice = PL_strdup(values[i]);
|
||
|
} else if (PL_strcasecmp(names[i], "onScanComplete") == 0) {
|
||
|
//////////////////////////
|
||
|
// onScanComplete Callback
|
||
|
PR_FREEIF(mOnScanCompleteScript);
|
||
|
mOnScanCompleteScript = PL_strdup(values[i]);
|
||
|
} else if(PL_strcasecmp(names[i], "onInitComplete") == 0) {
|
||
|
//////////////////////////
|
||
|
// onInitComplete Callback
|
||
|
PR_FREEIF(mOnInitCompleteScript);
|
||
|
mOnInitCompleteScript = PL_strdup(values[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// the mImageFilename is used to store data directly
|
||
|
// from the sane device and also rendering to the screen
|
||
|
sprintf( mImageFilename, "/tmp/nsSanePlugin.%p.jpg", (void *)this );
|
||
|
|
||
|
PlatformNew(); /* Call Platform-specific initializations */
|
||
|
return NS_OK;
|
||
|
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginInstance::SaveImage()
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginInstance::SaveImage()\n");
|
||
|
#endif
|
||
|
|
||
|
if (!mImageFilename) {
|
||
|
NS_ERROR("Attempt to save image before initial scan!");
|
||
|
return NS_ERROR_FAILURE;
|
||
|
}
|
||
|
|
||
|
mFileSelection = gtk_file_selection_new("Choose file to save image to.");
|
||
|
|
||
|
// Set a default filename
|
||
|
gtk_file_selection_set_filename(GTK_FILE_SELECTION(mFileSelection),
|
||
|
"saved.jpg");
|
||
|
|
||
|
// Callback for getting the filename
|
||
|
gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(mFileSelection)->ok_button),
|
||
|
"clicked", GTK_SIGNAL_FUNC (store_filename),
|
||
|
(gpointer) this);
|
||
|
|
||
|
// Ensure the file selection dialog goes away after
|
||
|
// 'OK' or 'CANCEL' button is selected
|
||
|
gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(mFileSelection)->ok_button),
|
||
|
"clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
|
||
|
GTK_OBJECT(mFileSelection));
|
||
|
gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(mFileSelection)->cancel_button),
|
||
|
"clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
|
||
|
GTK_OBJECT(mFileSelection));
|
||
|
|
||
|
// ok, now show the file selection dialog
|
||
|
gtk_widget_show(mFileSelection);
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginInstance::DoScanCompleteCallback()
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginInstance::DoScanCompleteCallback()\n");
|
||
|
#endif
|
||
|
|
||
|
char *url;
|
||
|
|
||
|
if (mOnScanCompleteScript && mPluginManager) {
|
||
|
url = (char *)PR_Malloc(PL_strlen(mOnScanCompleteScript) + 13);
|
||
|
if (!url)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
|
||
|
sprintf(url, "javascript:%s", mOnScanCompleteScript);
|
||
|
mPluginManager->GetURL((nsIPluginInstance *)this, url, "_self");
|
||
|
|
||
|
PR_FREEIF(url);
|
||
|
}
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginInstance::DoInitCompleteCallback()
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginInstance::DoInitCompleteCallback()\n");
|
||
|
#endif
|
||
|
|
||
|
char *url;
|
||
|
|
||
|
if (mOnInitCompleteScript && mPluginManager) {
|
||
|
url = (char *)PR_Malloc(PL_strlen(mOnInitCompleteScript) + 13);
|
||
|
if (!url)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
|
||
|
sprintf(url, "javascript:%s", mOnInitCompleteScript);
|
||
|
mPluginManager->GetURL((nsIPluginInstance *)this, url, "_self");
|
||
|
|
||
|
PR_FREEIF(url);
|
||
|
}
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginInstance::GetPeer( nsIPluginInstancePeer* *result )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginInstance::GetPeer()\n");
|
||
|
#endif
|
||
|
|
||
|
fPeer->AddRef();
|
||
|
*result = fPeer;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginInstance::Start( void )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginInstance::Start()\n");
|
||
|
#endif
|
||
|
|
||
|
PR_FREEIF(mRGBData);
|
||
|
mRGBData = nsnull;
|
||
|
|
||
|
sane_init(0,0);
|
||
|
mSaneOpen = SANE_FALSE;
|
||
|
nsresult rv = OpenSaneDeviceIF();
|
||
|
if (rv != NS_OK) {
|
||
|
NS_ERROR("Failed to open device in Start()\n");
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
PlatformNew();
|
||
|
|
||
|
// call onInitComplete callback
|
||
|
DoInitCompleteCallback();
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginInstance::Stop( void )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginInstance::Stop()\n");
|
||
|
#endif
|
||
|
|
||
|
// Wait for scanner operation to complete.
|
||
|
// TODO: Warn user that they are still scanning
|
||
|
// and send abort command to scanner if
|
||
|
// the user wishes.
|
||
|
if (mScanThread)
|
||
|
PR_JoinThread(mScanThread);
|
||
|
|
||
|
PR_FREEIF(mRGBData);
|
||
|
|
||
|
// close sane
|
||
|
if (mSaneOpen) {
|
||
|
sane_close(mSaneHandle);
|
||
|
sane_exit();
|
||
|
mSaneOpen = SANE_FALSE;
|
||
|
}
|
||
|
|
||
|
if (remove ( mImageFilename ) == -1)
|
||
|
perror(mImageFilename);
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginInstance::Destroy( void )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginInstance::Destroy()\n");
|
||
|
#endif
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginInstance::SetWindow(nsPluginWindow* window)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginInstance::SetWindow()\n");
|
||
|
#endif
|
||
|
|
||
|
nsresult result;
|
||
|
|
||
|
// The real work is handled in PlatformSetWindow
|
||
|
// (as if this plug-in was multiplatform)
|
||
|
result = PlatformSetWindow( window );
|
||
|
fWindow = window;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginInstance::NewStream( nsIPluginStreamListener** listener )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginInstance::NewStream()\n");
|
||
|
#endif
|
||
|
|
||
|
if ( listener != NULL )
|
||
|
*listener = new nsSanePluginStreamListener( this );
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginInstance::Print( nsPluginPrint* printInfo )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginInstance::Print()\n");
|
||
|
#endif
|
||
|
|
||
|
if ( printInfo == NULL )
|
||
|
return NS_ERROR_FAILURE;
|
||
|
|
||
|
// needs to be implemented
|
||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginInstance::HandleEvent(nsPluginEvent* event, PRBool* handled)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginInstance::HandleEvent()\n");
|
||
|
#endif
|
||
|
|
||
|
// Not used on unix platform. Only here for potential
|
||
|
// future porting efforts
|
||
|
*handled = (PRBool)PlatformHandleEvent(event);
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginInstance::GetValue(nsPluginInstanceVariable variable, void *value)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginInstance::GetValue()\n");
|
||
|
#endif
|
||
|
|
||
|
//Needs to be implemented
|
||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsSanePluginInstance::PlatformNew( void )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::PlatformNew\n");
|
||
|
#endif
|
||
|
|
||
|
fPlatform.window = 0;
|
||
|
}
|
||
|
|
||
|
nsresult
|
||
|
nsSanePluginInstance::PlatformDestroy( void )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::PlatformDestroy()\n");
|
||
|
#endif
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
nsresult
|
||
|
nsSanePluginInstance::PlatformSetWindow( nsPluginWindow* window )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::PlatformSetWindow()\n");
|
||
|
#endif
|
||
|
|
||
|
|
||
|
if ( window == NULL || window->window == NULL )
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
if ( fPlatform.superwin == (GdkSuperWin *)window->window )
|
||
|
return NS_OK;
|
||
|
|
||
|
// Record windowing info
|
||
|
fPlatform.superwin = (GdkSuperWin *)window->window;
|
||
|
fPlatform.height = window->height;
|
||
|
fPlatform.width = window->width;
|
||
|
|
||
|
// cleanup old widgets
|
||
|
if (fPlatform.widget)
|
||
|
gtk_widget_destroy(fPlatform.widget);
|
||
|
if (mEvent_box)
|
||
|
gtk_widget_destroy(mEvent_box);
|
||
|
if (mDrawing_area)
|
||
|
gtk_widget_destroy(mDrawing_area);
|
||
|
|
||
|
fPlatform.widget = gtk_mozbox_new(fPlatform.superwin->bin_window);
|
||
|
|
||
|
// Initialize the zoom box to outline the entire image
|
||
|
mZoom_box.x = 0;
|
||
|
mZoom_box.y = 0;
|
||
|
mZoom_box.width = fPlatform.width;
|
||
|
mZoom_box.height = fPlatform.height;
|
||
|
|
||
|
// Setup an event box to contain the drawable
|
||
|
mEvent_box = gtk_event_box_new();
|
||
|
gtk_container_add(GTK_CONTAINER(fPlatform.widget), mEvent_box);
|
||
|
gtk_widget_show(mEvent_box);
|
||
|
|
||
|
// Setup the drawable
|
||
|
mDrawing_area = ( GtkWidget * )gtk_drawing_area_new();
|
||
|
gtk_drawing_area_size( GTK_DRAWING_AREA( mDrawing_area ),
|
||
|
window->width, window->height);
|
||
|
gtk_container_add(GTK_CONTAINER(mEvent_box), mDrawing_area);
|
||
|
gtk_widget_show(mDrawing_area);
|
||
|
|
||
|
// Initialize line attributes for GC
|
||
|
GdkGC * da_gc = mDrawing_area->style->fg_gc[mDrawing_area->state];
|
||
|
gdk_gc_set_line_attributes ( da_gc, mLineWidth, mLineStyle,
|
||
|
mCapStyle, mJoinStyle);
|
||
|
|
||
|
// Register signals
|
||
|
gtk_signal_connect (GTK_OBJECT(mDrawing_area), "expose_event",
|
||
|
GTK_SIGNAL_FUNC(draw), this);
|
||
|
|
||
|
// Now make everything visable
|
||
|
gtk_widget_show( fPlatform.widget );
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
int16
|
||
|
nsSanePluginInstance::PlatformHandleEvent(nsPluginEvent* event)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::PlatformHandleEvent()\n");
|
||
|
#endif
|
||
|
|
||
|
/* UNIX Plugins do not use HandleEvent */
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::PaintImage(void)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::PaintImage(%p)\n", this);
|
||
|
#endif
|
||
|
|
||
|
if (mDrawing_area && fPlatform.widget) {
|
||
|
if (mImageFilename) {
|
||
|
|
||
|
if (!mRGBData) {
|
||
|
|
||
|
if (mState)
|
||
|
// we are currently scanning, so the jpeg file
|
||
|
// is not valid yet
|
||
|
return NS_OK;
|
||
|
|
||
|
FILE * f = fopen(mImageFilename, "rb");
|
||
|
if (!f)
|
||
|
// it's possible that an image hasn't been scanned yet
|
||
|
return NS_OK;
|
||
|
|
||
|
mRGBData = jpeg_file_to_rgb(f, &mRGBWidth, &mRGBHeight);
|
||
|
if (!mRGBData) {
|
||
|
NS_ERROR("Error converting jpeg to rgb data!");
|
||
|
return NS_ERROR_FAILURE;
|
||
|
}
|
||
|
|
||
|
fclose(f);
|
||
|
|
||
|
// scale down to window size
|
||
|
unsigned char * tmp = scale_image( mRGBData,
|
||
|
mRGBWidth, mRGBHeight,
|
||
|
fPlatform.width,
|
||
|
fPlatform.height);
|
||
|
if (!tmp) {
|
||
|
NS_ERROR("Error trying to scale image!");
|
||
|
return NS_ERROR_FAILURE;
|
||
|
}
|
||
|
|
||
|
// move to new data
|
||
|
PR_FREEIF(mRGBData);
|
||
|
mRGBData = tmp;
|
||
|
}
|
||
|
|
||
|
// render the image
|
||
|
gdk_draw_rgb_image (mDrawing_area->window,
|
||
|
mDrawing_area->style->fg_gc[GTK_STATE_NORMAL],
|
||
|
0, 0, fPlatform.width, fPlatform.height,
|
||
|
GDK_RGB_DITHER_MAX, mRGBData,
|
||
|
fPlatform.width * 3);
|
||
|
|
||
|
gdk_draw_rectangle (mDrawing_area->window,
|
||
|
mDrawing_area->style->fg_gc[mDrawing_area->state],
|
||
|
FALSE, mZoom_box.x, mZoom_box.y,
|
||
|
mZoom_box.width, mZoom_box.height);
|
||
|
|
||
|
gdk_flush();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
nsSanePluginInstance::GetImageFilename()
|
||
|
{
|
||
|
if (!mImageFilename)
|
||
|
return (char *)NULL;
|
||
|
|
||
|
// Caller is responsible for freeing string
|
||
|
return PL_strdup(mImageFilename);
|
||
|
}
|
||
|
|
||
|
GtkWidget *
|
||
|
nsSanePluginInstance::GetFileSelection()
|
||
|
{
|
||
|
if (!mFileSelection)
|
||
|
return (GtkWidget *)NULL;
|
||
|
|
||
|
return mFileSelection;
|
||
|
}
|
||
|
|
||
|
PRBool
|
||
|
nsSanePluginInstance::IsUIThread()
|
||
|
{
|
||
|
if (!mUIThread)
|
||
|
return PR_FALSE;
|
||
|
|
||
|
return (mUIThread == PR_GetCurrentThread());
|
||
|
}
|
||
|
|
||
|
// End of Plugin Instance API Methods.
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
// Image Preview Interface.
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::ZoomImage( PRUint16 x, PRUint16 y,
|
||
|
PRUint16 width, PRUint16 height)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::ZoomImage()\n");
|
||
|
#endif
|
||
|
|
||
|
int im_width, im_height, c_width, c_height, c_x, c_y;
|
||
|
|
||
|
if (!mRGBData)
|
||
|
return NS_ERROR_FAILURE;
|
||
|
|
||
|
// get the actual image width and height
|
||
|
im_width = mRGBWidth;
|
||
|
im_height = mRGBHeight;
|
||
|
|
||
|
if ( x >= (PRUint16)fPlatform.width ||
|
||
|
y >= (PRUint16)fPlatform.height )
|
||
|
return NS_ERROR_FAILURE;
|
||
|
|
||
|
if ( width + mZoom_box.x >= (PRUint16)fPlatform.width )
|
||
|
mZoom_box.width = fPlatform.width - mZoom_box.x;
|
||
|
|
||
|
if ( height + mZoom_box.y >= (PRUint16) fPlatform.height )
|
||
|
mZoom_box.height = fPlatform.height - mZoom_box.y;
|
||
|
|
||
|
mZoom_box.x = x;
|
||
|
mZoom_box.y = y;
|
||
|
|
||
|
// translate the zoom box geometry to the image geometry
|
||
|
c_width = (int)(((double)im_width/(double)fPlatform.width) *
|
||
|
(double)mZoom_box.width);
|
||
|
c_height =(int)(((double)im_height/(double)fPlatform.height) *
|
||
|
(double)mZoom_box.height);
|
||
|
c_x = (int)(((double)im_width/(double)fPlatform.width) *
|
||
|
(double)mZoom_box.x);
|
||
|
c_y = (int)(((double)im_height/(double)fPlatform.height) *
|
||
|
(double)mZoom_box.y);
|
||
|
|
||
|
unsigned char * tmp = crop_image(mRGBData, &mRGBWidth, &mRGBHeight,
|
||
|
c_x, c_y, c_width, c_height);
|
||
|
if (!tmp)
|
||
|
return NS_ERROR_FAILURE;
|
||
|
PR_FREEIF(mRGBData);
|
||
|
mRGBData = tmp;
|
||
|
|
||
|
mRGBWidth = c_width;
|
||
|
mRGBHeight = c_height;
|
||
|
|
||
|
mTopLeftXChange = (float)x/(float)fPlatform.width;
|
||
|
mTopLeftYChange = (float)y/(float)fPlatform.height;
|
||
|
mBottomRightXChange = (float)(fPlatform.width - (PRInt32)(x + mZoom_box.width))/(float)fPlatform.width;
|
||
|
mBottomRightYChange = (float)(fPlatform.height - (PRInt32)(y + mZoom_box.height))/(float)fPlatform.height;
|
||
|
|
||
|
mZoom_box.x = 0;
|
||
|
mZoom_box.y = 0;
|
||
|
mZoom_box.width = (PRUint16)fPlatform.width;
|
||
|
mZoom_box.height = (PRUint16)fPlatform.height;
|
||
|
|
||
|
return PaintImage();
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::ZoomImageWithAttributes( PRUint16 x, PRUint16 y,
|
||
|
PRUint16 width, PRUint16 height,
|
||
|
PRInt32 req_line_width,
|
||
|
const char * req_line_style,
|
||
|
const char * req_cap_style,
|
||
|
const char * req_join_style )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::ZoomImageWithAttributes()\n");
|
||
|
#endif
|
||
|
|
||
|
if (!mRGBData)
|
||
|
return NS_ERROR_FAILURE;
|
||
|
|
||
|
ZoomImage(x, y, width, height);
|
||
|
|
||
|
/*
|
||
|
* Set zoom box line attributes
|
||
|
*/
|
||
|
|
||
|
// Line Width
|
||
|
mLineWidth = req_line_width;
|
||
|
|
||
|
// Line Style
|
||
|
if (PL_strcasecmp(req_line_style, "dash") == 0)
|
||
|
mLineStyle = GDK_LINE_ON_OFF_DASH;
|
||
|
else if (PL_strcasecmp(req_line_style, "solid") == 0)
|
||
|
mLineStyle = GDK_LINE_SOLID;
|
||
|
else if (PL_strcasecmp(req_line_style, "double_dash") == 0)
|
||
|
mLineStyle = GDK_LINE_DOUBLE_DASH;
|
||
|
|
||
|
// Cap Style
|
||
|
if (PL_strcasecmp(req_cap_style, "round") == 0)
|
||
|
mCapStyle = GDK_CAP_ROUND;
|
||
|
else if (PL_strcasecmp(req_cap_style, "projecting") == 0)
|
||
|
mCapStyle = GDK_CAP_PROJECTING;
|
||
|
else if (PL_strcasecmp(req_cap_style, "butt") == 0)
|
||
|
mCapStyle = GDK_CAP_BUTT;
|
||
|
else if (PL_strcasecmp(req_cap_style, "not_last") == 0)
|
||
|
mCapStyle = GDK_CAP_NOT_LAST;
|
||
|
|
||
|
// Join Style
|
||
|
if (PL_strcasecmp(req_join_style, "miter") == 0)
|
||
|
mJoinStyle = GDK_JOIN_MITER;
|
||
|
else if (PL_strcasecmp(req_join_style, "round") == 0)
|
||
|
mJoinStyle = GDK_JOIN_ROUND;
|
||
|
else if (PL_strcasecmp(req_join_style, "bevel") == 0)
|
||
|
mJoinStyle = GDK_JOIN_BEVEL;
|
||
|
|
||
|
// Refresh
|
||
|
return PaintImage();
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::Crop(PRUint16 x, PRUint16 y,
|
||
|
PRUint16 width, PRUint16 height)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::Crop()\n");
|
||
|
#endif
|
||
|
|
||
|
if ( (x <= (PRUint16)fPlatform.width - width ) &&
|
||
|
(y <= (PRUint16)fPlatform.height - height) ) {
|
||
|
|
||
|
mZoom_box.x = x; mZoom_box.y = y;
|
||
|
mZoom_box.width = width;
|
||
|
mZoom_box.height = height;
|
||
|
|
||
|
} else {
|
||
|
return NS_ERROR_FAILURE;
|
||
|
}
|
||
|
|
||
|
return PaintImage();
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::Restore(void)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::Restore()\n");
|
||
|
#endif
|
||
|
|
||
|
PR_FREEIF(mRGBData);
|
||
|
mRGBData = nsnull;
|
||
|
|
||
|
// Reset zoom box
|
||
|
mZoom_box.x = mZoom_box.y = 0;
|
||
|
mZoom_box.width = (PRUint16) fPlatform.width;
|
||
|
mZoom_box.height = (PRUint16) fPlatform.height;
|
||
|
|
||
|
PaintImage();
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetZoomX(PRUint16 * x)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetZoomX()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(x != NULL, "null x pointer");
|
||
|
if (!x)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
*x = mZoom_box.x;
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetZoomX(PRUint16 x)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetZoomX()\n");
|
||
|
#endif
|
||
|
|
||
|
if (x > (PRInt32) fPlatform.width)
|
||
|
mZoom_box.x = (PRInt32) fPlatform.width;
|
||
|
else
|
||
|
mZoom_box.x = x;
|
||
|
|
||
|
return PaintImage();
|
||
|
}
|
||
|
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetZoomY(PRUint16 * y)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetZoomY()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(y != NULL, "null y pointer");
|
||
|
if (!y)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
*y = mZoom_box.y;
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetZoomY(PRUint16 y)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetZoomY()\n");
|
||
|
#endif
|
||
|
|
||
|
if (y > (PRInt32) fPlatform.height)
|
||
|
mZoom_box.y = (PRInt32)fPlatform.height;
|
||
|
else
|
||
|
mZoom_box.y = y;
|
||
|
|
||
|
return PaintImage();
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetZoomWidth(PRUint16 * width)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetZoomWidth()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(width != NULL, "null width pointer");
|
||
|
if (!width)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
*width = mZoom_box.width;
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetZoomWidth(PRUint16 width)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetZoomWidth()\n");
|
||
|
#endif
|
||
|
|
||
|
if (width + mZoom_box.x > (PRUint16)fPlatform.width)
|
||
|
mZoom_box.width = (PRInt32) fPlatform.width - mZoom_box.x;
|
||
|
else
|
||
|
mZoom_box.width = width;
|
||
|
|
||
|
return PaintImage();
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetZoomHeight(PRUint16 * height)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetZoomHeight()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(height != NULL, "null height pointer");
|
||
|
if (!height)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
*height = mZoom_box.height;
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetZoomHeight(PRUint16 height)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetZoomHeight()\n");
|
||
|
#endif
|
||
|
|
||
|
if (height + mZoom_box.y > (PRUint16) fPlatform.height)
|
||
|
mZoom_box.height = fPlatform.height - mZoom_box.y;
|
||
|
else
|
||
|
mZoom_box.height = height;
|
||
|
|
||
|
return PaintImage();
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetZoomLineWidth(PRInt32 * aZoomLineWidth)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetZoomLineWidth()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(aZoomLineWidth != NULL, "null width pointer");
|
||
|
if (!aZoomLineWidth)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
*aZoomLineWidth = mLineWidth;
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetZoomLineWidth(PRInt32 aZoomLineWidth)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetZoomLineWidth()\n");
|
||
|
#endif
|
||
|
|
||
|
if (aZoomLineWidth <= 0)
|
||
|
return NS_ERROR_INVALID_ARG;
|
||
|
|
||
|
mLineWidth = aZoomLineWidth;
|
||
|
|
||
|
return PaintImage();
|
||
|
}
|
||
|
|
||
|
#define MAX_LINE_ATTRIBUTE_LENGTH 20
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetZoomLineStyle(char ** aZoomLineStyle)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetZoomLineStyle()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(*aZoomLineStyle != NULL, "null width pointer");
|
||
|
if (!*aZoomLineStyle)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
*aZoomLineStyle = (char*) nsMemory::Alloc(MAX_LINE_ATTRIBUTE_LENGTH);
|
||
|
if (! *aZoomLineStyle)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
|
||
|
if (mLineStyle == GDK_LINE_ON_OFF_DASH)
|
||
|
PL_strcpy(*aZoomLineStyle, "dash");
|
||
|
else if (mLineStyle == GDK_LINE_SOLID)
|
||
|
PL_strcpy(*aZoomLineStyle, "solid");
|
||
|
else if (mLineStyle == GDK_LINE_DOUBLE_DASH)
|
||
|
PL_strcpy(*aZoomLineStyle, "double_dash");
|
||
|
else
|
||
|
PL_strcpy(*aZoomLineStyle, "unknown");
|
||
|
|
||
|
return PaintImage();
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetZoomLineStyle(const char * aZoomLineStyle)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetZoomLineStyle()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(aZoomLineStyle != NULL, "null width pointer");
|
||
|
if (!aZoomLineStyle)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
// Line Style
|
||
|
if (PL_strcasecmp(aZoomLineStyle, "dash") == 0)
|
||
|
mLineStyle = GDK_LINE_ON_OFF_DASH;
|
||
|
else if (PL_strcasecmp(aZoomLineStyle, "solid") == 0)
|
||
|
mLineStyle = GDK_LINE_SOLID;
|
||
|
else if (PL_strcasecmp(aZoomLineStyle, "double_dash") == 0)
|
||
|
mLineStyle = GDK_LINE_DOUBLE_DASH;
|
||
|
|
||
|
return PaintImage();
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetZoomCapStyle(char ** aZoomCapStyle)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetZoomCapStyle()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(*aZoomCapStyle != NULL, "null width pointer");
|
||
|
if (!*aZoomCapStyle)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
*aZoomCapStyle = (char*) nsMemory::Alloc(MAX_LINE_ATTRIBUTE_LENGTH);
|
||
|
if (! *aZoomCapStyle)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
|
||
|
if (mCapStyle == GDK_CAP_ROUND)
|
||
|
PL_strcpy(*aZoomCapStyle, "round");
|
||
|
else if (mCapStyle == GDK_CAP_PROJECTING)
|
||
|
PL_strcpy(*aZoomCapStyle, "projecting");
|
||
|
else if (mCapStyle == GDK_CAP_BUTT)
|
||
|
PL_strcpy(*aZoomCapStyle, "butt");
|
||
|
else if (mCapStyle == GDK_CAP_NOT_LAST)
|
||
|
PL_strcpy(*aZoomCapStyle, "not_last");
|
||
|
else
|
||
|
PL_strcpy(*aZoomCapStyle, "unknown");
|
||
|
|
||
|
|
||
|
return PaintImage();
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetZoomCapStyle(const char * aZoomCapStyle)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetZoomCapStyle()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(aZoomCapStyle != NULL, "null width pointer");
|
||
|
if (!aZoomCapStyle)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
// Cap Style
|
||
|
if (PL_strcasecmp(aZoomCapStyle, "round") == 0)
|
||
|
mCapStyle = GDK_CAP_ROUND;
|
||
|
else if (PL_strcasecmp(aZoomCapStyle, "projecting") == 0)
|
||
|
mCapStyle = GDK_CAP_PROJECTING;
|
||
|
else if (PL_strcasecmp(aZoomCapStyle, "butt") == 0)
|
||
|
mCapStyle = GDK_CAP_BUTT;
|
||
|
else if (PL_strcasecmp(aZoomCapStyle, "not_last") == 0)
|
||
|
mCapStyle = GDK_CAP_NOT_LAST;
|
||
|
|
||
|
return PaintImage();
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetZoomJoinStyle(char ** aZoomJoinStyle)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetZoomJoinStyle()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(*aZoomJoinStyle != NULL, "null width pointer");
|
||
|
if (!*aZoomJoinStyle)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
*aZoomJoinStyle = (char*) nsMemory::Alloc(MAX_LINE_ATTRIBUTE_LENGTH);
|
||
|
if (! *aZoomJoinStyle)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
|
||
|
if (mJoinStyle == GDK_JOIN_MITER)
|
||
|
PL_strcpy(*aZoomJoinStyle, "miter");
|
||
|
else if (mJoinStyle == GDK_JOIN_ROUND)
|
||
|
PL_strcpy(*aZoomJoinStyle, "round");
|
||
|
else if (mJoinStyle == GDK_JOIN_BEVEL)
|
||
|
PL_strcpy(*aZoomJoinStyle, "bevel");
|
||
|
else
|
||
|
PL_strcpy(*aZoomJoinStyle, "unknown");
|
||
|
|
||
|
return PaintImage();
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetZoomJoinStyle(const char * aZoomJoinStyle)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetZoomJoinStyle()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(aZoomJoinStyle != NULL, "null width pointer");
|
||
|
if (!aZoomJoinStyle)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
// Join Style
|
||
|
if (PL_strcasecmp(aZoomJoinStyle, "miter") == 0)
|
||
|
mJoinStyle = GDK_JOIN_MITER;
|
||
|
else if (PL_strcasecmp(aZoomJoinStyle, "round") == 0)
|
||
|
mJoinStyle = GDK_JOIN_ROUND;
|
||
|
else if (PL_strcasecmp(aZoomJoinStyle, "bevel") == 0)
|
||
|
mJoinStyle = GDK_JOIN_BEVEL;
|
||
|
|
||
|
return PaintImage();
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetZoomBR_XChange(float * aZoomBR_XChange)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetZoomBR_XChange()\n");
|
||
|
#endif
|
||
|
|
||
|
*aZoomBR_XChange = mBottomRightXChange;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetZoomBR_XChange(float aZoomBR_XChange)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetZoomBR_XChange()\n");
|
||
|
#endif
|
||
|
|
||
|
// Read-Only
|
||
|
return NS_ERROR_NOT_AVAILABLE;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetZoomBR_YChange(float * aZoomBR_YChange)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetZoomBR_YChange()\n");
|
||
|
#endif
|
||
|
|
||
|
*aZoomBR_YChange = mBottomRightYChange;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetZoomBR_YChange(float aZoomBR_YChange)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetZoomBR_YChange()\n");
|
||
|
#endif
|
||
|
|
||
|
// Read-Only
|
||
|
return NS_ERROR_NOT_AVAILABLE;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetZoomTL_XChange(float * aZoomTL_XChange)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetZoomTL_XChange()\n");
|
||
|
#endif
|
||
|
|
||
|
*aZoomTL_XChange = mTopLeftXChange;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetZoomTL_XChange(float aZoomTL_XChange)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetZoomTL_XChange()\n");
|
||
|
#endif
|
||
|
|
||
|
// Read-Only
|
||
|
return NS_ERROR_NOT_AVAILABLE;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetZoomTL_YChange(float * aZoomTL_YChange)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetZoomTL_YChange()\n");
|
||
|
#endif
|
||
|
|
||
|
*aZoomTL_YChange = mTopLeftYChange;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetZoomTL_YChange(float aZoomTL_YChange)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetZoomTL_YChange()\n");
|
||
|
#endif
|
||
|
|
||
|
// Read-Only
|
||
|
return NS_ERROR_NOT_AVAILABLE;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetQuality(PRInt32 * aQuality)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetQuality()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(aQuality != NULL, "null compression quality pointer");
|
||
|
if (!aQuality)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
*aQuality = mCompQuality;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetQuality(PRInt32 aQuality)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetQuality()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(aQuality > -1 && aQuality < 101,
|
||
|
"Invalid compression quality");
|
||
|
if (aQuality < 0 || aQuality > 100)
|
||
|
return NS_ERROR_INVALID_ARG;
|
||
|
|
||
|
mCompQuality = aQuality;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetMethod(char ** aMethod)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetMethod()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(aMethod != NULL, "Null method pointer");
|
||
|
if (!aMethod)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
*aMethod = (char*) nsMemory::Alloc(8);
|
||
|
if (!*aMethod)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
|
||
|
switch (mCompMethod) {
|
||
|
case JDCT_ISLOW:
|
||
|
PL_strcpy(*aMethod, "SLOW");
|
||
|
break;
|
||
|
case JDCT_IFAST:
|
||
|
PL_strcpy(*aMethod, "FAST");
|
||
|
break;
|
||
|
case JDCT_FLOAT:
|
||
|
PL_strcpy(*aMethod, "FLOAT");
|
||
|
break;
|
||
|
default:
|
||
|
PL_strcpy(*aMethod, "DEFAULT");
|
||
|
|
||
|
}
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetMethod(const char * aMethod)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetMethod()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(aMethod != NULL, "Null method pointer");
|
||
|
if (!aMethod)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
if (PL_strcasecmp(aMethod, "SLOW") == 0)
|
||
|
mCompMethod = JDCT_ISLOW;
|
||
|
else if (PL_strcasecmp(aMethod, "FAST") == 0)
|
||
|
mCompMethod = JDCT_IFAST;
|
||
|
else if (PL_strcasecmp(aMethod, "FLOAT") == 0)
|
||
|
mCompMethod = JDCT_FLOAT;
|
||
|
else
|
||
|
mCompMethod = JDCT_DEFAULT;
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
// END of Image Preview Interface
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
// Generic SANE Interface
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetDeviceOptions(char ** aDeviceOptions)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetDeviceOptions()\n");
|
||
|
#endif
|
||
|
|
||
|
const SANE_Option_Descriptor * optdesc;
|
||
|
SANE_Int string_size;
|
||
|
char *range_string, *word_string;
|
||
|
nsresult rv;
|
||
|
|
||
|
NS_ASSERTION(aDeviceOptions != NULL, "null options pointer");
|
||
|
if (!aDeviceOptions)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
*aDeviceOptions = nsnull;
|
||
|
|
||
|
rv = OpenSaneDeviceIF();
|
||
|
if (rv != NS_OK)
|
||
|
return rv;
|
||
|
|
||
|
// Find out how many options exist for device
|
||
|
optdesc = sane_get_option_descriptor(mSaneHandle, 0);
|
||
|
if (!optdesc || optdesc->size == 0) {
|
||
|
NS_ERROR("Error trying to get number of options for device!");
|
||
|
return NS_ERROR_FAILURE;
|
||
|
}
|
||
|
|
||
|
if (optdesc->size == 1) { /* size includes "size" option */
|
||
|
NS_ERROR("Hmm.. That's odd! No options for this device?");
|
||
|
return NS_OK; // I guess it's possible?
|
||
|
}
|
||
|
|
||
|
// allocate string to contain data to return to caller
|
||
|
string_size = ((optdesc->size - 1) * MAX_OPT_SIZE) + 1;
|
||
|
*aDeviceOptions = (char*) nsMemory::Alloc(string_size);
|
||
|
NS_ENSURE_TRUE(*aDeviceOptions, NS_ERROR_OUT_OF_MEMORY);
|
||
|
|
||
|
// initialize options string
|
||
|
for (int n=0; n<string_size; n++)
|
||
|
(*aDeviceOptions)[n] = '\0';
|
||
|
|
||
|
// step through each of the options and copy over relavent data
|
||
|
int i = 1;
|
||
|
while((optdesc = sane_get_option_descriptor(mSaneHandle, i)) != NULL) {
|
||
|
i++;
|
||
|
|
||
|
// don't return grouping options
|
||
|
if (optdesc->type == SANE_TYPE_GROUP)
|
||
|
continue;
|
||
|
|
||
|
/*
|
||
|
* WARNING! Need to replace ','s and ';'s with
|
||
|
* something else so that JavaScript parsing
|
||
|
* doesn't get hosed!
|
||
|
*/
|
||
|
|
||
|
// NAME
|
||
|
if (optdesc->name)
|
||
|
optioncat(aDeviceOptions, optdesc->name, ", ");
|
||
|
else
|
||
|
strcat(*aDeviceOptions, "N/A, ");
|
||
|
|
||
|
////////////////////////////////////
|
||
|
// TITLE
|
||
|
if (optdesc->title)
|
||
|
optioncat(aDeviceOptions, optdesc->title, ", ");
|
||
|
else
|
||
|
PL_strcat(*aDeviceOptions, "N/A, ");
|
||
|
|
||
|
////////////////////////////////////
|
||
|
// DESCRIPTION
|
||
|
if (optdesc->desc)
|
||
|
optioncat(aDeviceOptions, optdesc->desc, ", ");
|
||
|
else
|
||
|
PL_strcat(*aDeviceOptions, "N/A, ");
|
||
|
|
||
|
////////////////////////////////////
|
||
|
// Option Type
|
||
|
switch (optdesc->type) {
|
||
|
|
||
|
case SANE_TYPE_BOOL:
|
||
|
PL_strcat(*aDeviceOptions, "BOOL, ");
|
||
|
break;
|
||
|
|
||
|
case SANE_TYPE_INT:
|
||
|
PL_strcat(*aDeviceOptions, "INT, ");
|
||
|
break;
|
||
|
|
||
|
case SANE_TYPE_FIXED:
|
||
|
PL_strcat(*aDeviceOptions, "FIXED, ");
|
||
|
break;
|
||
|
|
||
|
case SANE_TYPE_STRING:
|
||
|
PL_strcat(*aDeviceOptions, "STRING, ");
|
||
|
break;
|
||
|
|
||
|
case SANE_TYPE_BUTTON:
|
||
|
PL_strcat(*aDeviceOptions, "BUTTON, ");
|
||
|
break;
|
||
|
|
||
|
case SANE_TYPE_GROUP:
|
||
|
PL_strcat(*aDeviceOptions, "GROUP, ");
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
PL_strcat(*aDeviceOptions, "UNKNOWN, ");
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////
|
||
|
// UNIT
|
||
|
switch (optdesc->unit) {
|
||
|
case SANE_UNIT_NONE:
|
||
|
PL_strcat(*aDeviceOptions, "NONE, ");
|
||
|
break;
|
||
|
|
||
|
case SANE_UNIT_PIXEL:
|
||
|
PL_strcat(*aDeviceOptions, "PIXEL, ");
|
||
|
break;
|
||
|
|
||
|
case SANE_UNIT_BIT:
|
||
|
PL_strcat(*aDeviceOptions, "BIT, ");
|
||
|
break;
|
||
|
|
||
|
case SANE_UNIT_MM:
|
||
|
PL_strcat(*aDeviceOptions, "MM, ");
|
||
|
break;
|
||
|
|
||
|
case SANE_UNIT_DPI:
|
||
|
PL_strcat(*aDeviceOptions, "PERCENT, ");
|
||
|
break;
|
||
|
|
||
|
case SANE_UNIT_MICROSECOND:
|
||
|
PL_strcat(*aDeviceOptions, "MICROSECOND, ");
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
PL_strcat(*aDeviceOptions, "UNKNOWN, ");
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////
|
||
|
// SIZE
|
||
|
char * size_option = (char *)PR_MALLOC(64);
|
||
|
if (!size_option)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
sprintf(size_option, "%i, ", optdesc->size);
|
||
|
PL_strcat(*aDeviceOptions, size_option);
|
||
|
PR_FREEIF(size_option);
|
||
|
|
||
|
////////////////////////////////////////
|
||
|
// ACTIVE?
|
||
|
if (SANE_OPTION_IS_ACTIVE(optdesc->cap))
|
||
|
PL_strcat(*aDeviceOptions, "ACTIVE, ");
|
||
|
else
|
||
|
PL_strcat(*aDeviceOptions, "UNACTIVE, ");
|
||
|
|
||
|
////////////////////////////////////////
|
||
|
// SW SETTABLE?
|
||
|
if (SANE_OPTION_IS_SETTABLE(optdesc->cap))
|
||
|
PL_strcat(*aDeviceOptions, "SETTABLE, ");
|
||
|
else
|
||
|
PL_strcat(*aDeviceOptions, "UNSETTABLE, ");
|
||
|
|
||
|
////////////////////////////////////////
|
||
|
// Contraints Union
|
||
|
switch (optdesc->constraint_type) {
|
||
|
case SANE_CONSTRAINT_RANGE:
|
||
|
range_string = (char *)PR_MALLOC(128);
|
||
|
if (!range_string)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
sprintf(range_string, "RANGE, %i, %i, %i; ",
|
||
|
optdesc->constraint.range->min,
|
||
|
optdesc->constraint.range->max,
|
||
|
optdesc->constraint.range->quant);
|
||
|
PL_strcat(*aDeviceOptions, range_string);
|
||
|
PR_FREEIF(range_string);
|
||
|
break;
|
||
|
|
||
|
case SANE_CONSTRAINT_WORD_LIST:
|
||
|
word_string = (char *) PR_MALLOC(64);
|
||
|
if (!word_string)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
|
||
|
PL_strcat(*aDeviceOptions, "WORD_LIST");
|
||
|
for (int word_index=1;
|
||
|
word_index <= optdesc->constraint.word_list[0];
|
||
|
word_index++) {
|
||
|
sprintf(word_string, ", %i", optdesc->constraint.word_list[i]);
|
||
|
PL_strcat(*aDeviceOptions, word_string);
|
||
|
}
|
||
|
PL_strcat(*aDeviceOptions, ";");
|
||
|
PR_FREEIF(word_string);
|
||
|
break;
|
||
|
|
||
|
case SANE_CONSTRAINT_STRING_LIST:
|
||
|
PL_strcat(*aDeviceOptions, "STRING_LIST");
|
||
|
for (int string_index=0;
|
||
|
optdesc->constraint.string_list[string_index];
|
||
|
string_index++) {
|
||
|
PL_strcat(*aDeviceOptions, ", ");
|
||
|
PL_strcat(*aDeviceOptions,
|
||
|
optdesc->constraint.string_list[string_index]);
|
||
|
}
|
||
|
PL_strcat(*aDeviceOptions, ";");
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
// no constraints
|
||
|
PL_strcat(*aDeviceOptions, "NONE;");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetDeviceOptions(const char * aDeviceOptions)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetDeviceOptions()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ERROR("DeviceOptions is read-only!\n");
|
||
|
return NS_ERROR_NOT_AVAILABLE;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetActiveDevice(char ** aActiveDevice)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetActiveDevice()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(aActiveDevice != NULL, "null device pointer");
|
||
|
if (!aActiveDevice)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
*aActiveDevice = nsnull;
|
||
|
if (!mSaneDevice)
|
||
|
return NS_OK;
|
||
|
|
||
|
*aActiveDevice = (char*) nsMemory::Alloc(PL_strlen(mSaneDevice) + 1);
|
||
|
NS_ENSURE_TRUE(*aActiveDevice, NS_ERROR_OUT_OF_MEMORY);
|
||
|
PL_strcpy(*aActiveDevice, mSaneDevice);
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetActiveDevice(const char * aActiveDevice)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetActiveDevice()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ASSERTION(aActiveDevice, "null active device pointer");
|
||
|
if (!aActiveDevice)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
PR_FREEIF (mSaneDevice);
|
||
|
mSaneDevice = PL_strdup(aActiveDevice);
|
||
|
|
||
|
if (mSaneOpen) {
|
||
|
sane_close(mSaneHandle);
|
||
|
sane_exit();
|
||
|
sane_init(0,0);
|
||
|
if (sane_open(mSaneDevice, &mSaneHandle) != SANE_STATUS_GOOD) {
|
||
|
mSaneOpen = SANE_FALSE;
|
||
|
NS_ERROR("Error trying to reopen sane device!\n");
|
||
|
return NS_ERROR_FAILURE;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
if (sane_open(mSaneDevice, &mSaneHandle) != SANE_STATUS_GOOD) {
|
||
|
NS_ERROR("Error trying to open closed sane device!\n");
|
||
|
return NS_ERROR_FAILURE;
|
||
|
}
|
||
|
mSaneOpen = SANE_TRUE;
|
||
|
}
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::OpenSaneDeviceIF( void )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::OpenSaneDeviceIF()\n");
|
||
|
#endif
|
||
|
|
||
|
if (mSaneOpen) {
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
if (!mSaneDevice) {
|
||
|
NS_ERROR("Device name not set!");
|
||
|
return NS_ERROR_FAILURE;
|
||
|
}
|
||
|
|
||
|
SANE_Status status = sane_open(mSaneDevice, &mSaneHandle);
|
||
|
if (status != SANE_STATUS_GOOD) {
|
||
|
NS_ERROR ("sane_open returned error code");
|
||
|
return NS_ERROR_FAILURE;
|
||
|
}
|
||
|
|
||
|
mSaneOpen = SANE_TRUE;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetImageParameters(char ** aImageParameters)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetImageParameters()\n");
|
||
|
#endif
|
||
|
|
||
|
SANE_Status status;
|
||
|
SANE_Parameters params;
|
||
|
nsresult rv;
|
||
|
|
||
|
NS_ASSERTION(aImageParameters != NULL, "null parameters pointer");
|
||
|
if (!aImageParameters)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
*aImageParameters = nsnull;
|
||
|
|
||
|
rv = OpenSaneDeviceIF();;
|
||
|
if (rv != NS_OK)
|
||
|
return rv;
|
||
|
|
||
|
status = sane_get_parameters(mSaneHandle, ¶ms);
|
||
|
if (status != SANE_STATUS_GOOD) {
|
||
|
sane_close(mSaneHandle);
|
||
|
NS_ERROR("Failed to get parameters for sane device!");
|
||
|
return NS_ERROR_FAILURE;
|
||
|
}
|
||
|
|
||
|
#define MAX_PARAM_LEN 256
|
||
|
*aImageParameters = (char *) nsMemory::Alloc(MAX_PARAM_LEN);
|
||
|
if (!*aImageParameters)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
|
||
|
char * format_string;
|
||
|
switch (params.format) {
|
||
|
|
||
|
case SANE_FRAME_GRAY:
|
||
|
format_string = PL_strdup("GRAY");
|
||
|
break;
|
||
|
|
||
|
case SANE_FRAME_RGB:
|
||
|
format_string = PL_strdup("RGB");
|
||
|
break;
|
||
|
|
||
|
case SANE_FRAME_RED:
|
||
|
format_string = PL_strdup("RED");
|
||
|
break;
|
||
|
|
||
|
case SANE_FRAME_GREEN:
|
||
|
format_string = PL_strdup("GREEN");
|
||
|
break;
|
||
|
|
||
|
case SANE_FRAME_BLUE:
|
||
|
format_string = PL_strdup("BLUE");
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
format_string = PL_strdup("UNKNOWN");
|
||
|
}
|
||
|
|
||
|
sprintf(*aImageParameters, "%s, %s, %i, %i, %i, %i",
|
||
|
format_string,
|
||
|
params.last_frame ? "TRUE" : "FALSE",
|
||
|
params.lines,
|
||
|
params.depth,
|
||
|
params.pixels_per_line,
|
||
|
params.bytes_per_line);
|
||
|
|
||
|
|
||
|
// cleanup
|
||
|
PR_FREEIF(format_string);
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetImageParameters(const char * aImageParameters)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetImageParameters()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ERROR("ImageParameters is read-only!\n");
|
||
|
return NS_ERROR_NOT_AVAILABLE;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetAvailableDevices(char ** aAvailableDevices)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetAvailableDevices()\n");
|
||
|
#endif
|
||
|
|
||
|
SANE_Status status;
|
||
|
const SANE_Device ** device_list;
|
||
|
int num, i;
|
||
|
|
||
|
NS_ASSERTION(aAvailableDevices != NULL, "null parameters pointer");
|
||
|
if (!aAvailableDevices)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
*aAvailableDevices = nsnull;
|
||
|
|
||
|
status = sane_get_devices(&device_list, SANE_TRUE);
|
||
|
if (status != SANE_STATUS_GOOD)
|
||
|
return NS_ERROR_FAILURE;
|
||
|
|
||
|
// find out how many devices are available
|
||
|
for ( num=0; device_list[num]; num++);
|
||
|
|
||
|
// allocate return string
|
||
|
#define MAX_DEVICE_SIZE 256
|
||
|
*aAvailableDevices = (char*) nsMemory::Alloc(num * MAX_DEVICE_SIZE);
|
||
|
if (!*aAvailableDevices)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
|
||
|
for ( i=0; i < num * MAX_DEVICE_SIZE; i++)
|
||
|
(*aAvailableDevices)[i] = '\0';
|
||
|
|
||
|
for ( i=0; i<num; i++) {
|
||
|
optioncat(aAvailableDevices, device_list[i]->name, ", ");
|
||
|
optioncat(aAvailableDevices, device_list[i]->vendor, ", ");
|
||
|
optioncat(aAvailableDevices, device_list[i]->model, ", ");
|
||
|
optioncat(aAvailableDevices, device_list[i]->type, "; ");
|
||
|
}
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetAvailableDevices(const char * aAvailableDevices)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetAvailableDevices()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_ERROR("AvailableDevices is read-only!\n");
|
||
|
return NS_ERROR_NOT_AVAILABLE;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::ScanImage(void)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::ScanImage()\n");
|
||
|
#endif
|
||
|
|
||
|
mState = 1;
|
||
|
mSuccess = 0;
|
||
|
|
||
|
mScanThread = PR_CreateThread( PR_USER_THREAD, scanimage_thread_routine,
|
||
|
(void*)this, PR_PRIORITY_HIGH,
|
||
|
PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
|
||
|
|
||
|
if (mScanThread == NULL) {
|
||
|
NS_ERROR("Could not create thread!");
|
||
|
return NS_ERROR_FAILURE;
|
||
|
}
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetOption(const char * name, const char * value)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetOption()\n");
|
||
|
#endif
|
||
|
|
||
|
nsresult rv;
|
||
|
SANE_Int optnum;
|
||
|
const SANE_Option_Descriptor * optdesc;
|
||
|
void * option_value;
|
||
|
SANE_Status status;
|
||
|
|
||
|
NS_ASSERTION(name != NULL && value != NULL, "null pointer");
|
||
|
if (!name || !value)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
rv = OpenSaneDeviceIF();
|
||
|
if (rv != NS_OK)
|
||
|
return rv;
|
||
|
|
||
|
// find the option number
|
||
|
for ( optnum=1;
|
||
|
((optdesc = sane_get_option_descriptor(mSaneHandle, optnum)) != NULL)
|
||
|
&& (PL_strcasecmp(name, optdesc->name) != 0);
|
||
|
optnum++ );
|
||
|
if (!optdesc) {
|
||
|
NS_ERROR("Option not found for sane device!");
|
||
|
return NS_ERROR_INVALID_ARG;
|
||
|
}
|
||
|
|
||
|
// determine the value to pass to device
|
||
|
if (optdesc->type == SANE_TYPE_BOOL) {
|
||
|
SANE_Bool sbool;
|
||
|
if (PL_strcasecmp(value, "TRUE") == 0) {
|
||
|
sbool = SANE_TRUE;
|
||
|
} else
|
||
|
sbool = SANE_FALSE;
|
||
|
|
||
|
option_value = (void *) &sbool;
|
||
|
|
||
|
} else if ( optdesc->type == SANE_TYPE_INT ||
|
||
|
optdesc->type == SANE_TYPE_FIXED ) {
|
||
|
SANE_Int sint;
|
||
|
sscanf(value, "%i", &sint);
|
||
|
|
||
|
option_value = (void *) &sint;
|
||
|
|
||
|
} else if (optdesc->type == SANE_TYPE_STRING) {
|
||
|
option_value = (void *) value;
|
||
|
} else {
|
||
|
option_value = NULL;
|
||
|
}
|
||
|
|
||
|
// set the option
|
||
|
status = sane_control_option( mSaneHandle, optnum,
|
||
|
SANE_ACTION_SET_VALUE, option_value,
|
||
|
NULL);
|
||
|
if (status != SANE_STATUS_GOOD) {
|
||
|
NS_ERROR("Error trying to set option!");
|
||
|
return NS_ERROR_FAILURE;
|
||
|
}
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
nsSanePluginInstance::WritePNMHeader (int fd, SANE_Frame format,
|
||
|
int width, int height, int depth)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::WritePNMHeader()\n");
|
||
|
#endif
|
||
|
|
||
|
char b[32];
|
||
|
|
||
|
switch (format) {
|
||
|
case SANE_FRAME_RED:
|
||
|
case SANE_FRAME_GREEN:
|
||
|
case SANE_FRAME_BLUE:
|
||
|
case SANE_FRAME_RGB:
|
||
|
sprintf (b, "P6\n%d %d\n255\n", width, height);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
if (depth == 1)
|
||
|
sprintf (b, "P4\n%d %d\n", width, height);
|
||
|
else
|
||
|
sprintf (b, "P5\n%d %d\n255\n", width, height);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return write(fd, b, PL_strlen(b));
|
||
|
}
|
||
|
|
||
|
// END of Generic SANE Interface
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// Scanner Status Interface
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetSuccess(PRBool * aSuccess)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetSuccess()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_PRECONDITION(aSuccess != nsnull, "null ptr");
|
||
|
if (! aSuccess) {
|
||
|
NS_ERROR("Null pointer passed to GetSuccess!\n");
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
}
|
||
|
|
||
|
*aSuccess = mSuccess;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetSuccess(PRBool aSuccess)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetSuccess()\n");
|
||
|
#endif
|
||
|
|
||
|
// This is a read-only flag.
|
||
|
NS_ERROR("Success is a read-only flag!\n");
|
||
|
return NS_ERROR_FAILURE;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::GetState(char ** aState)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::GetState()\n");
|
||
|
#endif
|
||
|
|
||
|
NS_PRECONDITION(aState != nsnull, "null ptr");
|
||
|
if (! aState) {
|
||
|
NS_ERROR("Null pointer passed to GetSuccess!\n");
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
}
|
||
|
|
||
|
*aState = (char*) nsMemory::Alloc(5);
|
||
|
if (!*aState) {
|
||
|
NS_ERROR("Unable to allocate State string!\n");
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
}
|
||
|
|
||
|
if (mState == 0)
|
||
|
PL_strcpy(*aState, "IDLE");
|
||
|
else
|
||
|
PL_strcpy(*aState, "BUSY");
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsSanePluginInstance::SetState(const char * aState)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSaneInstance::SetState()\n");
|
||
|
#endif
|
||
|
|
||
|
// This is a read-only flag.
|
||
|
NS_ERROR("Success is a read-only flag!\n");
|
||
|
return NS_ERROR_FAILURE;
|
||
|
}
|
||
|
|
||
|
// END of Scanner Status Interface
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// snPluginStreamListener Methods
|
||
|
|
||
|
nsSanePluginStreamListener::nsSanePluginStreamListener(nsSanePluginInstance* inst)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginStreamListener::nsSanePluginStreamListener()\n");
|
||
|
#endif
|
||
|
|
||
|
PR_AtomicIncrement(&gPluginObjectCount);
|
||
|
|
||
|
mPlugInst = inst;
|
||
|
}
|
||
|
|
||
|
nsSanePluginStreamListener::~nsSanePluginStreamListener(void)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginStreamListener::~nsSanePluginStreamListener()\n");
|
||
|
#endif
|
||
|
|
||
|
PR_AtomicDecrement(&gPluginObjectCount);
|
||
|
}
|
||
|
|
||
|
|
||
|
// This macro produces a simple version of QueryInterface, AddRef and Release.
|
||
|
// See the nsISupports.h header file for details.
|
||
|
NS_IMPL_ISUPPORTS1(nsSanePluginStreamListener, nsIPluginStreamListener)
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginStreamListener::OnStartBinding( nsIPluginStreamInfo* pluginInfo )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginStreamListener::OnStartBinding()\n");
|
||
|
#endif
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginStreamListener::OnDataAvailable( nsIPluginStreamInfo* pluginInfo,
|
||
|
nsIInputStream* input,
|
||
|
PRUint32 length )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginStreamListener::OnDataAvailable()\n");
|
||
|
#endif
|
||
|
|
||
|
// This plugin doesn't support
|
||
|
// streaming input data.
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginStreamListener::OnFileAvailable( nsIPluginStreamInfo* pluginInfo,
|
||
|
const char* fileName )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginStreamListener::OnFileAvailable()\n");
|
||
|
#endif
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginStreamListener::OnStopBinding( nsIPluginStreamInfo* pluginInfo,
|
||
|
nsresult status )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginStreamListener::OnStopBinding()\n");
|
||
|
#endif
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginStreamListener::OnNotify( const char* url, nsresult status )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginStreamListener::OnNotify()\n");
|
||
|
#endif
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_METHOD
|
||
|
nsSanePluginStreamListener::GetStreamType(nsPluginStreamType *result)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("nsSanePluginStreamListener::GetStreamType()\n");
|
||
|
#endif
|
||
|
|
||
|
*result = nsPluginStreamType_Normal;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
// End snPluginStreamListener methods
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Helper Global Fuctions
|
||
|
|
||
|
gboolean draw (GtkWidget *widget, GdkEventExpose *event, gpointer data) {
|
||
|
|
||
|
nsSanePluginInstance * pthis = (nsSanePluginInstance *)data;
|
||
|
|
||
|
pthis->PaintImage();
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
nsresult optioncat ( char ** dest, const char * src, const char * ending )
|
||
|
{
|
||
|
char * p;
|
||
|
int i;
|
||
|
|
||
|
NS_ASSERTION(dest != NULL, "null option string pointer");
|
||
|
if (!dest)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
NS_ASSERTION(src != NULL, "null option string pointer");
|
||
|
if (!src)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
NS_ASSERTION(ending != NULL, "null option string pointer");
|
||
|
if (!ending)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
// ensure that src string doesn't contain any ','s or ';'s
|
||
|
p = PL_strdup(src);
|
||
|
for ( i=0; p[i]; i++ ) {
|
||
|
if (p[i] == ',')
|
||
|
p[i] = '~'; // Replace ','s with '~'s
|
||
|
else if (p[i] == ';')
|
||
|
p[i] = '|'; // Replace ';'s with '|'s
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
PL_strcat(*dest, p);
|
||
|
PL_strcat(*dest, ending);
|
||
|
PR_FREEIF(p);
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
my_jpeg_error_exit (j_common_ptr cinfo)
|
||
|
{
|
||
|
emptr errmgr;
|
||
|
|
||
|
errmgr = (emptr) cinfo->err;
|
||
|
cinfo->err->output_message(cinfo);
|
||
|
siglongjmp(errmgr->setjmp_buffer, 1);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
unsigned char *
|
||
|
jpeg_file_to_rgb (FILE * f, int *w, int *h)
|
||
|
{
|
||
|
struct jpeg_decompress_struct cinfo;
|
||
|
struct my_JPEG_error_mgr jerr;
|
||
|
unsigned char *data, *line[16], *ptr;
|
||
|
int x, y, i;
|
||
|
|
||
|
cinfo.err = jpeg_std_error(&(jerr.pub));
|
||
|
jerr.pub.error_exit = my_jpeg_error_exit;
|
||
|
|
||
|
/* error handler to longjmp to, we want to preserve signals */
|
||
|
if (sigsetjmp(jerr.setjmp_buffer, 1)) {
|
||
|
|
||
|
/* Whoops there was a jpeg error */
|
||
|
jpeg_destroy_decompress(&cinfo);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
jpeg_create_decompress(&cinfo);
|
||
|
jpeg_stdio_src(&cinfo, f);
|
||
|
jpeg_read_header(&cinfo, TRUE);
|
||
|
cinfo.do_fancy_upsampling = FALSE;
|
||
|
cinfo.do_block_smoothing = FALSE;
|
||
|
|
||
|
cinfo.scale_num = 2;
|
||
|
cinfo.scale_denom = 1;
|
||
|
jpeg_start_decompress(&cinfo);
|
||
|
*w = cinfo.output_width;
|
||
|
*h = cinfo.output_height;
|
||
|
data = (unsigned char *)PR_Malloc(*w ** h * 3);
|
||
|
if (!data) {
|
||
|
NS_ERROR("jpeg_file_to_rgb: Error trying to allocate buffer!\n");
|
||
|
jpeg_destroy_decompress(&cinfo);
|
||
|
return NULL;
|
||
|
}
|
||
|
ptr = data;
|
||
|
|
||
|
if (cinfo.rec_outbuf_height > 16) {
|
||
|
NS_ERROR("ERROR: JPEG uses line buffers > 16. Cannot load.\n");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (cinfo.output_components == 3) {
|
||
|
for (y = 0; y < *h; y += cinfo.rec_outbuf_height) {
|
||
|
for (i = 0; i < cinfo.rec_outbuf_height; i++) {
|
||
|
line[i] = ptr;
|
||
|
ptr += *w * 3;
|
||
|
}
|
||
|
|
||
|
jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
|
||
|
}
|
||
|
} else if (cinfo.output_components == 1) {
|
||
|
for (i = 0; i < cinfo.rec_outbuf_height; i++) {
|
||
|
if ((line[i] = (unsigned char *)PR_Malloc(*w)) == NULL) {
|
||
|
int t = 0;
|
||
|
|
||
|
NS_ERROR("jpeg_file_to_rgb: Error tying to allocate line!\n");
|
||
|
|
||
|
for (t = 0; t < i; t++)
|
||
|
PR_FREEIF(line[t]);
|
||
|
jpeg_destroy_decompress(&cinfo);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (y = 0; y < *h; y += cinfo.rec_outbuf_height) {
|
||
|
jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
|
||
|
for (i = 0; i < cinfo.rec_outbuf_height; i++) {
|
||
|
for (x = 0; x < *w; x++) {
|
||
|
*ptr++ = line[i][x];
|
||
|
*ptr++ = line[i][x];
|
||
|
*ptr++ = line[i][x];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < cinfo.rec_outbuf_height; i++)
|
||
|
PR_FREEIF(line[i]);
|
||
|
}
|
||
|
|
||
|
jpeg_finish_decompress(&cinfo);
|
||
|
jpeg_destroy_decompress(&cinfo);
|
||
|
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
// Caller must free memory
|
||
|
unsigned char *
|
||
|
scale_image(unsigned char *rgb_data, int rgb_width, int rgb_height,
|
||
|
int w, int h)
|
||
|
{
|
||
|
int x, y, *xarray;
|
||
|
unsigned char **yarray, *ptr, *ptr2, *ptr22, *new_data;
|
||
|
int l, r, m, pos, inc, w3;
|
||
|
|
||
|
new_data = (unsigned char *) PR_Malloc( w * h * 3);
|
||
|
if (!new_data) {
|
||
|
NS_ERROR("ERROR: Cannot allocate image buffer\n");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
xarray = (int *)PR_Malloc(sizeof(int) * w);
|
||
|
if (!xarray) {
|
||
|
NS_ERROR("ERROR: Cannot allocate X co-ord buffer\n");
|
||
|
PR_FREEIF(new_data);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
yarray = (unsigned char **)PR_Malloc(sizeof(unsigned char *) * h);
|
||
|
if (!yarray) {
|
||
|
NS_ERROR("ERROR: Cannot allocate Y co-ord buffer\n");
|
||
|
PR_FREEIF(new_data);
|
||
|
PR_FREEIF(xarray);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ptr22 = rgb_data;
|
||
|
w3 = rgb_width * 3;
|
||
|
inc = 0;
|
||
|
l = 0;
|
||
|
r = 0;
|
||
|
m = w - l - r;
|
||
|
|
||
|
inc = (rgb_width << 16) / m;
|
||
|
pos = 0;
|
||
|
|
||
|
for (x = l; x < l + m; x++) {
|
||
|
xarray[x] = (pos >> 16) + (pos >> 16) + (pos >> 16);
|
||
|
pos += inc;
|
||
|
}
|
||
|
|
||
|
pos = (rgb_width - r) << 16;
|
||
|
for (x = w - r; x < w; x++) {
|
||
|
xarray[x] = (pos >> 16) + (pos >> 16) + (pos >> 16);
|
||
|
pos += 0x10000;
|
||
|
}
|
||
|
|
||
|
l = 0;
|
||
|
r = 0;
|
||
|
m = h - l - r;
|
||
|
|
||
|
if (m > 0)
|
||
|
inc = (rgb_height << 16) / m;
|
||
|
|
||
|
pos = 0;
|
||
|
|
||
|
for (x = l; x < l + m; x++) {
|
||
|
yarray[x] = ptr22 + ((pos >> 16) * w3);
|
||
|
pos += inc;
|
||
|
}
|
||
|
|
||
|
pos = (rgb_height - r) << 16;
|
||
|
for (x = h - r; x < h; x++) {
|
||
|
yarray[x] = ptr22 + ((pos >> 16) * w3);
|
||
|
pos += 0x10000;
|
||
|
}
|
||
|
|
||
|
ptr = new_data;
|
||
|
for (y = 0; y < h; y++) {
|
||
|
for (x = 0; x < w; x++) {
|
||
|
ptr2 = yarray[y] + xarray[x];
|
||
|
*ptr++ = (int)*ptr2++;
|
||
|
*ptr++ = (int)*ptr2++;
|
||
|
*ptr++ = (int)*ptr2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PR_FREEIF(xarray);
|
||
|
PR_FREEIF(yarray);
|
||
|
|
||
|
return new_data;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Caller must free memory
|
||
|
unsigned char *
|
||
|
crop_image(unsigned char *rgb_data, int *rgb_width, int *rgb_height,
|
||
|
gint x, gint y, gint w, gint h)
|
||
|
{
|
||
|
unsigned char *data;
|
||
|
int xx, yy, w3, w4;
|
||
|
unsigned char *ptr1, *ptr2;
|
||
|
|
||
|
if (!rgb_data)
|
||
|
return NULL;
|
||
|
|
||
|
if (x < 0)
|
||
|
{
|
||
|
w += x;
|
||
|
x = 0;
|
||
|
}
|
||
|
if (y < 0)
|
||
|
{
|
||
|
h += y;
|
||
|
y = 0;
|
||
|
}
|
||
|
if (x >= *rgb_width)
|
||
|
return NULL;
|
||
|
if (y >= *rgb_height)
|
||
|
return NULL;
|
||
|
if (w <= 0)
|
||
|
return NULL;
|
||
|
if (h <= 0)
|
||
|
return NULL;
|
||
|
if (x + w > *rgb_width)
|
||
|
w = *rgb_width - x;
|
||
|
if (y + h > *rgb_height)
|
||
|
h = *rgb_height - y;
|
||
|
if (w <= 0)
|
||
|
return NULL;
|
||
|
if (h <= 0)
|
||
|
return NULL;
|
||
|
|
||
|
w3 = *rgb_width * 3;
|
||
|
w4 = (*rgb_width - w) * 3;
|
||
|
data = (unsigned char *)PR_Malloc(w * h * 3);
|
||
|
if (data == NULL)
|
||
|
return NULL;
|
||
|
ptr1 = rgb_data + (y * w3) + (x * 3);
|
||
|
ptr2 = data;
|
||
|
for (yy = 0; yy < h; yy++)
|
||
|
{
|
||
|
for (xx = 0; xx < w; xx++)
|
||
|
{
|
||
|
*ptr2++ = *ptr1++;
|
||
|
*ptr2++ = *ptr1++;
|
||
|
*ptr2++ = *ptr1++;
|
||
|
}
|
||
|
ptr1 += w4;
|
||
|
}
|
||
|
|
||
|
*rgb_width = w;
|
||
|
*rgb_height = h;
|
||
|
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
void PR_CALLBACK scanimage_thread_routine( void * arg )
|
||
|
{
|
||
|
nsSanePluginInstance * pthis = (nsSanePluginInstance *)arg;
|
||
|
|
||
|
nsresult rv;
|
||
|
SANE_Status status;
|
||
|
SANE_Parameters param;
|
||
|
int len;
|
||
|
FILE * out;
|
||
|
SANE_Byte * buf;
|
||
|
JSAMPROW row_pointer[1];
|
||
|
char *fname;
|
||
|
|
||
|
// JPEG stuff
|
||
|
struct jpeg_compress_struct cinfo;
|
||
|
struct jpeg_error_mgr jerr;
|
||
|
|
||
|
// Error handling
|
||
|
jerr.error_exit = my_jpeg_error_exit; // fatal errors
|
||
|
cinfo.err = jpeg_std_error(&jerr);
|
||
|
|
||
|
jpeg_create_compress(&cinfo);
|
||
|
|
||
|
rv = pthis->OpenSaneDeviceIF();
|
||
|
if (rv != NS_OK)
|
||
|
goto error_exit;
|
||
|
|
||
|
// open image file
|
||
|
fname = pthis->GetImageFilename();
|
||
|
if (!fname)
|
||
|
goto error_exit;
|
||
|
out = fopen(fname, "wb");
|
||
|
PR_FREEIF(fname);
|
||
|
if (out == NULL) {
|
||
|
NS_ERROR("Unable to open mImageFilename!\n");
|
||
|
sane_cancel(pthis->mSaneHandle);
|
||
|
goto error_exit;
|
||
|
}
|
||
|
jpeg_stdio_dest(&cinfo, out);
|
||
|
|
||
|
status = sane_start(pthis->mSaneHandle);
|
||
|
if (status != SANE_STATUS_GOOD) {
|
||
|
NS_ERROR("Error trying to start sane device!");
|
||
|
goto error_exit;
|
||
|
}
|
||
|
|
||
|
status = sane_get_parameters(pthis->mSaneHandle, ¶m);
|
||
|
if (status != SANE_STATUS_GOOD) {
|
||
|
NS_ERROR("Error trying to get image parameters!\n");
|
||
|
sane_cancel(pthis->mSaneHandle);
|
||
|
goto error_exit;
|
||
|
}
|
||
|
cinfo.image_width = param.pixels_per_line;
|
||
|
cinfo.image_height = param.lines;
|
||
|
|
||
|
switch (param.format) {
|
||
|
case SANE_FRAME_RED:
|
||
|
case SANE_FRAME_GREEN:
|
||
|
case SANE_FRAME_BLUE:
|
||
|
// NOT Supported!
|
||
|
NS_ERROR("Multiframe devices not supported!\n");
|
||
|
sane_cancel(pthis->mSaneHandle);
|
||
|
goto error_exit;
|
||
|
break;
|
||
|
|
||
|
case SANE_FRAME_RGB:
|
||
|
cinfo.input_components = 3;
|
||
|
cinfo.in_color_space = JCS_RGB;
|
||
|
break;
|
||
|
|
||
|
case SANE_FRAME_GRAY:
|
||
|
cinfo.input_components = 1;
|
||
|
cinfo.in_color_space = JCS_GRAYSCALE;
|
||
|
break;
|
||
|
}
|
||
|
jpeg_set_defaults(&cinfo);
|
||
|
cinfo.dct_method = pthis->mCompMethod;
|
||
|
jpeg_set_quality(&cinfo, pthis->mCompQuality, FALSE);
|
||
|
jpeg_start_compress(&cinfo, TRUE);
|
||
|
|
||
|
buf = (SANE_Byte *)PR_MALLOC(param.bytes_per_line);
|
||
|
if (!buf) {
|
||
|
NS_ERROR("Error trying to allocate buffer!\n");
|
||
|
jpeg_destroy_compress(&cinfo);
|
||
|
fclose(out);
|
||
|
sane_cancel(pthis->mSaneHandle);
|
||
|
goto error_exit;
|
||
|
}
|
||
|
|
||
|
int total;
|
||
|
while(1) {
|
||
|
total = 0;
|
||
|
while (total < param.bytes_per_line) {
|
||
|
// Read in data from sane device
|
||
|
status = sane_read(pthis->mSaneHandle, buf + total,
|
||
|
param.bytes_per_line - total,
|
||
|
&len);
|
||
|
if (status != SANE_STATUS_GOOD) {
|
||
|
if (status == SANE_STATUS_EOF)
|
||
|
// done with this frame
|
||
|
goto finished_scan;
|
||
|
else {
|
||
|
NS_ERROR("Error trying to read from sane device!\n");
|
||
|
PR_FREEIF(buf);
|
||
|
jpeg_destroy_compress(&cinfo);
|
||
|
fclose(out);
|
||
|
sane_cancel(pthis->mSaneHandle);
|
||
|
goto error_exit;
|
||
|
}
|
||
|
}
|
||
|
total += len;
|
||
|
}
|
||
|
|
||
|
row_pointer[0] = (JSAMPLE *) buf;
|
||
|
jpeg_write_scanlines(&cinfo, row_pointer, 1);
|
||
|
|
||
|
} // end while
|
||
|
|
||
|
// cleanup
|
||
|
finished_scan:
|
||
|
jpeg_finish_compress(&cinfo);
|
||
|
jpeg_destroy_compress(&cinfo);
|
||
|
PR_FREEIF(buf);
|
||
|
sane_cancel(pthis->mSaneHandle);
|
||
|
fclose(out);
|
||
|
pthis->SetSuccess(PR_TRUE); // allow caller to check for success
|
||
|
|
||
|
error_exit:
|
||
|
|
||
|
////////////////////////////////////////////////
|
||
|
// Call onScanComplete callback in the UI thread
|
||
|
|
||
|
nsCOMPtr<nsIEventQueue> eventQ;
|
||
|
|
||
|
// Get the event queue of the current thread...
|
||
|
nsCOMPtr<nsIEventQueueService> eventQService =
|
||
|
do_GetService(kEventQueueService, &rv);
|
||
|
if (NS_FAILED(rv)) {
|
||
|
NS_ERROR("Unable to get event queue service!\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
rv = eventQService->GetThreadEventQueue(pthis->mUIThread,
|
||
|
getter_AddRefs(eventQ));
|
||
|
if (NS_FAILED(rv)) {
|
||
|
NS_ERROR("Unable to get thread queue!\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
PLEvent *event = new PLEvent;
|
||
|
if (!event) {
|
||
|
NS_ERROR("Unable to create new event!\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// ThreadHandleEvent will now execute in the UI thread.
|
||
|
PL_InitEvent(event,
|
||
|
pthis,
|
||
|
(PLHandleEventProc) ThreadedHandleEvent,
|
||
|
(PLDestroyEventProc) ThreadedDestroyEvent);
|
||
|
|
||
|
if (NS_FAILED(eventQ->PostEvent(event))) {
|
||
|
NS_ERROR("Error trying to post event!\n");
|
||
|
PL_DestroyEvent(event);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void PR_CALLBACK ThreadedHandleEvent(PLEvent * event)
|
||
|
{
|
||
|
nsSanePluginInstance *pthis = (nsSanePluginInstance *)event->owner;
|
||
|
|
||
|
// If this isn't the UI's thread then we are hosed!
|
||
|
if (PR_FALSE == pthis->IsUIThread()) {
|
||
|
NS_ERROR("Attempt to execute event from the wrong thread!\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pthis->SetState(0); // no longer scanning
|
||
|
pthis->Restore(); // repaint image
|
||
|
|
||
|
// Notify user that routine is finished
|
||
|
pthis->DoScanCompleteCallback();
|
||
|
}
|
||
|
|
||
|
void PR_CALLBACK ThreadedDestroyEvent(PLEvent* aEvent)
|
||
|
{
|
||
|
delete aEvent;
|
||
|
}
|
||
|
|
||
|
void store_filename(GtkFileSelection *selector, gpointer user_data)
|
||
|
{
|
||
|
nsSanePluginInstance *pthis = (nsSanePluginInstance *) user_data;
|
||
|
gchar *cmd;
|
||
|
GtkWidget * fs;
|
||
|
char * orig_filename;
|
||
|
char * dest_filename;
|
||
|
|
||
|
if (!user_data || !selector)
|
||
|
return;
|
||
|
|
||
|
fs = pthis->GetFileSelection();
|
||
|
orig_filename = pthis->GetImageFilename();
|
||
|
if ( !fs || !orig_filename )
|
||
|
return;
|
||
|
|
||
|
dest_filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION(fs));
|
||
|
if ( !dest_filename )
|
||
|
return;
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
printf("Saving %s to %s\n", orig_filename, dest_filename);
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* I'm just doing a simple 'cp' command with the shell.
|
||
|
* This probobly should be done in a NSPR safe kind
|
||
|
* of way.
|
||
|
*/
|
||
|
|
||
|
// cp /tmp/nsSanePlugin.###.jpg /path/to/save/to.jpg
|
||
|
cmd = (gchar *)PR_Malloc(PL_strlen(orig_filename) +
|
||
|
PL_strlen(dest_filename) + 6);
|
||
|
if (!cmd)
|
||
|
return;
|
||
|
|
||
|
sprintf(cmd, "cp %s %s", orig_filename, dest_filename);
|
||
|
system(cmd);
|
||
|
|
||
|
PR_FREEIF(cmd);
|
||
|
}
|
||
|
|
||
|
// END of Helper Global Functions
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|