Back to index

lightning-sunbird  0.9+nobinonly
nsSanePlugin.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org Code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 2001
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 /*
00039  * Implements the nsSanePluginInterface for the SANE plugin
00040  */
00041 
00042 #include <unistd.h>
00043 #include <stdio.h>
00044 #include <string.h>
00045 #include <fcntl.h>
00046 #include <errno.h>
00047 #include <setjmp.h>
00048 #include <gdk/gdk.h>
00049 #include <gdk/gdkprivate.h>
00050 #include <gtk/gtk.h>
00051 #include <sys/mman.h>
00052 #include <sys/types.h>
00053 #include <sys/stat.h>
00054 #include "nsIIOService.h"
00055 #include "nsSanePlugin.h"
00056 #include "plstr.h"
00057 #include "prmem.h"
00058 #include "nsIEventQueueService.h"
00059 #include "nsIEventQueue.h"
00060 
00061 extern "C"
00062 {
00063 #include "jpeglib.h"
00064 #include "sane/sane.h"
00065 #include "sane/sanei.h"
00066 #include "sane/saneopts.h"
00067 }
00068 
00069 #define MAX_OPT_SIZE (1024 * 2)
00070 
00071 struct my_JPEG_error_mgr
00072 {
00073     struct jpeg_error_mgr pub;
00074     sigjmp_buf setjmp_buffer;
00075 };
00076 typedef struct my_JPEG_error_mgr *emptr;
00077 
00078 static void PR_CALLBACK ThreadedDestroyEvent(PLEvent* aEvent);
00079 static void PR_CALLBACK ThreadedHandleEvent(PLEvent* aEvent);
00080 
00081 //static void PR_CALLBACK scanimage_thread_routine( void * arg );
00082 
00083 static void store_filename(GtkFileSelection *selector, gpointer user_data);
00084 static nsresult optioncat( char ** dest, const char * src, 
00085                            const char * ending );
00086 static void my_jpeg_error_exit (j_common_ptr cinfo);
00087 static unsigned char* jpeg_file_to_rgb (FILE * f, int *w, int *h);
00088 static gboolean draw (GtkWidget *widget, GdkEventExpose *event, gpointer data);
00089 static unsigned char * crop_image(unsigned char *rgb_data, int *rgb_width, 
00090                                   int *rgb_height,      gint x, gint y, 
00091                                   gint w, gint h);
00092 static unsigned char * scale_image(unsigned char *rgb_data, int rgb_width, 
00093                                    int rgb_height, int w, int h);
00094 
00095 static PRInt32 gPluginObjectCount = 0;
00096 
00097 static NS_DEFINE_CID(kCPluginManagerCID,        NS_PLUGINMANAGER_CID         );
00098 static NS_DEFINE_CID(kEventQueueService,        NS_EVENTQUEUESERVICE_CID     );
00099 
00100 
00102 // Plugin Instance API Methods
00103 
00104 nsSanePluginInstance::nsSanePluginInstance( void )
00105     : fPeer( NULL ), fWindow( NULL ), fMode( nsPluginMode_Embedded )
00106 {
00107 #ifdef DEBUG
00108     printf("nsSanePluginInstance::nsSanePluginInstance()\n");
00109 #endif
00110 
00111     PR_AtomicIncrement(&gPluginObjectCount);
00112 
00113     // set default jpeg compression attributes
00114     mCompQuality = 10;
00115     mCompMethod = JDCT_FASTEST;
00116 
00117     // Initialize sane interface
00118     mSaneDevice = nsnull;
00119     mSaneOpen = SANE_FALSE;
00120     mRGBData = nsnull;
00121     mBottomRightXChange = mBottomRightYChange = 
00122         mTopLeftXChange = mTopLeftYChange = 0;
00123 
00124     // initialize JavaScript callback members
00125     mOnScanCompleteScript = nsnull;
00126     mOnInitCompleteScript = nsnull;
00127     mScanThread = nsnull;
00128     mUIThread = PR_GetCurrentThread();
00129 
00130     mState = 0; // idle
00131     mSuccess = 1; // success
00132     mFileSelection = nsnull;
00133 
00134     // initialize gtk widgets
00135     fPlatform.widget = nsnull;
00136     mEvent_box = nsnull;
00137     mDrawing_area = nsnull;
00138 
00139     if (NS_FAILED(CallCreateInstance(kCPluginManagerCID, &mPluginManager))) {
00140         NS_ERROR("Error trying to create plugin manager!");
00141         return;
00142     }
00143 }
00144 
00145 nsSanePluginInstance::~nsSanePluginInstance(void)
00146 {
00147 #ifdef DEBUG
00148     printf("nsSanePluginInstance::~nsSanePluginInstance(%i)\n", 
00149            gPluginObjectCount );
00150 #endif 
00151 
00152     PR_AtomicDecrement(&gPluginObjectCount);
00153     PlatformDestroy(); // Perform platform specific cleanup
00154 
00155     if (mPluginManager) {
00156         mPluginManager->Release();
00157         mPluginManager = nsnull;
00158     }
00159 
00160     sane_exit();
00161 
00162     // cleanup old widgets
00163     if (fPlatform.widget)
00164         gtk_widget_destroy(fPlatform.widget);
00165     if (mEvent_box)
00166         gtk_widget_destroy(mEvent_box);
00167     if (mDrawing_area)
00168         gtk_widget_destroy(mDrawing_area);
00169 
00170     NS_IF_RELEASE(fPeer); 
00171     PR_FREEIF(mSaneDevice);
00172     PR_FREEIF(mOnScanCompleteScript);
00173     PR_FREEIF(mOnInitCompleteScript);
00174 
00175 }
00176 
00177 // This macro produces simple versions of QueryInterface, AddRef and Release
00178 // See the nsISupports.h header file for details.
00179 NS_IMPL_ISUPPORTS2(nsSanePluginInstance, 
00180                    nsIPluginInstance, 
00181                    nsISanePluginInstance)
00182 
00183 NS_METHOD
00184 nsSanePluginInstance::Initialize( nsIPluginInstancePeer* peer )
00185 {
00186 #ifdef DEBUG
00187     printf("nsSanePluginInstance::Initialize()\n");
00188 #endif
00189 
00190     NS_ASSERTION(peer != NULL, "null peer");
00191 
00192     nsIPluginTagInfo * taginfo;
00193     const char * const * names = nsnull;
00194     const char * const * values = nsnull;
00195     PRUint16 count = 0;
00196     nsresult result;
00197 
00198     gdk_rgb_init();
00199 
00200     fPeer = peer;
00201     peer->AddRef();
00202     result = peer->GetMode( &fMode );
00203 
00204     if ( NS_FAILED( result ) )
00205         return result;
00206 
00207     result = peer->QueryInterface( nsIPluginTagInfo::GetIID(),
00208                                    ( void ** )&taginfo );
00209 
00210     if ( NS_SUCCEEDED( result ) )
00211     {
00212         taginfo->GetAttributes( count, names, values );
00213         NS_IF_RELEASE( taginfo );
00214     }
00215 
00216     // Initialize default line attribute info
00217     mLineWidth = 5;
00218     mLineStyle = GDK_LINE_ON_OFF_DASH;
00219     mCapStyle = GDK_CAP_BUTT;
00220     mJoinStyle = GDK_JOIN_MITER;
00221 
00222     // Get user requested attribute info
00223     for (int i=0; i < count; i++) {
00224 
00225         if (PL_strcasecmp(names[i], "line_width") == 0) {
00227             // Line width
00228             sscanf(values[i], "%i", &mLineWidth);
00229 
00230         } else if (PL_strcasecmp(names[i], "line_style") == 0) {
00232             // Line style
00233             if (PL_strcasecmp(values[i], "dash") == 0) 
00234                 mLineStyle = GDK_LINE_ON_OFF_DASH;
00235             else if (PL_strcasecmp(values[i], "solid") == 0)
00236                 mLineStyle = GDK_LINE_SOLID;
00237             else if (PL_strcasecmp(values[i], "double_dash") == 0)
00238                 mLineStyle = GDK_LINE_DOUBLE_DASH;
00239 
00240         } else if (PL_strcasecmp(names[i], "cap_style") == 0) {
00242             // Cap style
00243             if (PL_strcasecmp(values[i], "round") == 0) 
00244                 mCapStyle = GDK_CAP_ROUND;
00245             else if (PL_strcasecmp(values[i], "projecting") == 0)
00246                 mCapStyle = GDK_CAP_PROJECTING;
00247             else if (PL_strcasecmp(values[i], "butt") == 0)
00248                 mCapStyle = GDK_CAP_BUTT;
00249             else if (PL_strcasecmp(values[i], "not_last") == 0)
00250                 mCapStyle = GDK_CAP_NOT_LAST;
00251 
00252         } else if (PL_strcasecmp(names[i], "join_style") == 0) {
00254             // Join style
00255             if (PL_strcasecmp(values[i], "miter") == 0) 
00256                 mJoinStyle = GDK_JOIN_MITER;
00257             else if (PL_strcasecmp(values[i], "round") == 0)
00258                 mJoinStyle = GDK_JOIN_ROUND;
00259             else if (PL_strcasecmp(values[i], "bevel") == 0)
00260                 mJoinStyle = GDK_JOIN_BEVEL;
00261 
00262         } else if (PL_strcasecmp(names[i], "device") == 0) {
00264             // Device
00265             PR_FREEIF(mSaneDevice);
00266             mSaneDevice = PL_strdup(values[i]);
00267         } else if (PL_strcasecmp(names[i], "onScanComplete") == 0) {
00269             // onScanComplete Callback
00270             PR_FREEIF(mOnScanCompleteScript);
00271             mOnScanCompleteScript = PL_strdup(values[i]);
00272         } else if(PL_strcasecmp(names[i], "onInitComplete") == 0) {
00274             // onInitComplete Callback
00275             PR_FREEIF(mOnInitCompleteScript);
00276             mOnInitCompleteScript = PL_strdup(values[i]);
00277         }
00278        }
00279     
00280     // the mImageFilename is used to store data directly 
00281     // from the sane device and also rendering to the screen
00282     sprintf( mImageFilename, "/tmp/nsSanePlugin.%p.jpg", (void *)this );
00283 
00284     PlatformNew();   /* Call Platform-specific initializations */
00285     return NS_OK;
00286 
00287 }
00288 
00289 NS_METHOD
00290 nsSanePluginInstance::SaveImage()
00291 {
00292 #ifdef DEBUG
00293     printf("nsSanePluginInstance::SaveImage()\n");
00294 #endif
00295     
00296     if (!mImageFilename) {
00297         NS_ERROR("Attempt to save image before initial scan!");
00298         return NS_ERROR_FAILURE;
00299     }
00300 
00301     mFileSelection = gtk_file_selection_new("Choose file to save image to.");
00302     
00303     // Set a default filename
00304     gtk_file_selection_set_filename(GTK_FILE_SELECTION(mFileSelection),
00305                                     "saved.jpg");
00306 
00307     // Callback for getting the filename
00308     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(mFileSelection)->ok_button),
00309                        "clicked", GTK_SIGNAL_FUNC (store_filename), 
00310                        (gpointer) this);
00311 
00312     // Ensure the file selection dialog goes away after
00313     // 'OK' or 'CANCEL' button is selected
00314     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(mFileSelection)->ok_button),
00315                               "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
00316                               GTK_OBJECT(mFileSelection));
00317     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(mFileSelection)->cancel_button),
00318                               "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
00319                               GTK_OBJECT(mFileSelection));
00320 
00321     // ok, now show the file selection dialog
00322     gtk_widget_show(mFileSelection);
00323     
00324     return NS_OK;
00325 }
00326 
00327 NS_METHOD
00328 nsSanePluginInstance::DoScanCompleteCallback()
00329 {
00330 #ifdef DEBUG
00331     printf("nsSanePluginInstance::DoScanCompleteCallback()\n");
00332 #endif
00333 
00334     char *url;
00335 
00336     if (mOnScanCompleteScript && mPluginManager) {
00337         url = (char *)PR_Malloc(PL_strlen(mOnScanCompleteScript) + 13);
00338         if (!url)
00339             return NS_ERROR_OUT_OF_MEMORY;
00340 
00341         sprintf(url, "javascript:%s", mOnScanCompleteScript);   
00342         mPluginManager->GetURL((nsIPluginInstance *)this, url, "_self");
00343 
00344         PR_FREEIF(url);
00345     }
00346     return NS_OK;
00347 }
00348 
00349 NS_METHOD
00350 nsSanePluginInstance::DoInitCompleteCallback()
00351 {
00352 #ifdef DEBUG
00353     printf("nsSanePluginInstance::DoInitCompleteCallback()\n");
00354 #endif
00355 
00356     char *url;
00357 
00358     if (mOnInitCompleteScript && mPluginManager) {
00359         url = (char *)PR_Malloc(PL_strlen(mOnInitCompleteScript) + 13);
00360         if (!url)
00361             return NS_ERROR_OUT_OF_MEMORY;
00362 
00363         sprintf(url, "javascript:%s", mOnInitCompleteScript);   
00364         mPluginManager->GetURL((nsIPluginInstance *)this, url, "_self");
00365 
00366         PR_FREEIF(url);
00367     }
00368 
00369     return NS_OK;
00370 }
00371 
00372 NS_METHOD
00373 nsSanePluginInstance::GetPeer( nsIPluginInstancePeer* *result )
00374 {
00375 #ifdef DEBUG
00376     printf("nsSanePluginInstance::GetPeer()\n");
00377 #endif
00378 
00379     fPeer->AddRef();
00380     *result = fPeer;
00381     return NS_OK;
00382 }
00383 
00384 NS_METHOD
00385 nsSanePluginInstance::Start( void )
00386 {
00387 #ifdef DEBUG
00388     printf("nsSanePluginInstance::Start()\n");
00389 #endif
00390 
00391     PR_FREEIF(mRGBData);
00392     mRGBData = nsnull;
00393 
00394     sane_init(0,0);
00395     mSaneOpen = SANE_FALSE;
00396     nsresult rv = OpenSaneDeviceIF();
00397     if (rv != NS_OK) {
00398         NS_ERROR("Failed to open device in Start()\n");
00399         return rv;
00400     }
00401 
00402     PlatformNew();
00403 
00404     // call onInitComplete callback
00405     DoInitCompleteCallback();
00406     return NS_OK;
00407 }
00408 
00409 NS_METHOD
00410 nsSanePluginInstance::Stop( void )
00411 {
00412 #ifdef DEBUG
00413     printf("nsSanePluginInstance::Stop()\n");
00414 #endif
00415 
00416     // Wait for scanner operation to complete.
00417     // TODO: Warn user that they are still scanning
00418     //       and send abort command to scanner if 
00419     //       the user wishes.
00420     if (mScanThread)
00421         PR_JoinThread(mScanThread);
00422 
00423     PR_FREEIF(mRGBData);
00424 
00425     // close sane
00426     if (mSaneOpen) {
00427         sane_close(mSaneHandle);
00428         sane_exit();
00429         mSaneOpen = SANE_FALSE;
00430     }
00431 
00432     if (remove ( mImageFilename ) == -1)
00433         perror(mImageFilename);
00434 
00435     return NS_OK;
00436 }
00437 
00438 NS_METHOD
00439 nsSanePluginInstance::Destroy( void )
00440 {
00441 #ifdef DEBUG
00442     printf("nsSanePluginInstance::Destroy()\n");
00443 #endif
00444 
00445     return NS_OK;
00446 }
00447 
00448 NS_METHOD
00449 nsSanePluginInstance::SetWindow(nsPluginWindow* window)
00450 {
00451 #ifdef DEBUG
00452     printf("nsSanePluginInstance::SetWindow()\n");
00453 #endif
00454 
00455     nsresult result;
00456 
00457     // The real work is handled in PlatformSetWindow
00458     // (as if this plug-in was multiplatform)
00459     result = PlatformSetWindow( window );
00460     fWindow = window;
00461 
00462     return result;
00463 }
00464 
00465 NS_METHOD
00466 nsSanePluginInstance::NewStream( nsIPluginStreamListener** listener )
00467 {
00468 #ifdef DEBUG
00469     printf("nsSanePluginInstance::NewStream()\n");
00470 #endif
00471 
00472     if ( listener != NULL )
00473         *listener = new nsSanePluginStreamListener( this );
00474     
00475     return NS_OK;
00476 }
00477 
00478 NS_METHOD
00479 nsSanePluginInstance::Print( nsPluginPrint* printInfo )
00480 {
00481 #ifdef DEBUG
00482     printf("nsSanePluginInstance::Print()\n");
00483 #endif
00484 
00485     if ( printInfo == NULL )
00486         return NS_ERROR_FAILURE;
00487 
00488     // needs to be implemented
00489     return NS_ERROR_NOT_IMPLEMENTED;
00490 }
00491 
00492 NS_METHOD
00493 nsSanePluginInstance::HandleEvent(nsPluginEvent* event, PRBool* handled)
00494 {
00495 #ifdef DEBUG
00496     printf("nsSanePluginInstance::HandleEvent()\n");
00497 #endif
00498 
00499     // Not used on unix platform.  Only here for potential
00500     // future porting efforts
00501     *handled = (PRBool)PlatformHandleEvent(event);
00502     return NS_OK;
00503 }
00504 
00505 NS_METHOD
00506 nsSanePluginInstance::GetValue(nsPluginInstanceVariable variable, void *value)
00507 {
00508 #ifdef DEBUG
00509     printf("nsSanePluginInstance::GetValue()\n");
00510 #endif
00511 
00512     //Needs to be implemented
00513     return NS_ERROR_NOT_IMPLEMENTED;
00514 }
00515 
00516 void
00517 nsSanePluginInstance::PlatformNew( void )
00518 {
00519 #ifdef DEBUG
00520     printf("nsSaneInstance::PlatformNew\n");
00521 #endif
00522 
00523     fPlatform.window = 0;
00524 }
00525 
00526 nsresult
00527 nsSanePluginInstance::PlatformDestroy( void )
00528 {
00529 #ifdef DEBUG
00530     printf("nsSaneInstance::PlatformDestroy()\n");
00531 #endif
00532 
00533        return NS_OK;
00534 }
00535 
00536 nsresult
00537 nsSanePluginInstance::PlatformSetWindow( nsPluginWindow* window )
00538 {
00539 #ifdef DEBUG
00540     printf("nsSaneInstance::PlatformSetWindow()\n");
00541 #endif
00542 
00543 
00544     if ( window == NULL || window->window == NULL )
00545         return NS_ERROR_NULL_POINTER;
00546     
00547     if ( fPlatform.superwin == (GdkSuperWin *)window->window )
00548         return NS_OK;
00549 
00550     // Record windowing info
00551     fPlatform.superwin = (GdkSuperWin *)window->window;
00552     fPlatform.height = window->height;
00553     fPlatform.width = window->width;
00554 
00555     // cleanup old widgets
00556     if (fPlatform.widget)
00557         gtk_widget_destroy(fPlatform.widget);
00558     if (mEvent_box)
00559         gtk_widget_destroy(mEvent_box);
00560     if (mDrawing_area)
00561         gtk_widget_destroy(mDrawing_area);
00562 
00563     fPlatform.widget = gtk_mozbox_new(fPlatform.superwin->bin_window);
00564 
00565     // Initialize the zoom box to outline the entire image
00566     mZoom_box.x = 0;
00567     mZoom_box.y = 0;
00568     mZoom_box.width = fPlatform.width;
00569     mZoom_box.height = fPlatform.height;
00570 
00571     // Setup an event box to contain the drawable
00572     mEvent_box = gtk_event_box_new();
00573     gtk_container_add(GTK_CONTAINER(fPlatform.widget), mEvent_box);
00574     gtk_widget_show(mEvent_box);
00575 
00576     // Setup the drawable
00577     mDrawing_area = ( GtkWidget * )gtk_drawing_area_new();
00578     gtk_drawing_area_size( GTK_DRAWING_AREA( mDrawing_area ),
00579                            window->width, window->height);
00580     gtk_container_add(GTK_CONTAINER(mEvent_box), mDrawing_area);
00581     gtk_widget_show(mDrawing_area);
00582 
00583     // Initialize line attributes for GC
00584     GdkGC * da_gc = mDrawing_area->style->fg_gc[mDrawing_area->state];
00585     gdk_gc_set_line_attributes ( da_gc, mLineWidth, mLineStyle, 
00586                                  mCapStyle, mJoinStyle);
00587 
00588     // Register signals
00589     gtk_signal_connect (GTK_OBJECT(mDrawing_area), "expose_event",
00590                         GTK_SIGNAL_FUNC(draw), this);
00591 
00592     // Now make everything visable
00593     gtk_widget_show( fPlatform.widget );
00594 
00595     return NS_OK;
00596 }
00597 
00598 int16
00599 nsSanePluginInstance::PlatformHandleEvent(nsPluginEvent* event)
00600 {
00601 #ifdef DEBUG
00602     printf("nsSaneInstance::PlatformHandleEvent()\n");
00603 #endif
00604 
00605     /* UNIX Plugins do not use HandleEvent */
00606     return 0;
00607 }
00608 
00609 
00610 NS_IMETHODIMP
00611 nsSanePluginInstance::PaintImage(void)
00612 {
00613 #ifdef DEBUG
00614     printf("nsSaneInstance::PaintImage(%p)\n", this);
00615 #endif
00616 
00617     if (mDrawing_area && fPlatform.widget) {
00618         if (mImageFilename) {
00619 
00620             if (!mRGBData) {
00621 
00622                 if (mState)
00623                     // we are currently scanning, so the jpeg file
00624                     // is not valid yet
00625                     return NS_OK;
00626                 
00627                 FILE * f = fopen(mImageFilename, "rb");
00628                 if (!f) 
00629                     // it's possible that an image hasn't been scanned yet
00630                     return NS_OK;
00631 
00632                 mRGBData = jpeg_file_to_rgb(f, &mRGBWidth, &mRGBHeight);
00633                 if (!mRGBData) {
00634                     NS_ERROR("Error converting jpeg to rgb data!");
00635                     return NS_ERROR_FAILURE;
00636                 }
00637 
00638                 fclose(f);
00639 
00640                 // scale down to window size
00641                 unsigned char * tmp = scale_image( mRGBData, 
00642                                                    mRGBWidth, mRGBHeight,
00643                                                    fPlatform.width,
00644                                                    fPlatform.height);
00645                 if (!tmp) {
00646                     NS_ERROR("Error trying to scale image!");
00647                     return NS_ERROR_FAILURE;
00648                 }
00649 
00650                 // move to new data
00651                 PR_FREEIF(mRGBData);
00652                 mRGBData = tmp;
00653             }
00654 
00655             // render the image
00656             gdk_draw_rgb_image (mDrawing_area->window, 
00657                                 mDrawing_area->style->fg_gc[GTK_STATE_NORMAL],
00658                                 0, 0, fPlatform.width, fPlatform.height,
00659                                 GDK_RGB_DITHER_MAX, mRGBData, 
00660                                 fPlatform.width * 3);
00661 
00662             gdk_draw_rectangle (mDrawing_area->window,
00663                                 mDrawing_area->style->fg_gc[mDrawing_area->state],
00664                                 FALSE, mZoom_box.x, mZoom_box.y, 
00665                                 mZoom_box.width, mZoom_box.height);        
00666             
00667             gdk_flush();
00668         }
00669     }
00670 
00671     return NS_OK;
00672 }
00673 
00674 char *
00675 nsSanePluginInstance::GetImageFilename()
00676 {
00677     if (!mImageFilename)
00678         return (char *)NULL;
00679     
00680     // Caller is responsible for freeing string
00681     return PL_strdup(mImageFilename);
00682 }
00683 
00684 GtkWidget *
00685 nsSanePluginInstance::GetFileSelection()
00686 {
00687     if (!mFileSelection)
00688         return (GtkWidget *)NULL;
00689 
00690     return mFileSelection;
00691 }
00692 
00693 PRBool
00694 nsSanePluginInstance::IsUIThread()
00695 {
00696     if (!mUIThread)
00697         return PR_FALSE;
00698 
00699     return (mUIThread == PR_GetCurrentThread());
00700 }
00701 
00702 // End of Plugin Instance API Methods.
00704 
00706 // Image Preview Interface.
00707 
00708 NS_IMETHODIMP
00709 nsSanePluginInstance::ZoomImage( PRUint16 x, PRUint16 y, 
00710                                  PRUint16 width, PRUint16 height)
00711 {
00712 #ifdef DEBUG
00713     printf("nsSaneInstance::ZoomImage()\n");
00714 #endif
00715 
00716     int im_width, im_height, c_width, c_height, c_x, c_y;
00717 
00718     if (!mRGBData)
00719         return NS_ERROR_FAILURE;
00720 
00721     // get the actual image width and height
00722     im_width = mRGBWidth;
00723     im_height = mRGBHeight;
00724 
00725     if ( x >= (PRUint16)fPlatform.width ||
00726          y >= (PRUint16)fPlatform.height )
00727         return NS_ERROR_FAILURE;
00728 
00729     if ( width + mZoom_box.x >= (PRUint16)fPlatform.width )
00730         mZoom_box.width = fPlatform.width - mZoom_box.x;
00731 
00732     if ( height + mZoom_box.y >= (PRUint16) fPlatform.height )
00733         mZoom_box.height = fPlatform.height - mZoom_box.y;
00734 
00735     mZoom_box.x = x;
00736     mZoom_box.y = y;
00737 
00738     // translate the zoom box geometry to the image geometry
00739     c_width = (int)(((double)im_width/(double)fPlatform.width) * 
00740                     (double)mZoom_box.width);
00741     c_height =(int)(((double)im_height/(double)fPlatform.height) * 
00742                     (double)mZoom_box.height);
00743     c_x = (int)(((double)im_width/(double)fPlatform.width) * 
00744                 (double)mZoom_box.x);
00745     c_y = (int)(((double)im_height/(double)fPlatform.height) * 
00746                 (double)mZoom_box.y);
00747 
00748     unsigned char * tmp = crop_image(mRGBData, &mRGBWidth, &mRGBHeight,
00749                                      c_x, c_y, c_width, c_height);
00750     if (!tmp)
00751         return NS_ERROR_FAILURE;
00752     PR_FREEIF(mRGBData);
00753     mRGBData = tmp;
00754 
00755     mRGBWidth = c_width;
00756     mRGBHeight = c_height;
00757 
00758     mTopLeftXChange = (float)x/(float)fPlatform.width;
00759     mTopLeftYChange = (float)y/(float)fPlatform.height;
00760     mBottomRightXChange = (float)(fPlatform.width - (PRInt32)(x + mZoom_box.width))/(float)fPlatform.width;
00761     mBottomRightYChange = (float)(fPlatform.height - (PRInt32)(y + mZoom_box.height))/(float)fPlatform.height;
00762 
00763     mZoom_box.x = 0;
00764     mZoom_box.y = 0;
00765     mZoom_box.width = (PRUint16)fPlatform.width;
00766     mZoom_box.height = (PRUint16)fPlatform.height;
00767 
00768     return PaintImage();
00769 }
00770 
00771 NS_IMETHODIMP
00772 nsSanePluginInstance::ZoomImageWithAttributes( PRUint16 x, PRUint16 y, 
00773                                                PRUint16 width, PRUint16 height,
00774                                                PRInt32 req_line_width,
00775                                                const char * req_line_style,
00776                                                const char * req_cap_style,
00777                                                const char * req_join_style )
00778 {
00779 #ifdef DEBUG
00780     printf("nsSaneInstance::ZoomImageWithAttributes()\n");
00781 #endif
00782 
00783     if (!mRGBData)
00784         return NS_ERROR_FAILURE;
00785 
00786     ZoomImage(x, y, width, height);
00787 
00788     /*
00789      * Set zoom box line attributes
00790      */
00791 
00792     // Line Width
00793     mLineWidth = req_line_width;
00794 
00795     // Line Style
00796     if (PL_strcasecmp(req_line_style, "dash") == 0) 
00797         mLineStyle = GDK_LINE_ON_OFF_DASH;
00798     else if (PL_strcasecmp(req_line_style, "solid") == 0)
00799         mLineStyle = GDK_LINE_SOLID;
00800     else if (PL_strcasecmp(req_line_style, "double_dash") == 0)
00801         mLineStyle = GDK_LINE_DOUBLE_DASH;
00802 
00803     // Cap Style
00804     if (PL_strcasecmp(req_cap_style, "round") == 0) 
00805         mCapStyle = GDK_CAP_ROUND;
00806     else if (PL_strcasecmp(req_cap_style, "projecting") == 0)
00807         mCapStyle = GDK_CAP_PROJECTING;
00808     else if (PL_strcasecmp(req_cap_style, "butt") == 0)
00809         mCapStyle = GDK_CAP_BUTT;
00810     else if (PL_strcasecmp(req_cap_style, "not_last") == 0)
00811         mCapStyle = GDK_CAP_NOT_LAST;
00812 
00813     // Join Style
00814     if (PL_strcasecmp(req_join_style, "miter") == 0) 
00815         mJoinStyle = GDK_JOIN_MITER;
00816     else if (PL_strcasecmp(req_join_style, "round") == 0)
00817         mJoinStyle = GDK_JOIN_ROUND;
00818     else if (PL_strcasecmp(req_join_style, "bevel") == 0)
00819         mJoinStyle = GDK_JOIN_BEVEL;
00820 
00821     // Refresh
00822     return PaintImage();
00823 }
00824 
00825 NS_IMETHODIMP
00826 nsSanePluginInstance::Crop(PRUint16 x, PRUint16 y, 
00827                            PRUint16 width, PRUint16 height)
00828 {
00829 #ifdef DEBUG
00830     printf("nsSaneInstance::Crop()\n");
00831 #endif
00832 
00833     if ( (x <= (PRUint16)fPlatform.width - width ) &&
00834          (y <= (PRUint16)fPlatform.height - height) ) {
00835         
00836         mZoom_box.x = x; mZoom_box.y = y;
00837         mZoom_box.width = width;
00838         mZoom_box.height = height;
00839 
00840     } else {
00841         return NS_ERROR_FAILURE;
00842     }
00843 
00844     return PaintImage();
00845 }
00846 
00847 NS_IMETHODIMP
00848 nsSanePluginInstance::Restore(void)
00849 {
00850 #ifdef DEBUG
00851     printf("nsSaneInstance::Restore()\n");
00852 #endif
00853 
00854     PR_FREEIF(mRGBData);
00855     mRGBData = nsnull;
00856 
00857     // Reset zoom box
00858     mZoom_box.x = mZoom_box.y = 0;
00859     mZoom_box.width = (PRUint16) fPlatform.width;
00860     mZoom_box.height = (PRUint16) fPlatform.height;
00861 
00862     PaintImage();
00863 
00864     return NS_OK;
00865 }
00866 
00867 
00868 NS_IMETHODIMP
00869 nsSanePluginInstance::GetZoomX(PRUint16 * x) 
00870 {
00871 #ifdef DEBUG
00872     printf("nsSaneInstance::GetZoomX()\n");
00873 #endif
00874 
00875     NS_ASSERTION(x != NULL, "null x pointer");
00876     if (!x)
00877         return NS_ERROR_NULL_POINTER;
00878 
00879     *x = mZoom_box.x;
00880     
00881     return NS_OK;
00882 }
00883 
00884 NS_IMETHODIMP
00885 nsSanePluginInstance::SetZoomX(PRUint16 x) 
00886 {
00887 #ifdef DEBUG
00888     printf("nsSaneInstance::SetZoomX()\n");
00889 #endif
00890 
00891     if (x > (PRInt32) fPlatform.width)
00892         mZoom_box.x = (PRInt32) fPlatform.width;
00893     else
00894         mZoom_box.x = x;
00895 
00896     return PaintImage();
00897 }
00898 
00899 
00900 NS_IMETHODIMP
00901 nsSanePluginInstance::GetZoomY(PRUint16 * y) 
00902 {
00903 #ifdef DEBUG
00904     printf("nsSaneInstance::GetZoomY()\n");
00905 #endif
00906 
00907     NS_ASSERTION(y != NULL, "null y pointer");
00908     if (!y)
00909         return NS_ERROR_NULL_POINTER;
00910 
00911     *y = mZoom_box.y;
00912     
00913     return NS_OK;
00914 }
00915 
00916 NS_IMETHODIMP
00917 nsSanePluginInstance::SetZoomY(PRUint16 y) 
00918 {
00919 #ifdef DEBUG
00920     printf("nsSaneInstance::SetZoomY()\n");
00921 #endif
00922 
00923     if (y > (PRInt32) fPlatform.height)
00924         mZoom_box.y = (PRInt32)fPlatform.height;
00925     else
00926         mZoom_box.y = y;
00927     
00928     return PaintImage();
00929 }
00930 
00931 NS_IMETHODIMP
00932 nsSanePluginInstance::GetZoomWidth(PRUint16 * width) 
00933 {
00934 #ifdef DEBUG
00935     printf("nsSaneInstance::GetZoomWidth()\n");
00936 #endif
00937 
00938     NS_ASSERTION(width != NULL, "null width pointer");
00939     if (!width)
00940         return NS_ERROR_NULL_POINTER;
00941 
00942     *width = mZoom_box.width;
00943     
00944     return NS_OK;
00945 }
00946 
00947 NS_IMETHODIMP
00948 nsSanePluginInstance::SetZoomWidth(PRUint16 width) 
00949 {
00950 #ifdef DEBUG
00951     printf("nsSaneInstance::SetZoomWidth()\n");
00952 #endif
00953 
00954     if (width + mZoom_box.x > (PRUint16)fPlatform.width)
00955         mZoom_box.width = (PRInt32) fPlatform.width - mZoom_box.x;
00956     else
00957         mZoom_box.width = width;
00958 
00959     return PaintImage();
00960 }
00961 
00962 NS_IMETHODIMP
00963 nsSanePluginInstance::GetZoomHeight(PRUint16 * height) 
00964 {
00965 #ifdef DEBUG
00966     printf("nsSaneInstance::GetZoomHeight()\n");
00967 #endif
00968 
00969     NS_ASSERTION(height != NULL, "null height pointer");
00970     if (!height)
00971         return NS_ERROR_NULL_POINTER;
00972 
00973     *height = mZoom_box.height;
00974     
00975     return NS_OK;
00976 }
00977 
00978 NS_IMETHODIMP
00979 nsSanePluginInstance::SetZoomHeight(PRUint16 height) 
00980 {
00981 #ifdef DEBUG
00982     printf("nsSaneInstance::SetZoomHeight()\n");
00983 #endif
00984 
00985     if (height + mZoom_box.y > (PRUint16) fPlatform.height)
00986         mZoom_box.height = fPlatform.height - mZoom_box.y;
00987     else
00988         mZoom_box.height = height;
00989 
00990     return PaintImage();
00991 }
00992 
00993 NS_IMETHODIMP
00994 nsSanePluginInstance::GetZoomLineWidth(PRInt32 * aZoomLineWidth) 
00995 {
00996 #ifdef DEBUG
00997     printf("nsSaneInstance::GetZoomLineWidth()\n");
00998 #endif
00999 
01000     NS_ASSERTION(aZoomLineWidth != NULL, "null width pointer");   
01001     if (!aZoomLineWidth)
01002         return NS_ERROR_NULL_POINTER;
01003 
01004     *aZoomLineWidth = mLineWidth;
01005 
01006     return NS_OK;
01007 }
01008 
01009 NS_IMETHODIMP
01010 nsSanePluginInstance::SetZoomLineWidth(PRInt32 aZoomLineWidth) 
01011 {
01012 #ifdef DEBUG
01013     printf("nsSaneInstance::SetZoomLineWidth()\n");
01014 #endif
01015 
01016     if (aZoomLineWidth <= 0)
01017         return NS_ERROR_INVALID_ARG;
01018 
01019     mLineWidth = aZoomLineWidth;
01020 
01021     return PaintImage();
01022 }
01023 
01024 #define MAX_LINE_ATTRIBUTE_LENGTH 20
01025 
01026 NS_IMETHODIMP
01027 nsSanePluginInstance::GetZoomLineStyle(char ** aZoomLineStyle) 
01028 {
01029 #ifdef DEBUG
01030     printf("nsSaneInstance::GetZoomLineStyle()\n");
01031 #endif
01032 
01033     NS_ASSERTION(*aZoomLineStyle != NULL, "null width pointer");   
01034     if (!*aZoomLineStyle)
01035         return NS_ERROR_NULL_POINTER;
01036 
01037     *aZoomLineStyle = (char*) nsMemory::Alloc(MAX_LINE_ATTRIBUTE_LENGTH);
01038     if (! *aZoomLineStyle)
01039         return NS_ERROR_OUT_OF_MEMORY;
01040     
01041     if (mLineStyle == GDK_LINE_ON_OFF_DASH)
01042         PL_strcpy(*aZoomLineStyle, "dash");
01043     else if (mLineStyle == GDK_LINE_SOLID)
01044         PL_strcpy(*aZoomLineStyle, "solid");
01045     else if (mLineStyle == GDK_LINE_DOUBLE_DASH)
01046         PL_strcpy(*aZoomLineStyle, "double_dash");
01047     else
01048         PL_strcpy(*aZoomLineStyle, "unknown");
01049 
01050     return PaintImage();
01051 }
01052 
01053 NS_IMETHODIMP
01054 nsSanePluginInstance::SetZoomLineStyle(const char * aZoomLineStyle) 
01055 {
01056 #ifdef DEBUG
01057     printf("nsSaneInstance::SetZoomLineStyle()\n");
01058 #endif
01059 
01060     NS_ASSERTION(aZoomLineStyle != NULL, "null width pointer");   
01061     if (!aZoomLineStyle)
01062         return NS_ERROR_NULL_POINTER;
01063 
01064     // Line Style
01065     if (PL_strcasecmp(aZoomLineStyle, "dash") == 0) 
01066         mLineStyle = GDK_LINE_ON_OFF_DASH;
01067     else if (PL_strcasecmp(aZoomLineStyle, "solid") == 0)
01068         mLineStyle = GDK_LINE_SOLID;
01069     else if (PL_strcasecmp(aZoomLineStyle, "double_dash") == 0)
01070         mLineStyle = GDK_LINE_DOUBLE_DASH;
01071 
01072     return PaintImage();
01073 }
01074 
01075 NS_IMETHODIMP
01076 nsSanePluginInstance::GetZoomCapStyle(char ** aZoomCapStyle) 
01077 {
01078 #ifdef DEBUG
01079     printf("nsSaneInstance::GetZoomCapStyle()\n");
01080 #endif
01081 
01082     NS_ASSERTION(*aZoomCapStyle != NULL, "null width pointer");   
01083     if (!*aZoomCapStyle)
01084         return NS_ERROR_NULL_POINTER;
01085 
01086     *aZoomCapStyle = (char*) nsMemory::Alloc(MAX_LINE_ATTRIBUTE_LENGTH);
01087     if (! *aZoomCapStyle)
01088         return NS_ERROR_OUT_OF_MEMORY;
01089     
01090     if (mCapStyle == GDK_CAP_ROUND)
01091         PL_strcpy(*aZoomCapStyle, "round");
01092     else if (mCapStyle == GDK_CAP_PROJECTING)
01093         PL_strcpy(*aZoomCapStyle, "projecting");
01094     else if (mCapStyle == GDK_CAP_BUTT)
01095         PL_strcpy(*aZoomCapStyle, "butt");
01096     else if (mCapStyle == GDK_CAP_NOT_LAST)
01097         PL_strcpy(*aZoomCapStyle, "not_last");
01098     else
01099         PL_strcpy(*aZoomCapStyle, "unknown");
01100 
01101 
01102     return PaintImage();
01103 }
01104 
01105 NS_IMETHODIMP
01106 nsSanePluginInstance::SetZoomCapStyle(const char * aZoomCapStyle) 
01107 {
01108 #ifdef DEBUG
01109     printf("nsSaneInstance::SetZoomCapStyle()\n");
01110 #endif
01111 
01112     NS_ASSERTION(aZoomCapStyle != NULL, "null width pointer");   
01113     if (!aZoomCapStyle)
01114         return NS_ERROR_NULL_POINTER;
01115 
01116     // Cap Style
01117     if (PL_strcasecmp(aZoomCapStyle, "round") == 0) 
01118         mCapStyle = GDK_CAP_ROUND;
01119     else if (PL_strcasecmp(aZoomCapStyle, "projecting") == 0)
01120         mCapStyle = GDK_CAP_PROJECTING;
01121     else if (PL_strcasecmp(aZoomCapStyle, "butt") == 0)
01122         mCapStyle = GDK_CAP_BUTT;
01123     else if (PL_strcasecmp(aZoomCapStyle, "not_last") == 0)
01124         mCapStyle = GDK_CAP_NOT_LAST;
01125 
01126     return PaintImage();
01127 }
01128 
01129 NS_IMETHODIMP
01130 nsSanePluginInstance::GetZoomJoinStyle(char ** aZoomJoinStyle) 
01131 {
01132 #ifdef DEBUG
01133     printf("nsSaneInstance::GetZoomJoinStyle()\n");
01134 #endif
01135 
01136     NS_ASSERTION(*aZoomJoinStyle != NULL, "null width pointer");   
01137     if (!*aZoomJoinStyle)
01138         return NS_ERROR_NULL_POINTER;
01139 
01140     *aZoomJoinStyle = (char*) nsMemory::Alloc(MAX_LINE_ATTRIBUTE_LENGTH);
01141     if (! *aZoomJoinStyle)
01142         return NS_ERROR_OUT_OF_MEMORY;
01143     
01144     if (mJoinStyle == GDK_JOIN_MITER)
01145         PL_strcpy(*aZoomJoinStyle, "miter");
01146     else if (mJoinStyle == GDK_JOIN_ROUND)
01147         PL_strcpy(*aZoomJoinStyle, "round");
01148     else if (mJoinStyle == GDK_JOIN_BEVEL)
01149         PL_strcpy(*aZoomJoinStyle, "bevel");
01150     else
01151         PL_strcpy(*aZoomJoinStyle, "unknown");
01152 
01153     return PaintImage();
01154 }
01155 
01156 NS_IMETHODIMP
01157 nsSanePluginInstance::SetZoomJoinStyle(const char * aZoomJoinStyle) 
01158 {
01159 #ifdef DEBUG
01160     printf("nsSaneInstance::SetZoomJoinStyle()\n");
01161 #endif
01162 
01163     NS_ASSERTION(aZoomJoinStyle != NULL, "null width pointer");   
01164     if (!aZoomJoinStyle)
01165         return NS_ERROR_NULL_POINTER;
01166 
01167     // Join Style
01168     if (PL_strcasecmp(aZoomJoinStyle, "miter") == 0) 
01169         mJoinStyle = GDK_JOIN_MITER;
01170     else if (PL_strcasecmp(aZoomJoinStyle, "round") == 0)
01171         mJoinStyle = GDK_JOIN_ROUND;
01172     else if (PL_strcasecmp(aZoomJoinStyle, "bevel") == 0)
01173         mJoinStyle = GDK_JOIN_BEVEL;
01174 
01175     return PaintImage();
01176 }
01177 
01178 NS_IMETHODIMP
01179 nsSanePluginInstance::GetZoomBR_XChange(float * aZoomBR_XChange) 
01180 {
01181 #ifdef DEBUG
01182     printf("nsSaneInstance::GetZoomBR_XChange()\n");
01183 #endif
01184 
01185     *aZoomBR_XChange = mBottomRightXChange;
01186     return NS_OK;
01187 }
01188 
01189 NS_IMETHODIMP
01190 nsSanePluginInstance::SetZoomBR_XChange(float aZoomBR_XChange) 
01191 {
01192 #ifdef DEBUG
01193     printf("nsSaneInstance::SetZoomBR_XChange()\n");
01194 #endif
01195 
01196     // Read-Only
01197     return NS_ERROR_NOT_AVAILABLE;
01198 }
01199 
01200 NS_IMETHODIMP
01201 nsSanePluginInstance::GetZoomBR_YChange(float * aZoomBR_YChange) 
01202 {
01203 #ifdef DEBUG
01204     printf("nsSaneInstance::GetZoomBR_YChange()\n");
01205 #endif
01206 
01207     *aZoomBR_YChange = mBottomRightYChange;
01208     return NS_OK;
01209 }
01210 
01211 NS_IMETHODIMP
01212 nsSanePluginInstance::SetZoomBR_YChange(float aZoomBR_YChange) 
01213 {
01214 #ifdef DEBUG
01215     printf("nsSaneInstance::SetZoomBR_YChange()\n");
01216 #endif
01217 
01218     // Read-Only
01219     return NS_ERROR_NOT_AVAILABLE;
01220 }
01221 
01222 NS_IMETHODIMP
01223 nsSanePluginInstance::GetZoomTL_XChange(float * aZoomTL_XChange) 
01224 {
01225 #ifdef DEBUG
01226     printf("nsSaneInstance::GetZoomTL_XChange()\n");
01227 #endif
01228 
01229     *aZoomTL_XChange = mTopLeftXChange;
01230     return NS_OK;
01231 }
01232 
01233 NS_IMETHODIMP
01234 nsSanePluginInstance::SetZoomTL_XChange(float aZoomTL_XChange) 
01235 {
01236 #ifdef DEBUG
01237     printf("nsSaneInstance::SetZoomTL_XChange()\n");
01238 #endif
01239 
01240     // Read-Only
01241     return NS_ERROR_NOT_AVAILABLE;
01242 }
01243 
01244 NS_IMETHODIMP
01245 nsSanePluginInstance::GetZoomTL_YChange(float * aZoomTL_YChange) 
01246 {
01247 #ifdef DEBUG
01248     printf("nsSaneInstance::GetZoomTL_YChange()\n");
01249 #endif
01250 
01251     *aZoomTL_YChange = mTopLeftYChange;
01252     return NS_OK;
01253 }
01254 
01255 NS_IMETHODIMP
01256 nsSanePluginInstance::SetZoomTL_YChange(float aZoomTL_YChange) 
01257 {
01258 #ifdef DEBUG
01259     printf("nsSaneInstance::SetZoomTL_YChange()\n");
01260 #endif
01261 
01262     // Read-Only
01263     return NS_ERROR_NOT_AVAILABLE;
01264 }
01265 
01266 NS_IMETHODIMP
01267 nsSanePluginInstance::GetQuality(PRInt32 * aQuality)
01268 {
01269 #ifdef DEBUG
01270     printf("nsSaneInstance::GetQuality()\n");
01271 #endif
01272 
01273     NS_ASSERTION(aQuality != NULL, "null compression quality pointer");   
01274     if (!aQuality)
01275         return NS_ERROR_NULL_POINTER;    
01276     
01277     *aQuality = mCompQuality;
01278     return NS_OK;
01279 }
01280 
01281 NS_IMETHODIMP
01282 nsSanePluginInstance::SetQuality(PRInt32 aQuality)
01283 {
01284 #ifdef DEBUG
01285     printf("nsSaneInstance::SetQuality()\n");
01286 #endif
01287 
01288     NS_ASSERTION(aQuality > -1 && aQuality < 101, 
01289                  "Invalid compression quality");
01290     if (aQuality < 0 || aQuality > 100)
01291         return NS_ERROR_INVALID_ARG;
01292 
01293     mCompQuality = aQuality;
01294     return NS_OK;
01295 }
01296 
01297 NS_IMETHODIMP
01298 nsSanePluginInstance::GetMethod(char ** aMethod)
01299 {
01300 #ifdef DEBUG
01301     printf("nsSaneInstance::GetMethod()\n");
01302 #endif
01303 
01304     NS_ASSERTION(aMethod != NULL, "Null method pointer");
01305     if (!aMethod)
01306         return NS_ERROR_NULL_POINTER;
01307 
01308     *aMethod = (char*) nsMemory::Alloc(8);
01309     if (!*aMethod)
01310         return NS_ERROR_OUT_OF_MEMORY;
01311 
01312     switch (mCompMethod) {
01313     case JDCT_ISLOW:
01314         PL_strcpy(*aMethod, "SLOW");
01315         break;
01316     case JDCT_IFAST:
01317         PL_strcpy(*aMethod, "FAST");
01318         break;
01319     case JDCT_FLOAT:
01320         PL_strcpy(*aMethod, "FLOAT");
01321         break;
01322     default:
01323         PL_strcpy(*aMethod, "DEFAULT");
01324         
01325     }
01326 
01327     return NS_OK;
01328 }
01329 
01330 NS_IMETHODIMP
01331 nsSanePluginInstance::SetMethod(const char * aMethod)
01332 {
01333 #ifdef DEBUG
01334     printf("nsSaneInstance::SetMethod()\n");
01335 #endif
01336 
01337     NS_ASSERTION(aMethod != NULL, "Null method pointer");
01338     if (!aMethod)
01339         return NS_ERROR_NULL_POINTER;
01340 
01341     if (PL_strcasecmp(aMethod, "SLOW") == 0)
01342         mCompMethod = JDCT_ISLOW;
01343     else if (PL_strcasecmp(aMethod, "FAST") == 0)
01344         mCompMethod = JDCT_IFAST;
01345     else if (PL_strcasecmp(aMethod, "FLOAT") == 0)
01346         mCompMethod = JDCT_FLOAT;
01347     else
01348         mCompMethod = JDCT_DEFAULT;
01349 
01350     return NS_OK;
01351 }
01352 
01353 // END of Image Preview Interface
01355 
01357 // Generic SANE Interface
01358 
01359 NS_IMETHODIMP
01360 nsSanePluginInstance::GetDeviceOptions(char ** aDeviceOptions)
01361 {
01362 #ifdef DEBUG
01363     printf("nsSaneInstance::GetDeviceOptions()\n");
01364 #endif
01365 
01366     const SANE_Option_Descriptor * optdesc;
01367     SANE_Int string_size;
01368     char *range_string, *word_string;
01369     nsresult rv;
01370 
01371     NS_ASSERTION(aDeviceOptions != NULL, "null options pointer");   
01372     if (!aDeviceOptions)
01373         return NS_ERROR_NULL_POINTER;
01374 
01375     *aDeviceOptions = nsnull;
01376 
01377     rv = OpenSaneDeviceIF();
01378     if (rv != NS_OK)
01379         return rv;
01380 
01381     // Find out how many options exist for device
01382     optdesc = sane_get_option_descriptor(mSaneHandle, 0);
01383     if (!optdesc || optdesc->size == 0) {
01384         NS_ERROR("Error trying to get number of options for device!");
01385         return NS_ERROR_FAILURE;
01386     }
01387 
01388     if (optdesc->size == 1) { /* size includes "size" option */
01389         NS_ERROR("Hmm.. That's odd! No options for this device?");
01390         return NS_OK; // I guess it's possible?
01391     }
01392 
01393     // allocate string to contain data to return to caller
01394     string_size = ((optdesc->size - 1) * MAX_OPT_SIZE) + 1;
01395     *aDeviceOptions = (char*) nsMemory::Alloc(string_size);
01396     NS_ENSURE_TRUE(*aDeviceOptions, NS_ERROR_OUT_OF_MEMORY);
01397 
01398     // initialize options string
01399     for (int n=0; n<string_size; n++)
01400         (*aDeviceOptions)[n] = '\0';
01401 
01402     // step through each of the options and copy over relavent data
01403     int i = 1;
01404     while((optdesc = sane_get_option_descriptor(mSaneHandle, i)) != NULL) {
01405         i++;
01406 
01407         // don't return grouping options
01408         if (optdesc->type == SANE_TYPE_GROUP) 
01409             continue;
01410         
01411         /* 
01412          * WARNING! Need to replace ','s and ';'s with
01413          *          something else so that JavaScript parsing
01414          *          doesn't get hosed!
01415          */
01416 
01417         // NAME
01418         if (optdesc->name) 
01419             optioncat(aDeviceOptions, optdesc->name, ", ");
01420         else 
01421             strcat(*aDeviceOptions, "N/A, ");
01422 
01424         // TITLE
01425         if (optdesc->title)
01426             optioncat(aDeviceOptions, optdesc->title, ", ");
01427         else 
01428             PL_strcat(*aDeviceOptions, "N/A, ");
01429 
01431         // DESCRIPTION
01432         if (optdesc->desc) 
01433             optioncat(aDeviceOptions, optdesc->desc, ", ");
01434         else
01435             PL_strcat(*aDeviceOptions, "N/A, ");
01436 
01438         // Option Type
01439         switch (optdesc->type) {
01440 
01441         case SANE_TYPE_BOOL:
01442             PL_strcat(*aDeviceOptions, "BOOL, ");
01443             break;
01444 
01445         case SANE_TYPE_INT:
01446             PL_strcat(*aDeviceOptions, "INT, ");
01447             break;
01448 
01449         case SANE_TYPE_FIXED:
01450             PL_strcat(*aDeviceOptions, "FIXED, ");
01451             break;
01452 
01453         case SANE_TYPE_STRING:
01454             PL_strcat(*aDeviceOptions, "STRING, ");
01455             break;
01456 
01457         case SANE_TYPE_BUTTON:
01458             PL_strcat(*aDeviceOptions, "BUTTON, ");
01459             break;
01460 
01461         case SANE_TYPE_GROUP:
01462             PL_strcat(*aDeviceOptions, "GROUP, ");
01463             break;
01464 
01465         default:
01466             PL_strcat(*aDeviceOptions, "UNKNOWN, ");
01467         }
01468 
01470         // UNIT
01471         switch (optdesc->unit) {
01472         case SANE_UNIT_NONE:
01473             PL_strcat(*aDeviceOptions, "NONE, ");
01474             break;
01475 
01476         case SANE_UNIT_PIXEL:
01477             PL_strcat(*aDeviceOptions, "PIXEL, ");
01478             break;
01479 
01480         case SANE_UNIT_BIT:
01481             PL_strcat(*aDeviceOptions, "BIT, ");
01482             break;
01483 
01484         case SANE_UNIT_MM:
01485             PL_strcat(*aDeviceOptions, "MM, ");
01486             break;
01487 
01488         case SANE_UNIT_DPI:
01489             PL_strcat(*aDeviceOptions, "PERCENT, ");
01490             break;
01491 
01492         case SANE_UNIT_MICROSECOND:
01493             PL_strcat(*aDeviceOptions, "MICROSECOND, ");
01494             break;
01495 
01496         default:
01497             PL_strcat(*aDeviceOptions, "UNKNOWN, ");
01498         }
01499 
01501         // SIZE
01502         char * size_option = (char *)PR_MALLOC(64);
01503         if (!size_option)
01504             return NS_ERROR_OUT_OF_MEMORY;
01505         sprintf(size_option, "%i, ", optdesc->size);
01506         PL_strcat(*aDeviceOptions, size_option);
01507         PR_FREEIF(size_option);
01508 
01510         // ACTIVE?
01511         if (SANE_OPTION_IS_ACTIVE(optdesc->cap))
01512             PL_strcat(*aDeviceOptions, "ACTIVE, ");
01513         else 
01514             PL_strcat(*aDeviceOptions, "UNACTIVE, ");
01515 
01517         // SW SETTABLE?
01518         if (SANE_OPTION_IS_SETTABLE(optdesc->cap))
01519             PL_strcat(*aDeviceOptions, "SETTABLE, ");
01520         else 
01521             PL_strcat(*aDeviceOptions, "UNSETTABLE, ");
01522 
01524         // Contraints Union
01525         switch (optdesc->constraint_type) {
01526         case SANE_CONSTRAINT_RANGE:
01527             range_string = (char *)PR_MALLOC(128);
01528             if (!range_string)
01529                 return NS_ERROR_OUT_OF_MEMORY;
01530             sprintf(range_string, "RANGE, %i, %i, %i; ",
01531                     optdesc->constraint.range->min,
01532                     optdesc->constraint.range->max,
01533                     optdesc->constraint.range->quant);
01534             PL_strcat(*aDeviceOptions, range_string);
01535             PR_FREEIF(range_string);
01536             break;
01537 
01538         case SANE_CONSTRAINT_WORD_LIST:
01539             word_string = (char *) PR_MALLOC(64);
01540             if (!word_string)
01541                 return NS_ERROR_OUT_OF_MEMORY;
01542             
01543             PL_strcat(*aDeviceOptions, "WORD_LIST");
01544             for (int word_index=1; 
01545                  word_index <= optdesc->constraint.word_list[0]; 
01546                  word_index++) {
01547                 sprintf(word_string, ", %i", optdesc->constraint.word_list[i]);
01548                 PL_strcat(*aDeviceOptions, word_string);
01549             }
01550             PL_strcat(*aDeviceOptions, ";");
01551             PR_FREEIF(word_string);
01552             break;
01553 
01554         case SANE_CONSTRAINT_STRING_LIST:
01555             PL_strcat(*aDeviceOptions, "STRING_LIST");
01556             for (int string_index=0; 
01557                  optdesc->constraint.string_list[string_index];
01558                  string_index++) {
01559                 PL_strcat(*aDeviceOptions, ", ");
01560                 PL_strcat(*aDeviceOptions, 
01561                           optdesc->constraint.string_list[string_index]);
01562             }
01563             PL_strcat(*aDeviceOptions, ";");
01564             break;
01565 
01566         default:
01567             // no constraints
01568             PL_strcat(*aDeviceOptions, "NONE;");
01569         }        
01570     }
01571     
01572     return NS_OK;
01573 }
01574 
01575 NS_IMETHODIMP
01576 nsSanePluginInstance::SetDeviceOptions(const char * aDeviceOptions)
01577 {
01578 #ifdef DEBUG
01579     printf("nsSaneInstance::SetDeviceOptions()\n");
01580 #endif
01581 
01582     NS_ERROR("DeviceOptions is read-only!\n");
01583     return NS_ERROR_NOT_AVAILABLE;
01584 }
01585 
01586 NS_IMETHODIMP
01587 nsSanePluginInstance::GetActiveDevice(char ** aActiveDevice)
01588 {
01589 #ifdef DEBUG
01590     printf("nsSaneInstance::GetActiveDevice()\n");
01591 #endif
01592 
01593     NS_ASSERTION(aActiveDevice != NULL, "null device pointer");   
01594     if (!aActiveDevice)
01595         return NS_ERROR_NULL_POINTER;
01596 
01597     *aActiveDevice = nsnull;
01598     if (!mSaneDevice)
01599         return NS_OK;
01600     
01601     *aActiveDevice = (char*) nsMemory::Alloc(PL_strlen(mSaneDevice) + 1);
01602     NS_ENSURE_TRUE(*aActiveDevice, NS_ERROR_OUT_OF_MEMORY);
01603     PL_strcpy(*aActiveDevice, mSaneDevice);
01604     
01605     return NS_OK;
01606 }
01607 
01608 NS_IMETHODIMP
01609 nsSanePluginInstance::SetActiveDevice(const char * aActiveDevice)
01610 {
01611 #ifdef DEBUG
01612     printf("nsSaneInstance::SetActiveDevice()\n");
01613 #endif
01614 
01615     NS_ASSERTION(aActiveDevice, "null active device pointer");
01616     if (!aActiveDevice)
01617         return NS_ERROR_NULL_POINTER;
01618 
01619     PR_FREEIF (mSaneDevice);
01620     mSaneDevice = PL_strdup(aActiveDevice);
01621 
01622     if (mSaneOpen) {
01623         sane_close(mSaneHandle);
01624         sane_exit();
01625         sane_init(0,0);
01626         if (sane_open(mSaneDevice, &mSaneHandle) != SANE_STATUS_GOOD) {
01627             mSaneOpen = SANE_FALSE;
01628             NS_ERROR("Error trying to reopen sane device!\n");
01629             return NS_ERROR_FAILURE;
01630         }
01631             
01632     } else {
01633         if (sane_open(mSaneDevice, &mSaneHandle) != SANE_STATUS_GOOD) {
01634             NS_ERROR("Error trying to open closed sane device!\n");
01635             return NS_ERROR_FAILURE;
01636         }
01637         mSaneOpen = SANE_TRUE;
01638     }
01639 
01640     return NS_OK;
01641 }
01642 
01643 NS_IMETHODIMP
01644 nsSanePluginInstance::OpenSaneDeviceIF( void )
01645 {
01646 #ifdef DEBUG
01647     printf("nsSaneInstance::OpenSaneDeviceIF()\n");
01648 #endif
01649 
01650     if (mSaneOpen) {
01651         return NS_OK;
01652     }
01653 
01654     if (!mSaneDevice) {
01655         NS_ERROR("Device name not set!");
01656         return NS_ERROR_FAILURE;
01657     }
01658 
01659     SANE_Status status = sane_open(mSaneDevice, &mSaneHandle);
01660     if (status != SANE_STATUS_GOOD) {
01661         NS_ERROR ("sane_open returned error code");
01662         return NS_ERROR_FAILURE;
01663     }
01664 
01665     mSaneOpen = SANE_TRUE;
01666     return NS_OK;
01667 }
01668 
01669 NS_IMETHODIMP
01670 nsSanePluginInstance::GetImageParameters(char ** aImageParameters)
01671 {
01672 #ifdef DEBUG
01673     printf("nsSaneInstance::GetImageParameters()\n");
01674 #endif
01675 
01676     SANE_Status status;
01677     SANE_Parameters params;
01678     nsresult rv;
01679     
01680     NS_ASSERTION(aImageParameters != NULL, "null parameters pointer");   
01681     if (!aImageParameters)
01682         return NS_ERROR_NULL_POINTER;
01683 
01684     *aImageParameters = nsnull;
01685 
01686     rv = OpenSaneDeviceIF();;
01687     if (rv != NS_OK)
01688         return rv;
01689     
01690     status = sane_get_parameters(mSaneHandle, &params);
01691     if (status != SANE_STATUS_GOOD) {
01692         sane_close(mSaneHandle);
01693         NS_ERROR("Failed to get parameters for sane device!");
01694         return NS_ERROR_FAILURE;
01695     }
01696 
01697 #define MAX_PARAM_LEN 256
01698     *aImageParameters = (char *) nsMemory::Alloc(MAX_PARAM_LEN);
01699     if (!*aImageParameters)
01700         return NS_ERROR_OUT_OF_MEMORY;
01701 
01702     char * format_string;
01703     switch (params.format) {
01704 
01705     case SANE_FRAME_GRAY:
01706         format_string = PL_strdup("GRAY");
01707         break;
01708 
01709     case SANE_FRAME_RGB:
01710         format_string = PL_strdup("RGB");
01711         break;
01712 
01713     case SANE_FRAME_RED:
01714         format_string = PL_strdup("RED");
01715         break;
01716 
01717     case SANE_FRAME_GREEN:
01718         format_string = PL_strdup("GREEN");
01719         break;
01720 
01721     case SANE_FRAME_BLUE:
01722         format_string = PL_strdup("BLUE");
01723         break;
01724 
01725     default:
01726         format_string = PL_strdup("UNKNOWN");
01727     }
01728 
01729     sprintf(*aImageParameters, "%s, %s, %i, %i, %i, %i",
01730             format_string,
01731             params.last_frame ? "TRUE" : "FALSE",
01732             params.lines,
01733             params.depth,
01734             params.pixels_per_line,
01735             params.bytes_per_line);
01736 
01737 
01738     // cleanup
01739     PR_FREEIF(format_string);
01740 
01741     return NS_OK;
01742 }
01743 
01744 NS_IMETHODIMP
01745 nsSanePluginInstance::SetImageParameters(const char * aImageParameters)
01746 {
01747 #ifdef DEBUG
01748     printf("nsSaneInstance::SetImageParameters()\n");
01749 #endif
01750 
01751     NS_ERROR("ImageParameters is read-only!\n");
01752     return NS_ERROR_NOT_AVAILABLE;
01753 }
01754 
01755 NS_IMETHODIMP
01756 nsSanePluginInstance::GetAvailableDevices(char ** aAvailableDevices)
01757 {
01758 #ifdef DEBUG
01759     printf("nsSaneInstance::GetAvailableDevices()\n");
01760 #endif
01761 
01762     SANE_Status status;
01763     const SANE_Device ** device_list;
01764     int num, i;
01765 
01766     NS_ASSERTION(aAvailableDevices != NULL, "null parameters pointer");   
01767     if (!aAvailableDevices)
01768         return NS_ERROR_NULL_POINTER;
01769 
01770     *aAvailableDevices = nsnull;
01771 
01772     status = sane_get_devices(&device_list, SANE_TRUE);
01773     if (status != SANE_STATUS_GOOD)
01774         return NS_ERROR_FAILURE;
01775 
01776     // find out how many devices are available
01777     for ( num=0; device_list[num]; num++);
01778 
01779     // allocate return string
01780 #define MAX_DEVICE_SIZE 256
01781     *aAvailableDevices = (char*) nsMemory::Alloc(num * MAX_DEVICE_SIZE);
01782     if (!*aAvailableDevices)
01783         return NS_ERROR_OUT_OF_MEMORY;
01784 
01785     for ( i=0; i < num * MAX_DEVICE_SIZE; i++)
01786         (*aAvailableDevices)[i] = '\0';
01787 
01788     for ( i=0; i<num; i++) {
01789         optioncat(aAvailableDevices, device_list[i]->name,   ", ");
01790         optioncat(aAvailableDevices, device_list[i]->vendor, ", ");
01791         optioncat(aAvailableDevices, device_list[i]->model,  ", ");
01792         optioncat(aAvailableDevices, device_list[i]->type,   "; ");
01793     }
01794 
01795     return NS_OK;
01796 }
01797 
01798 NS_IMETHODIMP
01799 nsSanePluginInstance::SetAvailableDevices(const char * aAvailableDevices)
01800 {
01801 #ifdef DEBUG
01802     printf("nsSaneInstance::SetAvailableDevices()\n");
01803 #endif
01804 
01805     NS_ERROR("AvailableDevices is read-only!\n");
01806     return NS_ERROR_NOT_AVAILABLE;
01807 }
01808 
01809 NS_IMETHODIMP
01810 nsSanePluginInstance::ScanImage(void)
01811 {
01812 #ifdef DEBUG
01813     printf("nsSaneInstance::ScanImage()\n");
01814 #endif
01815 
01816     mState = 1;
01817     mSuccess = 0;
01818 
01819     mScanThread = PR_CreateThread( PR_USER_THREAD, scanimage_thread_routine, 
01820                                   (void*)this, PR_PRIORITY_HIGH, 
01821                                   PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
01822 
01823     if (mScanThread == NULL) {
01824         NS_ERROR("Could not create thread!");
01825         return NS_ERROR_FAILURE;
01826     }
01827 
01828     return NS_OK;
01829 }
01830 
01831 NS_IMETHODIMP
01832 nsSanePluginInstance::SetOption(const char * name, const char * value)
01833 {
01834 #ifdef DEBUG
01835     printf("nsSaneInstance::SetOption()\n");
01836 #endif
01837 
01838     nsresult rv;
01839     SANE_Int optnum;
01840     const SANE_Option_Descriptor * optdesc;
01841     void * option_value;
01842     SANE_Status status;
01843 
01844     NS_ASSERTION(name != NULL && value != NULL, "null pointer");
01845     if (!name || !value)
01846         return NS_ERROR_NULL_POINTER;
01847 
01848     rv = OpenSaneDeviceIF();
01849     if (rv != NS_OK) 
01850         return rv;
01851 
01852     // find the option number
01853     for ( optnum=1; 
01854           ((optdesc = sane_get_option_descriptor(mSaneHandle, optnum)) != NULL)
01855               && (PL_strcasecmp(name, optdesc->name) != 0);
01856           optnum++ );
01857     if (!optdesc) {
01858         NS_ERROR("Option not found for sane device!");
01859         return NS_ERROR_INVALID_ARG;
01860     }
01861 
01862     // determine the value to pass to device
01863     if (optdesc->type == SANE_TYPE_BOOL) {
01864         SANE_Bool sbool;
01865         if (PL_strcasecmp(value, "TRUE") == 0) {
01866             sbool = SANE_TRUE;
01867         } else 
01868             sbool = SANE_FALSE;
01869 
01870         option_value = (void *) &sbool;
01871 
01872     } else if ( optdesc->type == SANE_TYPE_INT ||
01873                 optdesc->type == SANE_TYPE_FIXED ) {
01874         SANE_Int sint;
01875         sscanf(value, "%i", &sint);
01876 
01877         option_value = (void *) &sint;
01878 
01879     } else if (optdesc->type == SANE_TYPE_STRING) {
01880         option_value = (void *) value;
01881     } else {
01882         option_value = NULL;
01883     }
01884 
01885     // set the option
01886     status = sane_control_option( mSaneHandle, optnum, 
01887                                   SANE_ACTION_SET_VALUE, option_value,
01888                                   NULL);
01889     if (status != SANE_STATUS_GOOD) {
01890         NS_ERROR("Error trying to set option!");
01891         return NS_ERROR_FAILURE;
01892     }
01893 
01894     return NS_OK;
01895 }
01896 
01897 int
01898 nsSanePluginInstance::WritePNMHeader (int fd, SANE_Frame format, 
01899                                   int width, int height, int depth)
01900 {
01901 #ifdef DEBUG
01902     printf("nsSaneInstance::WritePNMHeader()\n");
01903 #endif
01904 
01905     char b[32];
01906 
01907     switch (format) {
01908     case SANE_FRAME_RED:
01909     case SANE_FRAME_GREEN:
01910     case SANE_FRAME_BLUE:
01911     case SANE_FRAME_RGB:
01912         sprintf (b, "P6\n%d %d\n255\n", width, height);
01913         break;
01914 
01915     default:
01916         if (depth == 1)
01917             sprintf (b, "P4\n%d %d\n", width, height);
01918         else
01919             sprintf (b, "P5\n%d %d\n255\n", width, height);
01920         break;
01921     }
01922 
01923     return write(fd, b, PL_strlen(b));
01924 }
01925 
01926 // END of Generic SANE Interface
01928 
01930 // Scanner Status Interface
01931 
01932 NS_IMETHODIMP
01933 nsSanePluginInstance::GetSuccess(PRBool * aSuccess)
01934 {
01935 #ifdef DEBUG
01936     printf("nsSaneInstance::GetSuccess()\n");
01937 #endif
01938 
01939     NS_PRECONDITION(aSuccess != nsnull, "null ptr");
01940     if (! aSuccess) {
01941         NS_ERROR("Null pointer passed to GetSuccess!\n");
01942         return NS_ERROR_NULL_POINTER;
01943     }
01944 
01945     *aSuccess = mSuccess;
01946     return NS_OK;
01947 }
01948 
01949 NS_IMETHODIMP
01950 nsSanePluginInstance::SetSuccess(PRBool aSuccess)
01951 {
01952 #ifdef DEBUG
01953     printf("nsSaneInstance::SetSuccess()\n");
01954 #endif
01955 
01956     // This is a read-only flag.
01957     NS_ERROR("Success is a read-only flag!\n");
01958     return NS_ERROR_FAILURE;
01959 }
01960 
01961 NS_IMETHODIMP
01962 nsSanePluginInstance::GetState(char ** aState)
01963 {
01964 #ifdef DEBUG
01965     printf("nsSaneInstance::GetState()\n");
01966 #endif
01967 
01968     NS_PRECONDITION(aState != nsnull, "null ptr");
01969     if (! aState) {
01970         NS_ERROR("Null pointer passed to GetSuccess!\n");
01971         return NS_ERROR_NULL_POINTER;
01972     }
01973 
01974     *aState = (char*) nsMemory::Alloc(5);
01975     if (!*aState) {
01976         NS_ERROR("Unable to allocate State string!\n");
01977         return NS_ERROR_OUT_OF_MEMORY;
01978     }
01979 
01980     if (mState == 0)
01981         PL_strcpy(*aState, "IDLE");
01982     else
01983         PL_strcpy(*aState, "BUSY");
01984 
01985     return NS_OK;
01986 }
01987 
01988 NS_IMETHODIMP
01989 nsSanePluginInstance::SetState(const char * aState)
01990 {
01991 #ifdef DEBUG
01992     printf("nsSaneInstance::SetState()\n");
01993 #endif
01994 
01995     // This is a read-only flag.
01996     NS_ERROR("Success is a read-only flag!\n");
01997     return NS_ERROR_FAILURE;
01998 }
01999 
02000 // END of Scanner Status Interface
02002 
02004 // snPluginStreamListener Methods
02005 
02006 nsSanePluginStreamListener::nsSanePluginStreamListener(nsSanePluginInstance* inst)
02007 {
02008 #ifdef DEBUG
02009     printf("nsSanePluginStreamListener::nsSanePluginStreamListener()\n");
02010 #endif
02011 
02012     PR_AtomicIncrement(&gPluginObjectCount);
02013 
02014     mPlugInst = inst;
02015 }
02016 
02017 nsSanePluginStreamListener::~nsSanePluginStreamListener(void)
02018 {
02019 #ifdef DEBUG
02020     printf("nsSanePluginStreamListener::~nsSanePluginStreamListener()\n");
02021 #endif
02022 
02023     PR_AtomicDecrement(&gPluginObjectCount);
02024 }
02025 
02026 
02027 // This macro produces a simple version of QueryInterface, AddRef and Release.
02028 // See the nsISupports.h header file for details.
02029 NS_IMPL_ISUPPORTS1(nsSanePluginStreamListener, nsIPluginStreamListener)
02030 
02031 NS_METHOD
02032 nsSanePluginStreamListener::OnStartBinding( nsIPluginStreamInfo* pluginInfo )
02033 {
02034 #ifdef DEBUG
02035     printf("nsSanePluginStreamListener::OnStartBinding()\n");
02036 #endif
02037 
02038     return NS_OK;
02039 }
02040 
02041 NS_METHOD
02042 nsSanePluginStreamListener::OnDataAvailable( nsIPluginStreamInfo* pluginInfo, 
02043                                              nsIInputStream* input, 
02044                                              PRUint32 length )
02045 {
02046 #ifdef DEBUG
02047     printf("nsSanePluginStreamListener::OnDataAvailable()\n");
02048 #endif
02049 
02050     // This plugin doesn't support 
02051     // streaming input data.
02052     return NS_OK;
02053 }
02054 
02055 
02056 NS_METHOD
02057 nsSanePluginStreamListener::OnFileAvailable( nsIPluginStreamInfo* pluginInfo, 
02058                                              const char* fileName )
02059 {
02060 #ifdef DEBUG
02061     printf("nsSanePluginStreamListener::OnFileAvailable()\n");
02062 #endif
02063 
02064     return NS_OK;
02065 }
02066 
02067 NS_METHOD
02068 nsSanePluginStreamListener::OnStopBinding( nsIPluginStreamInfo* pluginInfo,
02069                                            nsresult status )
02070 {
02071 #ifdef DEBUG
02072     printf("nsSanePluginStreamListener::OnStopBinding()\n");
02073 #endif
02074 
02075     return NS_OK;
02076 }
02077 
02078 NS_METHOD
02079 nsSanePluginStreamListener::OnNotify( const char* url, nsresult status )
02080 {
02081 #ifdef DEBUG
02082     printf("nsSanePluginStreamListener::OnNotify()\n");
02083 #endif
02084 
02085     return NS_OK;
02086 }
02087 
02088 NS_METHOD
02089 nsSanePluginStreamListener::GetStreamType(nsPluginStreamType *result)
02090 {
02091 #ifdef DEBUG
02092     printf("nsSanePluginStreamListener::GetStreamType()\n");
02093 #endif
02094 
02095     *result = nsPluginStreamType_Normal;
02096     return NS_OK;
02097 }
02098 
02099 // End snPluginStreamListener methods
02101 
02103 // Helper Global Fuctions
02104 
02105 gboolean draw (GtkWidget *widget, GdkEventExpose *event, gpointer data) {
02106 
02107     nsSanePluginInstance * pthis = (nsSanePluginInstance *)data;
02108 
02109     pthis->PaintImage();
02110     return TRUE;
02111 }
02112 
02113 nsresult optioncat ( char ** dest, const char * src, const char * ending )
02114 {
02115     char * p;
02116     int i;
02117 
02118     NS_ASSERTION(dest != NULL, "null option string pointer");
02119     if (!dest)
02120         return NS_ERROR_NULL_POINTER;
02121 
02122     NS_ASSERTION(src != NULL, "null option string pointer");
02123     if (!src)
02124         return NS_ERROR_NULL_POINTER;
02125 
02126     NS_ASSERTION(ending != NULL, "null option string pointer");
02127     if (!ending)
02128         return NS_ERROR_NULL_POINTER;
02129 
02130     // ensure that src string doesn't contain any ','s or ';'s
02131     p = PL_strdup(src);
02132     for ( i=0; p[i]; i++ ) {
02133         if (p[i] == ',')
02134             p[i] = '~';  // Replace ','s with '~'s
02135         else if (p[i] == ';')
02136             p[i] = '|';  // Replace ';'s with '|'s
02137 
02138     }
02139 
02140 
02141     PL_strcat(*dest, p);
02142     PL_strcat(*dest, ending);
02143     PR_FREEIF(p);
02144 
02145     return NS_OK;
02146 }
02147 
02148 void
02149 my_jpeg_error_exit (j_common_ptr cinfo)
02150 {
02151     emptr errmgr;
02152 
02153     errmgr = (emptr) cinfo->err;
02154     cinfo->err->output_message(cinfo);
02155     siglongjmp(errmgr->setjmp_buffer, 1);
02156     return;
02157 }
02158 
02159 unsigned char      *
02160 jpeg_file_to_rgb (FILE * f, int *w, int *h)
02161 {
02162   struct jpeg_decompress_struct cinfo;
02163   struct my_JPEG_error_mgr jerr;
02164   unsigned char      *data, *line[16], *ptr;
02165   int                 x, y, i;
02166 
02167   cinfo.err = jpeg_std_error(&(jerr.pub));
02168   jerr.pub.error_exit = my_jpeg_error_exit;
02169 
02170   /* error handler to longjmp to, we want to preserve signals */
02171   if (sigsetjmp(jerr.setjmp_buffer, 1)) {
02172     
02173     /* Whoops there was a jpeg error */
02174     jpeg_destroy_decompress(&cinfo);
02175     return NULL;
02176   }
02177 
02178   jpeg_create_decompress(&cinfo);
02179   jpeg_stdio_src(&cinfo, f);
02180   jpeg_read_header(&cinfo, TRUE);
02181   cinfo.do_fancy_upsampling = FALSE;
02182   cinfo.do_block_smoothing = FALSE;
02183 
02184   cinfo.scale_num = 2;
02185   cinfo.scale_denom = 1;
02186   jpeg_start_decompress(&cinfo);
02187   *w = cinfo.output_width;
02188   *h = cinfo.output_height;
02189   data = (unsigned char *)PR_Malloc(*w ** h * 3);
02190   if (!data) {
02191     NS_ERROR("jpeg_file_to_rgb: Error trying to allocate buffer!\n");
02192     jpeg_destroy_decompress(&cinfo);
02193     return NULL;
02194   }
02195   ptr = data;
02196 
02197   if (cinfo.rec_outbuf_height > 16) {
02198       NS_ERROR("ERROR: JPEG uses line buffers > 16. Cannot load.\n");
02199       return NULL;
02200   }
02201 
02202   if (cinfo.output_components == 3) {
02203     for (y = 0; y < *h; y += cinfo.rec_outbuf_height) {
02204       for (i = 0; i < cinfo.rec_outbuf_height; i++) {
02205        line[i] = ptr;
02206        ptr += *w * 3;
02207       }
02208 
02209       jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
02210     }
02211   } else if (cinfo.output_components == 1) {
02212     for (i = 0; i < cinfo.rec_outbuf_height; i++) {
02213       if ((line[i] = (unsigned char *)PR_Malloc(*w)) == NULL) {
02214        int                 t = 0;
02215        
02216        NS_ERROR("jpeg_file_to_rgb: Error tying to allocate line!\n");
02217        
02218        for (t = 0; t < i; t++)
02219          PR_FREEIF(line[t]);
02220        jpeg_destroy_decompress(&cinfo);
02221        return NULL;
02222       }
02223     }
02224 
02225     for (y = 0; y < *h; y += cinfo.rec_outbuf_height) {
02226       jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
02227       for (i = 0; i < cinfo.rec_outbuf_height; i++) {
02228        for (x = 0; x < *w; x++) {
02229          *ptr++ = line[i][x];
02230          *ptr++ = line[i][x];
02231          *ptr++ = line[i][x];
02232        }
02233       }
02234     }
02235 
02236     for (i = 0; i < cinfo.rec_outbuf_height; i++)
02237       PR_FREEIF(line[i]);
02238   }
02239 
02240   jpeg_finish_decompress(&cinfo);
02241   jpeg_destroy_decompress(&cinfo);
02242 
02243   return data;
02244 }
02245 
02246 // Caller must free memory
02247 unsigned char *
02248 scale_image(unsigned char *rgb_data, int rgb_width, int rgb_height,
02249            int w, int h)
02250 {
02251   int                 x, y, *xarray;
02252   unsigned char     **yarray, *ptr, *ptr2, *ptr22, *new_data;
02253   int                 l, r, m, pos, inc, w3;
02254 
02255   new_data = (unsigned char *) PR_Malloc( w * h * 3);
02256   if (!new_data) {
02257     NS_ERROR("ERROR: Cannot allocate image buffer\n");
02258     return NULL;
02259   }
02260 
02261   xarray = (int *)PR_Malloc(sizeof(int) * w);
02262   if (!xarray) {
02263     NS_ERROR("ERROR: Cannot allocate X co-ord buffer\n");
02264     PR_FREEIF(new_data);
02265     return NULL;
02266   }
02267 
02268   yarray = (unsigned char **)PR_Malloc(sizeof(unsigned char *) * h);
02269   if (!yarray) {
02270     NS_ERROR("ERROR: Cannot allocate Y co-ord buffer\n");
02271     PR_FREEIF(new_data);
02272     PR_FREEIF(xarray);
02273     return NULL;
02274   }
02275   
02276   ptr22 = rgb_data;
02277   w3 = rgb_width * 3;
02278   inc = 0;
02279   l = 0;
02280   r = 0;
02281   m = w - l - r;
02282 
02283   inc = (rgb_width << 16) / m;
02284   pos = 0;
02285 
02286   for (x = l; x < l + m; x++) {
02287     xarray[x] = (pos >> 16) + (pos >> 16) + (pos >> 16);
02288     pos += inc;
02289   }
02290 
02291   pos = (rgb_width - r) << 16;
02292   for (x = w - r; x < w; x++) {
02293     xarray[x] = (pos >> 16) + (pos >> 16) + (pos >> 16);
02294     pos += 0x10000;
02295   }
02296 
02297   l = 0;
02298   r = 0;
02299   m = h - l - r;
02300 
02301   if (m > 0)
02302     inc = (rgb_height << 16) / m;
02303 
02304   pos = 0;
02305 
02306   for (x = l; x < l + m; x++) {
02307     yarray[x] = ptr22 + ((pos >> 16) * w3);
02308     pos += inc;
02309   }
02310 
02311   pos = (rgb_height - r) << 16;
02312   for (x = h - r; x < h; x++) {
02313     yarray[x] = ptr22 + ((pos >> 16) * w3);
02314     pos += 0x10000;
02315   }
02316 
02317   ptr = new_data;
02318   for (y = 0; y < h; y++) {
02319     for (x = 0; x < w; x++) {
02320       ptr2 = yarray[y] + xarray[x];
02321       *ptr++ = (int)*ptr2++;
02322       *ptr++ = (int)*ptr2++;
02323       *ptr++ = (int)*ptr2;
02324     }
02325   }
02326 
02327   PR_FREEIF(xarray);
02328   PR_FREEIF(yarray);
02329 
02330   return new_data;
02331 }
02332 
02333 
02334 // Caller must free memory
02335 unsigned char *
02336 crop_image(unsigned char *rgb_data, int *rgb_width, int *rgb_height,
02337           gint x, gint y, gint w, gint h)
02338 {
02339   unsigned char      *data;
02340   int                 xx, yy, w3, w4;
02341   unsigned char      *ptr1, *ptr2;
02342 
02343   if (!rgb_data)
02344     return NULL;
02345 
02346   if (x < 0)
02347     {
02348       w += x;
02349       x = 0;
02350     }
02351   if (y < 0)
02352     {
02353       h += y;
02354       y = 0;
02355     }
02356   if (x >= *rgb_width)
02357     return NULL;
02358   if (y >= *rgb_height)
02359     return NULL;
02360   if (w <= 0)
02361     return NULL;
02362   if (h <= 0)
02363     return NULL;
02364   if (x + w > *rgb_width)
02365     w = *rgb_width - x;
02366   if (y + h > *rgb_height)
02367     h = *rgb_height - y;
02368   if (w <= 0)
02369     return NULL;
02370   if (h <= 0)
02371     return NULL;
02372 
02373   w3 = *rgb_width * 3;
02374   w4 = (*rgb_width - w) * 3;
02375   data = (unsigned char *)PR_Malloc(w * h * 3);
02376   if (data == NULL)
02377     return NULL;
02378   ptr1 = rgb_data + (y * w3) + (x * 3);
02379   ptr2 = data;
02380   for (yy = 0; yy < h; yy++)
02381     {
02382       for (xx = 0; xx < w; xx++)
02383        {
02384          *ptr2++ = *ptr1++;
02385          *ptr2++ = *ptr1++;
02386          *ptr2++ = *ptr1++;
02387        }
02388       ptr1 += w4;
02389     }
02390   
02391   *rgb_width = w;
02392   *rgb_height = h;
02393 
02394   return data;
02395 }
02396 
02397 void PR_CALLBACK scanimage_thread_routine( void * arg )
02398 {
02399     nsSanePluginInstance * pthis = (nsSanePluginInstance *)arg;
02400 
02401     nsresult rv;
02402     SANE_Status status;
02403     SANE_Parameters param;
02404     int len;
02405     FILE * out;
02406     SANE_Byte * buf;
02407     JSAMPROW row_pointer[1];
02408     char *fname;
02409 
02410     // JPEG stuff
02411     struct jpeg_compress_struct cinfo;
02412        struct jpeg_error_mgr jerr;
02413 
02414        // Error handling
02415     jerr.error_exit = my_jpeg_error_exit; // fatal errors
02416        cinfo.err = jpeg_std_error(&jerr);
02417 
02418        jpeg_create_compress(&cinfo);
02419 
02420     rv = pthis->OpenSaneDeviceIF();
02421     if (rv != NS_OK)
02422         goto error_exit;
02423 
02424     // open image file
02425     fname = pthis->GetImageFilename();
02426     if (!fname)
02427         goto error_exit;
02428     out = fopen(fname, "wb");
02429     PR_FREEIF(fname);
02430     if (out == NULL) {
02431         NS_ERROR("Unable to open mImageFilename!\n");
02432         sane_cancel(pthis->mSaneHandle);
02433         goto error_exit;       
02434     }
02435     jpeg_stdio_dest(&cinfo, out);
02436 
02437     status = sane_start(pthis->mSaneHandle);
02438     if (status != SANE_STATUS_GOOD) {
02439         NS_ERROR("Error trying to start sane device!");
02440         goto error_exit;
02441     }
02442 
02443     status = sane_get_parameters(pthis->mSaneHandle, &param);
02444     if (status != SANE_STATUS_GOOD) {
02445         NS_ERROR("Error trying to get image parameters!\n");
02446         sane_cancel(pthis->mSaneHandle);
02447         goto error_exit;
02448     }
02449     cinfo.image_width = param.pixels_per_line;
02450     cinfo.image_height = param.lines;
02451 
02452     switch (param.format) {
02453     case SANE_FRAME_RED:
02454     case SANE_FRAME_GREEN:
02455     case SANE_FRAME_BLUE:
02456         // NOT Supported!
02457         NS_ERROR("Multiframe devices not supported!\n");
02458         sane_cancel(pthis->mSaneHandle);
02459         goto error_exit;
02460         break;
02461                 
02462     case SANE_FRAME_RGB:
02463         cinfo.input_components = 3;
02464         cinfo.in_color_space = JCS_RGB;
02465         break;
02466 
02467     case SANE_FRAME_GRAY:
02468         cinfo.input_components = 1;
02469         cinfo.in_color_space = JCS_GRAYSCALE;
02470         break;
02471     }
02472     jpeg_set_defaults(&cinfo); 
02473     cinfo.dct_method = pthis->mCompMethod; 
02474     jpeg_set_quality(&cinfo, pthis->mCompQuality, FALSE);
02475     jpeg_start_compress(&cinfo, TRUE);
02476 
02477     buf = (SANE_Byte *)PR_MALLOC(param.bytes_per_line);
02478     if (!buf) {
02479         NS_ERROR("Error trying to allocate buffer!\n");
02480         jpeg_destroy_compress(&cinfo);
02481         fclose(out);
02482         sane_cancel(pthis->mSaneHandle);
02483         goto error_exit;
02484     }
02485 
02486     int total;
02487     while(1) {
02488         total = 0;
02489         while (total < param.bytes_per_line) {
02490             // Read in data from sane device
02491             status = sane_read(pthis->mSaneHandle, buf + total, 
02492                                param.bytes_per_line - total, 
02493                                &len);
02494             if (status != SANE_STATUS_GOOD) {
02495                 if (status == SANE_STATUS_EOF)
02496                     // done with this frame
02497                     goto finished_scan;
02498                 else {
02499                     NS_ERROR("Error trying to read from sane device!\n");
02500                     PR_FREEIF(buf);
02501                     jpeg_destroy_compress(&cinfo);
02502                     fclose(out);
02503                     sane_cancel(pthis->mSaneHandle);
02504                     goto error_exit;
02505                 }
02506             }
02507             total += len;
02508         }
02509 
02510         row_pointer[0] = (JSAMPLE *) buf;
02511         jpeg_write_scanlines(&cinfo, row_pointer, 1); 
02512 
02513     } // end while
02514 
02515     // cleanup
02516  finished_scan:
02517     jpeg_finish_compress(&cinfo);
02518     jpeg_destroy_compress(&cinfo);
02519     PR_FREEIF(buf);
02520     sane_cancel(pthis->mSaneHandle);
02521     fclose(out);
02522     pthis->SetSuccess(PR_TRUE); // allow caller to check for success
02523 
02524  error_exit:
02525 
02527     // Call onScanComplete callback in the UI thread
02528 
02529     nsCOMPtr<nsIEventQueue> eventQ;
02530 
02531     // Get the event queue of the current thread...
02532     nsCOMPtr<nsIEventQueueService> eventQService = 
02533              do_GetService(kEventQueueService, &rv);
02534     if (NS_FAILED(rv)) {
02535         NS_ERROR("Unable to get event queue service!\n");
02536         return;
02537     }
02538 
02539     rv = eventQService->GetThreadEventQueue(pthis->mUIThread,
02540                                             getter_AddRefs(eventQ));
02541     if (NS_FAILED(rv)) {
02542         NS_ERROR("Unable to get thread queue!\n");
02543         return;
02544     }
02545 
02546     PLEvent *event = new PLEvent;
02547     if (!event) {
02548         NS_ERROR("Unable to create new event!\n");
02549         return;
02550     }
02551 
02552     // ThreadHandleEvent will now execute in the UI thread.
02553     PL_InitEvent(event, 
02554                  pthis,
02555                  (PLHandleEventProc)  ThreadedHandleEvent,
02556                  (PLDestroyEventProc) ThreadedDestroyEvent);
02557 
02558     if (NS_FAILED(eventQ->PostEvent(event))) {
02559         NS_ERROR("Error trying to post event!\n");
02560         PL_DestroyEvent(event);
02561         return;
02562     }
02563 }
02564 
02565 void PR_CALLBACK ThreadedHandleEvent(PLEvent * event)
02566 {
02567     nsSanePluginInstance *pthis = (nsSanePluginInstance *)event->owner;    
02568    
02569     // If this isn't the UI's thread then we are hosed!
02570     if (PR_FALSE == pthis->IsUIThread()) {
02571         NS_ERROR("Attempt to execute event from the wrong thread!\n");
02572         return;
02573     }
02574 
02575     pthis->SetState(0); // no longer scanning
02576     pthis->Restore();  // repaint image
02577 
02578     // Notify user that routine is finished
02579     pthis->DoScanCompleteCallback();
02580 }
02581 
02582 void PR_CALLBACK ThreadedDestroyEvent(PLEvent* aEvent)
02583 {
02584     delete aEvent;
02585 }
02586 
02587 void store_filename(GtkFileSelection *selector, gpointer user_data) 
02588 {
02589     nsSanePluginInstance *pthis = (nsSanePluginInstance *) user_data;    
02590     gchar *cmd;
02591     GtkWidget * fs;
02592     char * orig_filename;
02593     char * dest_filename;
02594 
02595     if (!user_data || !selector)
02596         return;
02597 
02598     fs = pthis->GetFileSelection();
02599     orig_filename = pthis->GetImageFilename();
02600     if ( !fs || !orig_filename )
02601         return;
02602 
02603     dest_filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION(fs));
02604     if ( !dest_filename )
02605         return;
02606 
02607 #ifdef DEBUG
02608     printf("Saving %s to %s\n", orig_filename, dest_filename);
02609 #endif
02610 
02611     /*
02612      * I'm just doing a simple 'cp' command with the shell.
02613      * This probobly should be done in a NSPR safe kind
02614      * of way.
02615      */
02616 
02617     // cp /tmp/nsSanePlugin.###.jpg /path/to/save/to.jpg
02618     cmd = (gchar *)PR_Malloc(PL_strlen(orig_filename) + 
02619                              PL_strlen(dest_filename) + 6);
02620     if (!cmd)
02621         return;
02622         
02623     sprintf(cmd, "cp %s %s", orig_filename, dest_filename);
02624     system(cmd);
02625 
02626     PR_FREEIF(cmd);
02627 }
02628 
02629 // END of Helper Global Functions
02631 
02632 
02633 
02634 
02635 
02636 
02637 
02638 
02639 
02640 
02641 
02642 
02643 
02644 
02645 
02646 
02647 
02648 
02649