]> git.saurik.com Git - wxWidgets.git/blame - src/html/m_image.cpp
compilation fix for recent commit
[wxWidgets.git] / src / html / m_image.cpp
CommitLineData
5526e819 1/////////////////////////////////////////////////////////////////////////////
c88293a4 2// Name: m_image.cpp
5526e819
VS
3// Purpose: wxHtml module for displaying images
4// Author: Vaclav Slavik
69941f05 5// RCS-ID: $Id$
25082126 6// Copyright: (c) 1999 Vaclav Slavik, Joel Lucsy
5526e819
VS
7// Licence: wxWindows Licence
8/////////////////////////////////////////////////////////////////////////////
9
3364ab79
RS
10#ifdef __GNUG__
11#pragma implementation
12#endif
13
25082126 14#include "wx/wxprec.h"
3364ab79 15
5526e819 16#include "wx/defs.h"
f6bcfd97 17#if wxUSE_HTML && wxUSE_STREAMS
5526e819 18
3364ab79
RS
19#ifdef __BORDLANDC__
20#pragma hdrstop
21#endif
22
23#ifndef WXPRECOMP
04dbb646 24 #include "wx/dc.h"
ea5c1679
VS
25 #include "wx/scrolwin.h"
26 #include "wx/timer.h"
2d963ba2 27 #include "wx/dcmemory.h"
3364ab79
RS
28#endif
29
69941f05
VS
30#include "wx/html/forcelnk.h"
31#include "wx/html/m_templ.h"
5526e819 32
25082126 33#include "wx/image.h"
ea5c1679 34#include "wx/gifdecod.h"
25082126
VS
35#include "wx/dynarray.h"
36
37#include <math.h>
38#include <float.h>
5526e819 39
c88293a4 40FORCE_LINK_ME(m_image)
5526e819
VS
41
42
25082126
VS
43
44
45WX_DECLARE_OBJARRAY(int, CoordArray);
3096bd2f 46#include "wx/arrimpl.cpp" // this is a magic incantation which must be done!
25082126
VS
47WX_DEFINE_OBJARRAY(CoordArray);
48
49
50//--------------------------------------------------------------------------------
51// wxHtmlImageMapAreaCell
52// 0-width, 0-height cell that represents single area in imagemap
53// (it's GetLink is called from wxHtmlImageCell's)
54//--------------------------------------------------------------------------------
55
56class wxHtmlImageMapAreaCell : public wxHtmlCell
57{
01325161
VS
58 public:
59 enum celltype { CIRCLE, RECT, POLY };
60 protected:
61 CoordArray coords;
62 celltype type;
edbd0635 63 int radius;
01325161 64 public:
edbd0635 65 wxHtmlImageMapAreaCell( celltype t, wxString &coords, double pixel_scale = 1.0);
846914d1 66 virtual wxHtmlLinkInfo *GetLink( int x = 0, int y = 0 ) const;
25082126
VS
67};
68
69
70
71
72
edbd0635 73wxHtmlImageMapAreaCell::wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::celltype t, wxString &incoords, double pixel_scale )
25082126 74{
edbd0635 75 int i;
01325161
VS
76 wxString x = incoords, y;
77
78 type = t;
04dbb646 79 while ((i = x.Find( ',' )) != -1)
4f9297b0 80 {
edbd0635 81 coords.Add( (int)(pixel_scale * (double)wxAtoi( x.Left( i ).c_str())) );
01325161
VS
82 x = x.Mid( i + 1 );
83 }
edbd0635 84 coords.Add( (int)(pixel_scale * (double)wxAtoi( x.c_str())) );
25082126
VS
85}
86
846914d1 87wxHtmlLinkInfo *wxHtmlImageMapAreaCell::GetLink( int x, int y ) const
25082126 88{
04dbb646 89 switch (type)
4f9297b0 90 {
01325161
VS
91 case RECT:
92 {
edbd0635 93 int l, t, r, b;
01325161
VS
94
95 l = coords[ 0 ];
96 t = coords[ 1 ];
97 r = coords[ 2 ];
98 b = coords[ 3 ];
04dbb646
VZ
99 if (x >= l && x <= r && y >= t && y <= b)
100 {
01325161
VS
101 return m_Link;
102 }
103 break;
104 }
105 case CIRCLE:
106 {
edbd0635
VS
107 int l, t, r;
108 double d;
01325161
VS
109
110 l = coords[ 0 ];
111 t = coords[ 1 ];
112 r = coords[ 2 ];
113 d = sqrt( (double) (((x - l) * (x - l)) + ((y - t) * (y - t))) );
04dbb646
VZ
114 if (d < (double)r)
115 {
01325161
VS
116 return m_Link;
117 }
118 }
119 break;
120 case POLY:
121 {
04dbb646
VZ
122 if (coords.GetCount() >= 6)
123 {
edbd0635
VS
124 int intersects = 0;
125 int wherex = x;
126 int wherey = y;
127 int totalv = coords.GetCount() / 2;
128 int totalc = totalv * 2;
129 int xval = coords[totalc - 2];
130 int yval = coords[totalc - 1];
131 int end = totalc;
132 int pointer = 1;
01325161 133
04dbb646
VZ
134 if ((yval >= wherey) != (coords[pointer] >= wherey))
135 {
136 if ((xval >= wherex) == (coords[0] >= wherex))
137 {
01325161 138 intersects += (xval >= wherex) ? 1 : 0;
04dbb646
VZ
139 }
140 else
141 {
01325161
VS
142 intersects += ((xval - (yval - wherey) *
143 (coords[0] - xval) /
144 (coords[pointer] - yval)) >= wherex) ? 1 : 0;
145 }
146 }
147
04dbb646
VZ
148 while (pointer < end)
149 {
01325161
VS
150 yval = coords[pointer];
151 pointer += 2;
04dbb646
VZ
152 if (yval >= wherey)
153 {
154 while ((pointer < end) && (coords[pointer] >= wherey))
155 {
01325161
VS
156 pointer += 2;
157 }
04dbb646
VZ
158 if (pointer >= end)
159 {
01325161
VS
160 break;
161 }
162 if ((coords[pointer - 3] >= wherex) ==
163 (coords[pointer - 1] >= wherex)) {
164 intersects += (coords[pointer - 3] >= wherex) ? 1 : 0;
04dbb646
VZ
165 }
166 else
167 {
01325161
VS
168 intersects +=
169 ((coords[pointer - 3] - (coords[pointer - 2] - wherey) *
170 (coords[pointer - 1] - coords[pointer - 3]) /
171 (coords[pointer] - coords[pointer - 2])) >= wherex) ? 1 : 0;
172 }
04dbb646
VZ
173 }
174 else
175 {
176 while ((pointer < end) && (coords[pointer] < wherey))
177 {
01325161
VS
178 pointer += 2;
179 }
04dbb646
VZ
180 if (pointer >= end)
181 {
01325161
VS
182 break;
183 }
184 if ((coords[pointer - 3] >= wherex) ==
04dbb646
VZ
185 (coords[pointer - 1] >= wherex))
186 {
01325161 187 intersects += (coords[pointer - 3] >= wherex) ? 1 : 0;
04dbb646
VZ
188 }
189 else
190 {
01325161
VS
191 intersects +=
192 ((coords[pointer - 3] - (coords[pointer - 2] - wherey) *
193 (coords[pointer - 1] - coords[pointer - 3]) /
194 (coords[pointer] - coords[pointer - 2])) >= wherex) ? 1 : 0;
195 }
196 }
197 }
04dbb646
VZ
198 if ((intersects & 1) != 0)
199 {
01325161
VS
200 return m_Link;
201 }
202 }
203 }
204 break;
205 }
4f9297b0 206
04dbb646 207 if (m_Next)
4f9297b0 208 {
edbd0635 209 wxHtmlImageMapAreaCell *a = (wxHtmlImageMapAreaCell*)m_Next;
01325161
VS
210 return a->GetLink( x, y );
211 }
846914d1 212 return NULL;
25082126
VS
213}
214
215
216
217
218
219
220
221
222//--------------------------------------------------------------------------------
223// wxHtmlImageMapCell
224// 0-width, 0-height cell that represents map from imagemaps
225// it is always placed before wxHtmlImageMapAreaCells
efba2b89 226// It responds to Find(wxHTML_COND_ISIMAGEMAP)
25082126
VS
227//--------------------------------------------------------------------------------
228
229
230class wxHtmlImageMapCell : public wxHtmlCell
231{
01325161
VS
232 public:
233 wxHtmlImageMapCell( wxString &name );
234 protected:
235 wxString m_Name;
236 public:
846914d1 237 virtual wxHtmlLinkInfo *GetLink( int x = 0, int y = 0 ) const;
01325161 238 virtual const wxHtmlCell *Find( int cond, const void *param ) const;
25082126
VS
239};
240
241
242wxHtmlImageMapCell::wxHtmlImageMapCell( wxString &name )
243{
01325161 244 m_Name = name ;
25082126
VS
245}
246
846914d1 247wxHtmlLinkInfo *wxHtmlImageMapCell::GetLink( int x, int y ) const
25082126 248{
edbd0635 249 wxHtmlImageMapAreaCell *a = (wxHtmlImageMapAreaCell*)m_Next;
01325161
VS
250 if (a)
251 return a->GetLink( x, y );
252 return wxHtmlCell::GetLink( x, y );
25082126
VS
253}
254
255const wxHtmlCell *wxHtmlImageMapCell::Find( int cond, const void *param ) const
256{
04dbb646 257 if (cond == wxHTML_COND_ISIMAGEMAP)
4f9297b0 258 {
01325161
VS
259 if (m_Name == *((wxString*)(param)))
260 return this;
261 }
262 return wxHtmlCell::Find(cond, param);
25082126
VS
263}
264
265
266
267
268
5526e819
VS
269//--------------------------------------------------------------------------------
270// wxHtmlImageCell
271// Image/bitmap
272//--------------------------------------------------------------------------------
273
274class wxHtmlImageCell : public wxHtmlCell
275{
ea5c1679
VS
276public:
277 wxHtmlImageCell(wxWindow *window,
278 wxFSFile *input, int w = -1, int h = -1,
279 double scale = 1.0, int align = wxHTML_ALIGN_BOTTOM,
280 const wxString& mapname = wxEmptyString);
281 ~wxHtmlImageCell();
282 void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2);
283 virtual wxHtmlLinkInfo *GetLink(int x = 0, int y = 0) const;
284
285 void SetImage(const wxImage& img);
286#if wxUSE_GIF && wxUSE_TIMER
287 void AdvanceAnimation(wxTimer *timer);
288 virtual void Layout(int w);
289#endif
290
291private:
292 wxBitmap *m_bitmap;
293 int m_bmpW, m_bmpH;
294 wxScrolledWindow *m_window;
295#if wxUSE_GIF && wxUSE_TIMER
296 wxGIFDecoder *m_gifDecoder;
297 wxTimer *m_gifTimer;
298 int m_physX, m_physY;
299#endif
300 double m_scale;
301 wxHtmlImageMapCell *m_imageMap;
302 wxString m_mapName;
5526e819
VS
303};
304
ea5c1679
VS
305#if wxUSE_GIF && wxUSE_TIMER
306class wxGIFTimer : public wxTimer
307{
308 public:
309 wxGIFTimer(wxHtmlImageCell *cell) : m_cell(cell) {}
310 virtual void Notify()
311 {
312 m_cell->AdvanceAnimation(this);
313 }
5526e819 314
ea5c1679
VS
315 private:
316 wxHtmlImageCell *m_cell;
317};
318#endif
5526e819 319
25082126 320
5526e819
VS
321//--------------------------------------------------------------------------------
322// wxHtmlImageCell
323//--------------------------------------------------------------------------------
324
ea5c1679
VS
325wxHtmlImageCell::wxHtmlImageCell(wxWindow *window, wxFSFile *input,
326 int w, int h, double scale, int align,
327 const wxString& mapname) : wxHtmlCell()
5526e819 328{
ea5c1679
VS
329 m_window = wxStaticCast(window, wxScrolledWindow);
330 m_scale = scale;
331 m_bitmap = NULL;
332 m_bmpW = w;
333 m_bmpH = h;
334 m_imageMap = NULL;
335 m_mapName = mapname;
336 SetCanLiveOnPagebreak(FALSE);
337#if wxUSE_GIF && wxUSE_TIMER
338 m_gifDecoder = NULL;
339 m_gifTimer = NULL;
340 m_physX = m_physY = -1;
341#endif
04dbb646 342
ea5c1679
VS
343 wxInputStream *s = input->GetStream();
344
345 if ( s )
4f9297b0 346 {
ea5c1679
VS
347 bool readImg = TRUE;
348
349#if wxUSE_GIF && wxUSE_TIMER
350 if ( (input->GetLocation().Matches(wxT("*.gif")) ||
351 input->GetLocation().Matches(wxT("*.GIF"))) && m_window )
352 {
353 m_gifDecoder = new wxGIFDecoder(s, TRUE);
354 if ( m_gifDecoder->ReadGIF() == wxGIF_OK )
355 {
356 wxImage img;
357 if ( m_gifDecoder->ConvertToImage(&img) )
358 SetImage(img);
37a1f3f6 359
ea5c1679 360 readImg = FALSE;
37a1f3f6 361
ea5c1679
VS
362 if ( m_gifDecoder->IsAnimation() )
363 {
364 m_gifTimer = new wxGIFTimer(this);
365 m_gifTimer->Start(m_gifDecoder->GetDelay(), TRUE);
366 }
367 else
368 {
369 wxDELETE(m_gifDecoder);
370 }
371 }
372 else
373 {
374 wxDELETE(m_gifDecoder);
375 }
376 }
377
378 if ( readImg )
379#endif
04dbb646 380 {
ea5c1679 381 SetImage(wxImage(*s, wxBITMAP_TYPE_ANY));
04dbb646 382 }
5526e819 383 }
ea5c1679
VS
384
385 m_Width = (int)(scale * (double)m_bmpW);
386 m_Height = (int)(scale * (double)m_bmpH);
387
04dbb646 388 switch (align)
4f9297b0 389 {
efba2b89 390 case wxHTML_ALIGN_TOP :
01325161
VS
391 m_Descent = m_Height;
392 break;
efba2b89 393 case wxHTML_ALIGN_CENTER :
01325161
VS
394 m_Descent = m_Height / 2;
395 break;
396 case wxHTML_ALIGN_BOTTOM :
397 default :
398 m_Descent = 0;
399 break;
5526e819 400 }
ea5c1679 401 }
25082126 402
ea5c1679
VS
403void wxHtmlImageCell::SetImage(const wxImage& img)
404{
405 if ( img.Ok() )
406 {
407 delete m_bitmap;
408
409 int ww, hh;
410 ww = img.GetWidth();
411 hh = img.GetHeight();
412
413 if ( m_bmpW == -1 )
414 m_bmpW = ww;
415 if ( m_bmpH == -1 )
416 m_bmpH = hh;
417
418 if ((m_bmpW != ww) || (m_bmpH != hh))
419 {
420 wxImage img2 = img.Scale(m_bmpW, m_bmpH);
421 m_bitmap = new wxBitmap(img2);
422 }
423 else
424 m_bitmap = new wxBitmap(img);
425 }
5526e819
VS
426}
427
ea5c1679
VS
428#if wxUSE_GIF && wxUSE_TIMER
429void wxHtmlImageCell::AdvanceAnimation(wxTimer *timer)
430{
431 wxImage img;
432
433 m_gifDecoder->GoNextFrame(TRUE);
434
435 if ( m_physX == -1 )
436 {
437 m_physX = m_physY = 0;
438 for (wxHtmlCell *cell = this; cell; cell = cell->GetParent())
439 {
440 m_physX += cell->GetPosX();
441 m_physY += cell->GetPosY();
442 }
443 }
444
445 int x, y;
446 m_window->CalcScrolledPosition(m_physX, m_physY, &x, &y);
447 wxRect rect(x, y, m_Width, m_Height);
448
449 if ( m_window->GetClientRect().Intersects(rect) &&
450 m_gifDecoder->ConvertToImage(&img) )
451 {
2d963ba2
VS
452 if ( (int)m_gifDecoder->GetWidth() != m_Width ||
453 (int)m_gifDecoder->GetHeight() != m_Height ||
454 m_gifDecoder->GetLeft() != 0 || m_gifDecoder->GetTop() != 0 )
455 {
456 wxBitmap bmp(img);
457 wxMemoryDC dc;
458 dc.SelectObject(*m_bitmap);
459 dc.DrawBitmap(bmp, m_gifDecoder->GetLeft(), m_gifDecoder->GetTop());
460 }
461 else
462 SetImage(img);
ea5c1679
VS
463 m_window->Refresh(img.HasMask(), &rect);
464 }
465
466 timer->Start(m_gifDecoder->GetDelay(), TRUE);
467}
468
469void wxHtmlImageCell::Layout(int w)
470{
471 wxHtmlCell::Layout(w);
472 m_physX = m_physY = -1;
473}
474
475#endif
476
477wxHtmlImageCell::~wxHtmlImageCell()
478{
479 delete m_bitmap;
480#if wxUSE_GIF && wxUSE_TIMER
481 delete m_gifTimer;
482 delete m_gifDecoder;
483#endif
484}
5526e819
VS
485
486
d699f48b 487void wxHtmlImageCell::Draw(wxDC& dc, int x, int y, int WXUNUSED(view_y1), int WXUNUSED(view_y2))
5526e819 488{
ea5c1679 489 if (m_bitmap)
b5c01940
VS
490 {
491 double us_x, us_y;
492 dc.GetUserScale(&us_x, &us_y);
ea5c1679 493 dc.SetUserScale(us_x * m_scale, us_y * m_scale);
04dbb646 494
ea5c1679
VS
495 dc.DrawBitmap(*m_bitmap, (int) ((x + m_PosX) / m_scale),
496 (int) ((y + m_PosY) / m_scale), TRUE);
b5c01940
VS
497 dc.SetUserScale(us_x, us_y);
498 }
5526e819
VS
499}
500
846914d1 501wxHtmlLinkInfo *wxHtmlImageCell::GetLink( int x, int y ) const
25082126 502{
ea5c1679 503 if (m_mapName.IsEmpty())
01325161 504 return wxHtmlCell::GetLink( x, y );
ea5c1679 505 if (!m_imageMap)
4f9297b0 506 {
edbd0635 507 wxHtmlContainerCell *p, *op;
01325161 508 op = p = GetParent();
04dbb646
VZ
509 while (p)
510 {
01325161
VS
511 op = p;
512 p = p->GetParent();
513 }
514 p = op;
ea5c1679
VS
515 wxHtmlCell *cell = (wxHtmlCell*)p->Find(wxHTML_COND_ISIMAGEMAP,
516 (const void*)(&m_mapName));
04dbb646
VZ
517 if (!cell)
518 {
ea5c1679 519 ((wxString&)m_mapName).Clear();
01325161
VS
520 return wxHtmlCell::GetLink( x, y );
521 }
4f9297b0 522 { // dirty hack, ask Joel why he fills m_ImageMap in this place
01325161 523 // THE problem is that we're in const method and we can't modify m_ImageMap
ea5c1679 524 wxHtmlImageMapCell **cx = (wxHtmlImageMapCell**)(&m_imageMap);
01325161 525 *cx = (wxHtmlImageMapCell*)cell;
25082126 526 }
01325161 527 }
ea5c1679 528 return m_imageMap->GetLink(x, y);
25082126 529}
5526e819
VS
530
531
532
533//--------------------------------------------------------------------------------
534// tag handler
535//--------------------------------------------------------------------------------
536
01325161 537TAG_HANDLER_BEGIN(IMG, "IMG,MAP,AREA")
5526e819
VS
538
539 TAG_HANDLER_PROC(tag)
540 {
04dbb646
VZ
541 if (tag.GetName() == wxT("IMG"))
542 {
543 if (tag.HasParam(wxT("SRC")))
544 {
01325161
VS
545 int w = -1, h = -1;
546 int al;
547 wxFSFile *str;
0413cec5 548 wxString tmp = tag.GetParam(wxT("SRC"));
01325161
VS
549 wxString mn = wxEmptyString;
550
4f9297b0 551 str = m_WParser->GetFS()->OpenFile(tmp);
04dbb646 552 if (tag.HasParam(wxT("WIDTH")))
8bd72d90 553 tag.GetParamAsInt(wxT("WIDTH"), &w);
04dbb646 554 if (tag.HasParam(wxT("HEIGHT")))
8bd72d90 555 tag.GetParamAsInt(wxT("HEIGHT"), &h);
01325161 556 al = wxHTML_ALIGN_BOTTOM;
04dbb646
VZ
557 if (tag.HasParam(wxT("ALIGN")))
558 {
0413cec5 559 wxString alstr = tag.GetParam(wxT("ALIGN"));
01325161 560 alstr.MakeUpper(); // for the case alignment was in ".."
04dbb646 561 if (alstr == wxT("TEXTTOP"))
8bd72d90 562 al = wxHTML_ALIGN_TOP;
04dbb646 563 else if ((alstr == wxT("CENTER")) || (alstr == wxT("ABSCENTER")))
8bd72d90 564 al = wxHTML_ALIGN_CENTER;
01325161 565 }
04dbb646
VZ
566 if (tag.HasParam(wxT("USEMAP")))
567 {
0413cec5 568 mn = tag.GetParam( wxT("USEMAP") );
04dbb646
VZ
569 if (mn.GetChar(0) == wxT('#'))
570 {
01325161
VS
571 mn = mn.Mid( 1 );
572 }
573 }
574 wxHtmlImageCell *cel = NULL;
04dbb646
VZ
575 if (str)
576 {
ea5c1679
VS
577 cel = new wxHtmlImageCell(m_WParser->GetWindow(),
578 str, w, h,
579 m_WParser->GetPixelScale(),
580 al, mn);
4f9297b0 581 cel->SetLink(m_WParser->GetLink());
50da928b 582 cel->SetId(tag.GetParam(wxT("id"))); // may be empty
4f9297b0 583 m_WParser->GetContainer()->InsertCell(cel);
01325161
VS
584 delete str;
585 }
586 }
587 }
04dbb646
VZ
588 if (tag.GetName() == wxT("MAP"))
589 {
01325161
VS
590 m_WParser->CloseContainer();
591 m_WParser->OpenContainer();
04dbb646
VZ
592 if (tag.HasParam(wxT("NAME")))
593 {
0413cec5 594 wxString tmp = tag.GetParam(wxT("NAME"));
01325161
VS
595 wxHtmlImageMapCell *cel = new wxHtmlImageMapCell( tmp );
596 m_WParser->GetContainer()->InsertCell( cel );
597 }
598 ParseInner( tag );
599 m_WParser->CloseContainer();
600 m_WParser->OpenContainer();
601 }
04dbb646
VZ
602 if (tag.GetName() == wxT("AREA"))
603 {
604 if (tag.HasParam(wxT("SHAPE")))
605 {
0413cec5 606 wxString tmp = tag.GetParam(wxT("SHAPE"));
edbd0635 607 wxString coords = wxEmptyString;
01325161
VS
608 tmp.MakeUpper();
609 wxHtmlImageMapAreaCell *cel = NULL;
04dbb646
VZ
610 if (tag.HasParam(wxT("COORDS")))
611 {
0413cec5 612 coords = tag.GetParam(wxT("COORDS"));
01325161 613 }
04dbb646
VZ
614 if (tmp == wxT("POLY"))
615 {
4f9297b0 616 cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::POLY, coords, m_WParser->GetPixelScale() );
04dbb646
VZ
617 }
618 else if (tmp == wxT("CIRCLE"))
619 {
4f9297b0 620 cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::CIRCLE, coords, m_WParser->GetPixelScale() );
04dbb646
VZ
621 }
622 else if (tmp == wxT("RECT"))
623 {
4f9297b0 624 cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::RECT, coords, m_WParser->GetPixelScale() );
01325161 625 }
04dbb646
VZ
626 if (cel != NULL && tag.HasParam(wxT("HREF")))
627 {
0413cec5 628 wxString tmp = tag.GetParam(wxT("HREF"));
846914d1 629 wxString target = wxEmptyString;
0413cec5 630 if (tag.HasParam(wxT("TARGET"))) target = tag.GetParam(wxT("TARGET"));
846914d1 631 cel->SetLink( wxHtmlLinkInfo(tmp, target));
01325161
VS
632 }
633 if (cel != NULL) m_WParser->GetContainer()->InsertCell( cel );
634 }
635 }
5526e819
VS
636
637 return FALSE;
638 }
639
01325161 640TAG_HANDLER_END(IMG)
5526e819
VS
641
642
643
644TAGS_MODULE_BEGIN(Image)
645
646 TAGS_MODULE_ADD(IMG)
647
648TAGS_MODULE_END(Image)
649
650
3364ab79 651#endif