fix for BC++ internal compiler error
[wxWidgets.git] / samples / image / image.cpp
1 /*
2 * Program: image
3 *
4 * Author: Robert Roebling
5 *
6 * Copyright: (C) 1998, Robert Roebling
7 *
8 */
9
10 // For compilers that support precompilation, includes "wx/wx.h".
11 #include "wx/wxprec.h"
12
13 #ifdef __BORLANDC__
14 #pragma hdrstop
15 #endif
16
17 #ifndef WX_PRECOMP
18 #include "wx/wx.h"
19 #endif
20
21 #include "wx/image.h"
22 #include "wx/file.h"
23 #include "wx/mstream.h"
24 #include "wx/wfstream.h"
25 #include "wx/quantize.h"
26
27 #include "smile.xbm"
28 #include "smile.xpm"
29
30
31 // derived classes
32
33 class MyFrame;
34 class MyApp;
35
36 // MyCanvas
37
38 class MyCanvas: public wxScrolledWindow
39 {
40 public:
41 MyCanvas() {};
42 MyCanvas( wxWindow *parent, wxWindowID, const wxPoint &pos, const wxSize &size );
43 ~MyCanvas();
44 void OnPaint( wxPaintEvent &event );
45 void CreateAntiAliasedBitmap();
46
47 wxBitmap *my_horse_png;
48 wxBitmap *my_horse_jpeg;
49 wxBitmap *my_horse_gif;
50 wxBitmap *my_horse_bmp;
51 wxBitmap *my_horse_pcx;
52 wxBitmap *my_horse_pnm;
53 wxBitmap *my_horse_tiff;
54 wxBitmap *my_horse_xpm;
55
56 wxBitmap *my_smile_xbm;
57 wxBitmap *my_square;
58 wxBitmap *my_anti;
59
60 protected:
61 wxBitmap m_bmpSmileXpm;
62 wxIcon m_iconSmileXpm;
63
64 private:
65 DECLARE_DYNAMIC_CLASS(MyCanvas)
66 DECLARE_EVENT_TABLE()
67 };
68
69
70 const int nChoices = 8 ;
71 static const wxString bppchoices[nChoices] =
72 {
73 "1 bpp color",
74 "1 bpp B&W",
75 "4 bpp color",
76 "8 bpp color",
77 "8 bpp greyscale",
78 "8 bpp red",
79 "8 bpp own palette",
80 "24 bpp"
81 };
82
83 static const int bppvalues[nChoices] =
84 {
85 wxBMP_1BPP,
86 wxBMP_1BPP_BW,
87 wxBMP_4BPP,
88 wxBMP_8BPP,
89 wxBMP_8BPP_GREY,
90 wxBMP_8BPP_RED,
91 wxBMP_8BPP_PALETTE,
92 wxBMP_24BPP
93 };
94
95 // MyFrame
96
97
98 class MyFrame: public wxFrame
99 {
100 public:
101 MyFrame();
102
103 void OnAbout( wxCommandEvent &event );
104 void OnNewFrame( wxCommandEvent &event );
105 void OnQuit( wxCommandEvent &event );
106
107 MyCanvas *m_canvas;
108
109 private:
110 DECLARE_DYNAMIC_CLASS(MyFrame)
111 DECLARE_EVENT_TABLE()
112 };
113
114 class MyImageFrame : public wxFrame
115 {
116 public:
117 MyImageFrame(wxFrame *parent, const wxBitmap& bitmap)
118 : wxFrame(parent, -1, _T("Double click to save"),
119 wxDefaultPosition, wxDefaultSize,
120 wxCAPTION | wxSYSTEM_MENU),
121 m_bitmap(bitmap)
122 {
123 SetClientSize(bitmap.GetWidth(), bitmap.GetHeight());
124 }
125
126 void OnPaint(wxPaintEvent& WXUNUSED(event))
127 {
128 wxPaintDC dc( this );
129 dc.DrawBitmap( m_bitmap, 0, 0 );
130 }
131
132 void OnSave(wxCommandEvent& WXUNUSED(event))
133 {
134 wxImage image(m_bitmap);
135
136 int bppselection = wxGetSingleChoiceIndex("Set BMP BPP",
137 "Set BMP BPP",
138 nChoices,
139 bppchoices,
140 this);
141 if ( bppselection == -1 )
142 {
143 // cancelled
144 return;
145 }
146
147 image.SetOption(wxBMP_FORMAT, bppvalues[bppselection]);
148
149 wxString deffilename = bppchoices[bppselection];
150 deffilename.Replace(wxT(" "), wxT("_"));
151 deffilename += wxT(".bmp");
152 wxString savefilename = wxFileSelector( wxT("Save Image"),
153 wxT(""),
154 deffilename,
155 (const wxChar *)NULL,
156 wxT("BMP files (*.bmp)|*.bmp|")
157 wxT("PNG files (*.png)|*.png|")
158 wxT("JPEG files (*.jpg)|*.jpg|")
159 wxT("GIF files (*.gif)|*.gif|")
160 wxT("TIFF files (*.tif)|*.tif|")
161 wxT("PCX files (*.pcx)|*.pcx"),
162 wxSAVE);
163
164 if ( savefilename.empty() )
165 return;
166
167 if ( image.GetOptionInt(wxBMP_FORMAT) == wxBMP_8BPP_PALETTE )
168 {
169 unsigned char *cmap = new unsigned char [256];
170 for ( int i = 0; i < 256; i++ )
171 cmap[i] = i;
172 image.SetPalette(wxPalette(256, cmap, cmap, cmap));
173
174 delete cmap;
175 }
176
177 bool saved = FALSE;
178
179 wxString extension = savefilename.AfterLast('.').Lower();
180
181 if (extension == "bmp")
182 saved=image.SaveFile(savefilename, wxBITMAP_TYPE_BMP);
183 else if (extension == "png")
184 saved=image.SaveFile(savefilename, wxBITMAP_TYPE_PNG);
185 else if (extension == "pcx")
186 saved=image.SaveFile(savefilename, wxBITMAP_TYPE_PCX);
187 else if ((extension == "tif") || (extension == "tiff"))
188 saved=image.SaveFile(savefilename, wxBITMAP_TYPE_TIF);
189 else if (extension == "jpg")
190 saved=image.SaveFile(savefilename, wxBITMAP_TYPE_JPEG);
191 else if (extension == "pnm")
192 saved=image.SaveFile(savefilename, wxBITMAP_TYPE_PNM);
193 else
194 wxMessageBox("Unknown file type, see options in file selector.",
195 "Unknown file type",
196 wxOK|wxCENTRE, this);
197 }
198
199 private:
200 wxBitmap m_bitmap;
201
202 DECLARE_EVENT_TABLE()
203 };
204
205 // MyApp
206
207 class MyApp: public wxApp
208 {
209 public:
210 virtual bool OnInit();
211 };
212
213 // main program
214
215 IMPLEMENT_APP(MyApp)
216
217 // MyCanvas
218
219 IMPLEMENT_DYNAMIC_CLASS(MyCanvas, wxScrolledWindow)
220
221 BEGIN_EVENT_TABLE(MyImageFrame, wxFrame)
222 EVT_PAINT(MyImageFrame::OnPaint)
223 EVT_LEFT_DCLICK(MyImageFrame::OnSave)
224 END_EVENT_TABLE()
225
226 BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
227 EVT_PAINT(MyCanvas::OnPaint)
228 END_EVENT_TABLE()
229
230 MyCanvas::MyCanvas( wxWindow *parent, wxWindowID id,
231 const wxPoint &pos, const wxSize &size )
232 : wxScrolledWindow( parent, id, pos, size, wxSUNKEN_BORDER )
233 #if !defined(__WINDOWS__) || wxUSE_XPM_IN_MSW
234 , m_bmpSmileXpm((const char **) smile_xpm)
235 , m_iconSmileXpm((const char **) smile_xpm)
236 #endif
237 {
238 my_horse_png = (wxBitmap*) NULL;
239 my_horse_jpeg = (wxBitmap*) NULL;
240 my_horse_gif = (wxBitmap*) NULL;
241 my_horse_bmp = (wxBitmap*) NULL;
242 my_horse_pcx = (wxBitmap*) NULL;
243 my_horse_pnm = (wxBitmap*) NULL;
244 my_horse_tiff = (wxBitmap*) NULL;
245 my_horse_xpm = (wxBitmap*) NULL;
246 my_smile_xbm = (wxBitmap*) NULL;
247 my_square = (wxBitmap*) NULL;
248 my_anti = (wxBitmap*) NULL;
249
250 SetBackgroundColour(* wxWHITE);
251
252 wxBitmap bitmap( 100, 100 );
253
254 wxMemoryDC dc;
255 dc.SelectObject( bitmap );
256 dc.SetBrush( wxBrush( "orange", wxSOLID ) );
257 dc.SetPen( *wxBLACK_PEN );
258 dc.DrawRectangle( 0, 0, 100, 100 );
259 dc.SetBrush( *wxWHITE_BRUSH );
260 dc.DrawRectangle( 20, 20, 60, 60 );
261 dc.SelectObject( wxNullBitmap );
262
263 // try to find the directory with our images
264 wxString dir;
265 if ( wxFile::Exists(wxT("./horse.png")) )
266 dir = "./";
267 else if ( wxFile::Exists(wxT("../horse.png")) )
268 dir = "../";
269 else
270 wxLogWarning(wxT("Can't find image files in either '.' or '..'!"));
271
272 wxImage image = bitmap.ConvertToImage();
273
274 #if wxUSE_LIBPNG
275 if ( !image.SaveFile( dir + wxString("test.png"), wxBITMAP_TYPE_PNG ))
276 wxLogError(wxT("Can't save file"));
277
278 image.Destroy();
279
280 image.LoadFile( dir + wxString("test.png") );
281 my_square = new wxBitmap( image );
282
283 image.Destroy();
284
285 if ( !image.LoadFile( dir + wxString("horse.png")) )
286 wxLogError(wxT("Can't load PNG image"));
287 else
288 my_horse_png = new wxBitmap( image );
289 #endif // wxUSE_LIBPNG
290
291 #if wxUSE_LIBJPEG
292 image.Destroy();
293
294 if ( !image.LoadFile( dir + wxString("horse.jpg")) )
295 wxLogError(wxT("Can't load JPG image"));
296 else
297 my_horse_jpeg = new wxBitmap( image );
298 #endif // wxUSE_LIBJPEG
299
300 #if wxUSE_GIF
301 image.Destroy();
302
303 if ( !image.LoadFile( dir + wxString("horse.gif")) )
304 wxLogError(wxT("Can't load GIF image"));
305 else
306 my_horse_gif = new wxBitmap( image );
307 #endif
308
309 #if wxUSE_PCX
310 image.Destroy();
311
312 if ( !image.LoadFile( dir + wxString("horse.pcx"), wxBITMAP_TYPE_PCX ) )
313 wxLogError(wxT("Can't load PCX image"));
314 else
315 my_horse_pcx = new wxBitmap( image );
316 #endif
317
318 image.Destroy();
319
320 if ( !image.LoadFile( dir + wxString("horse.bmp"), wxBITMAP_TYPE_BMP ) )
321 wxLogError(wxT("Can't load BMP image"));
322 else
323 my_horse_bmp = new wxBitmap( image );
324
325 #if wxUSE_XPM
326 image.Destroy();
327
328 if ( !image.LoadFile( dir + wxString("horse.xpm"), wxBITMAP_TYPE_XPM ) )
329 wxLogError(wxT("Can't load XPM image"));
330 else
331 my_horse_xpm = new wxBitmap( image );
332
333 if ( !image.SaveFile( dir + wxString("test.xpm"), wxBITMAP_TYPE_XPM ))
334 wxLogError(wxT("Can't save file"));
335 #endif
336
337 #if wxUSE_PNM
338 image.Destroy();
339
340 if ( !image.LoadFile( dir + wxString("horse.pnm"), wxBITMAP_TYPE_PNM ) )
341 wxLogError(wxT("Can't load PNM image"));
342 else
343 my_horse_pnm = new wxBitmap( image );
344 #endif
345
346 #if wxUSE_LIBTIFF
347 image.Destroy();
348
349 if ( !image.LoadFile( dir + wxString("horse.tif"), wxBITMAP_TYPE_TIF ) )
350 wxLogError(wxT("Can't load TIFF image"));
351 else
352 my_horse_tiff = new wxBitmap( image );
353 #endif
354
355 CreateAntiAliasedBitmap();
356
357 my_smile_xbm = new wxBitmap( (const char*)smile_bits, smile_width,
358 smile_height, 1 );
359
360 #if !defined(__WINDOWS__) || wxUSE_XPM_IN_MSW
361 // demonstrates XPM automatically using the mask when saving
362 if ( m_bmpSmileXpm.Ok() )
363 m_bmpSmileXpm.SaveFile("saved.xpm", wxBITMAP_TYPE_XPM);
364 #endif
365 }
366
367 MyCanvas::~MyCanvas()
368 {
369 delete my_horse_pnm;
370 delete my_horse_png;
371 delete my_horse_jpeg;
372 delete my_horse_gif;
373 delete my_horse_bmp;
374 delete my_horse_pcx;
375 delete my_horse_tiff;
376 delete my_horse_xpm;
377 delete my_smile_xbm;
378 delete my_square;
379 delete my_anti;
380 }
381
382 void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) )
383 {
384 wxPaintDC dc( this );
385 PrepareDC( dc );
386
387 dc.DrawText( "Loaded image", 30, 10 );
388 if (my_square && my_square->Ok()) dc.DrawBitmap( *my_square, 30, 30 );
389
390 dc.DrawText( "Drawn directly", 150, 10 );
391 dc.SetBrush( wxBrush( "orange", wxSOLID ) );
392 dc.SetPen( *wxBLACK_PEN );
393 dc.DrawRectangle( 150, 30, 100, 100 );
394 dc.SetBrush( *wxWHITE_BRUSH );
395 dc.DrawRectangle( 170, 50, 60, 60 );
396
397 if (my_anti && my_anti->Ok())
398 dc.DrawBitmap( *my_anti, 280, 30 );
399
400 dc.DrawText( "PNG handler", 30, 135 );
401 if (my_horse_png && my_horse_png->Ok())
402 {
403 dc.DrawBitmap( *my_horse_png, 30, 150 );
404 wxRect rect(0,0,100,100);
405 wxBitmap sub( my_horse_png->GetSubBitmap(rect) );
406 dc.DrawText( "GetSubBitmap()", 280, 190 );
407 dc.DrawBitmap( sub, 280, 210 );
408 }
409
410 dc.DrawText( "JPEG handler", 30, 365 );
411 if (my_horse_jpeg && my_horse_jpeg->Ok())
412 dc.DrawBitmap( *my_horse_jpeg, 30, 380 );
413
414 dc.DrawText( "GIF handler", 30, 595 );
415 if (my_horse_gif && my_horse_gif->Ok())
416 dc.DrawBitmap( *my_horse_gif, 30, 610 );
417
418 dc.DrawText( "PCX handler", 30, 825 );
419 if (my_horse_pcx && my_horse_pcx->Ok())
420 dc.DrawBitmap( *my_horse_pcx, 30, 840 );
421
422 dc.DrawText( "BMP handler", 30, 1055 );
423 if (my_horse_bmp && my_horse_bmp->Ok())
424 dc.DrawBitmap( *my_horse_bmp, 30, 1070 );
425
426 dc.DrawText( "PNM handler", 30, 1285 );
427 if (my_horse_pnm && my_horse_pnm->Ok())
428 dc.DrawBitmap( *my_horse_pnm, 30, 1300 );
429
430 dc.DrawText( "TIFF handler", 30, 1515 );
431 if (my_horse_tiff && my_horse_tiff->Ok())
432 dc.DrawBitmap( *my_horse_tiff, 30, 1530 );
433
434 dc.DrawText( "XPM handler", 30, 1745 );
435 if (my_horse_xpm && my_horse_xpm->Ok())
436 dc.DrawBitmap( *my_horse_xpm, 30, 1760 );
437
438 if (my_smile_xbm && my_smile_xbm->Ok())
439 {
440 dc.DrawText( "XBM bitmap", 30, 1975 );
441 dc.DrawText( "(green on red)", 30, 1990 );
442 dc.SetTextForeground( "GREEN" );
443 dc.SetTextBackground( "RED" );
444 dc.DrawBitmap( *my_smile_xbm, 30, 2010 );
445
446 dc.SetTextForeground( "BLACK" );
447 dc.DrawText( "After wxImage conversion", 150, 1975 );
448 dc.DrawText( "(red on white)", 150, 1990 );
449 dc.SetTextForeground( "RED" );
450 wxImage i = my_smile_xbm->ConvertToImage();
451 i.SetMaskColour( 255, 255, 255 );
452 i.Replace( 0, 0, 0,
453 wxRED_PEN->GetColour().Red(),
454 wxRED_PEN->GetColour().Green(),
455 wxRED_PEN->GetColour().Blue() );
456 dc.DrawBitmap( i.ConvertToBitmap(), 150, 2010, TRUE );
457 dc.SetTextForeground( "BLACK" );
458 }
459
460
461 wxBitmap mono( 60,50,1 );
462 wxMemoryDC memdc;
463 memdc.SelectObject( mono );
464 memdc.SetPen( *wxBLACK_PEN );
465 memdc.SetBrush( *wxWHITE_BRUSH );
466 memdc.DrawRectangle( 0,0,60,50 );
467 memdc.SetTextForeground( *wxBLACK );
468 memdc.DrawText( "Hi!", 5, 5 );
469 memdc.SetBrush( *wxBLACK_BRUSH );
470 memdc.DrawRectangle( 33,5,20,20 );
471 memdc.SetPen( *wxRED_PEN );
472 memdc.DrawLine( 5, 42, 50, 42 );
473 memdc.SelectObject( wxNullBitmap );
474
475 if (mono.Ok())
476 {
477 dc.DrawText( "Mono bitmap", 30, 2095 );
478 dc.DrawText( "(red on green)", 30, 2110 );
479 dc.SetTextForeground( "RED" );
480 dc.SetTextBackground( "GREEN" );
481 dc.DrawBitmap( mono, 30, 2130 );
482
483 dc.SetTextForeground( "BLACK" );
484 dc.DrawText( "After wxImage conversion", 150, 2095 );
485 dc.DrawText( "(red on white)", 150, 2110 );
486 dc.SetTextForeground( "RED" );
487 wxImage i = mono.ConvertToImage();
488 i.SetMaskColour( 255,255,255 );
489 i.Replace( 0,0,0,
490 wxRED_PEN->GetColour().Red(),
491 wxRED_PEN->GetColour().Green(),
492 wxRED_PEN->GetColour().Blue() );
493 dc.DrawBitmap( i.ConvertToBitmap(), 150, 2130, TRUE );
494 dc.SetTextForeground( "BLACK" );
495 }
496
497 dc.DrawText("XPM bitmap", 30, 2230);
498 if ( m_bmpSmileXpm.Ok() )
499 {
500 dc.DrawBitmap(m_bmpSmileXpm, 30, 2250, TRUE);
501 }
502
503 dc.DrawText("XPM icon", 150, 2230);
504 if ( m_iconSmileXpm.Ok() )
505 {
506 dc.DrawIcon(m_iconSmileXpm, 150, 2250);
507 }
508 }
509
510 void MyCanvas::CreateAntiAliasedBitmap()
511 {
512 wxBitmap bitmap( 300, 300 );
513
514 wxMemoryDC dc;
515
516 dc.SelectObject( bitmap );
517
518 dc.Clear();
519
520 dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL) );
521 dc.SetTextForeground( "RED" );
522 dc.DrawText( "This is anti-aliased Text.", 20, 20 );
523 dc.DrawText( "And a Rectangle.", 20, 60 );
524
525 dc.SetBrush( *wxRED_BRUSH );
526 dc.SetPen( *wxTRANSPARENT_PEN );
527 dc.DrawRoundedRectangle( 20, 100, 200, 180, 20 );
528
529 wxImage original= bitmap.ConvertToImage();
530 wxImage anti( 150, 150 );
531
532 /* This is quite slow, but safe. Use wxImage::GetData() for speed instead. */
533
534 for (int y = 1; y < 149; y++)
535 for (int x = 1; x < 149; x++)
536 {
537 int red = original.GetRed( x*2, y*2 ) +
538 original.GetRed( x*2-1, y*2 ) +
539 original.GetRed( x*2, y*2+1 ) +
540 original.GetRed( x*2+1, y*2+1 );
541 red = red/4;
542
543 int green = original.GetGreen( x*2, y*2 ) +
544 original.GetGreen( x*2-1, y*2 ) +
545 original.GetGreen( x*2, y*2+1 ) +
546 original.GetGreen( x*2+1, y*2+1 );
547 green = green/4;
548
549 int blue = original.GetBlue( x*2, y*2 ) +
550 original.GetBlue( x*2-1, y*2 ) +
551 original.GetBlue( x*2, y*2+1 ) +
552 original.GetBlue( x*2+1, y*2+1 );
553 blue = blue/4;
554 anti.SetRGB( x, y, red, green, blue );
555 }
556 my_anti = new wxBitmap( anti.ConvertToBitmap() );
557 }
558
559 // MyFrame
560
561 const int ID_QUIT = 108;
562 const int ID_ABOUT = 109;
563 const int ID_NEW = 110;
564
565 IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
566
567 BEGIN_EVENT_TABLE(MyFrame,wxFrame)
568 EVT_MENU (ID_ABOUT, MyFrame::OnAbout)
569 EVT_MENU (ID_QUIT, MyFrame::OnQuit)
570 EVT_MENU (ID_NEW, MyFrame::OnNewFrame)
571 END_EVENT_TABLE()
572
573 MyFrame::MyFrame()
574 : wxFrame( (wxFrame *)NULL, -1, "wxImage sample",
575 wxPoint(20,20), wxSize(470,360) )
576 {
577 wxMenu *file_menu = new wxMenu();
578 file_menu->Append( ID_NEW, "&Show image...");
579 file_menu->AppendSeparator();
580 file_menu->Append( ID_ABOUT, "&About...");
581 file_menu->AppendSeparator();
582 file_menu->Append( ID_QUIT, "E&xit");
583
584 wxMenuBar *menu_bar = new wxMenuBar();
585 menu_bar->Append(file_menu, "&File");
586
587 SetMenuBar( menu_bar );
588
589 CreateStatusBar(2);
590 int widths[] = { -1, 100 };
591 SetStatusWidths( 2, widths );
592
593 m_canvas = new MyCanvas( this, -1, wxPoint(0,0), wxSize(10,10) );
594
595 // 500 width * 2100 height
596 m_canvas->SetScrollbars( 10, 10, 50, 220 );
597 }
598
599 void MyFrame::OnQuit( wxCommandEvent &WXUNUSED(event) )
600 {
601 Close( TRUE );
602 }
603
604 void MyFrame::OnAbout( wxCommandEvent &WXUNUSED(event) )
605 {
606 (void)wxMessageBox( "wxImage demo\n"
607 "Robert Roebling (c) 1998,2000",
608 "About wxImage Demo", wxICON_INFORMATION | wxOK );
609 }
610
611 void MyFrame::OnNewFrame( wxCommandEvent &WXUNUSED(event) )
612 {
613 wxString filename = wxFileSelector(_T("Select image file"));
614 if ( !filename )
615 return;
616
617 wxImage image;
618 if ( !image.LoadFile(filename) )
619 {
620 wxLogError(_T("Couldn't load image from '%s'."), filename.c_str());
621
622 return;
623 }
624
625 (new MyImageFrame(this, image.ConvertToBitmap()))->Show();
626 }
627
628 //-----------------------------------------------------------------------------
629 // MyApp
630 //-----------------------------------------------------------------------------
631
632 bool MyApp::OnInit()
633 {
634 #if wxUSE_LIBPNG
635 wxImage::AddHandler( new wxPNGHandler );
636 #endif
637
638 #if wxUSE_LIBJPEG
639 wxImage::AddHandler( new wxJPEGHandler );
640 #endif
641
642 #if wxUSE_LIBTIFF
643 wxImage::AddHandler( new wxTIFFHandler );
644 #endif
645
646 #if wxUSE_GIF
647 wxImage::AddHandler( new wxGIFHandler );
648 #endif
649
650 #if wxUSE_PCX
651 wxImage::AddHandler( new wxPCXHandler );
652 #endif
653
654 #if wxUSE_PNM
655 wxImage::AddHandler( new wxPNMHandler );
656 #endif
657
658 #if wxUSE_XPM
659 wxImage::AddHandler( new wxXPMHandler );
660 #endif
661
662 wxFrame *frame = new MyFrame();
663 frame->Show( TRUE );
664
665 return TRUE;
666 }
667