File: dvpspl.cc

package info (click to toggle)
dcmtk 3.5.4-4
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 23,784 kB
  • ctags: 22,942
  • sloc: cpp: 165,761; ansic: 46,396; sh: 3,808; perl: 3,465; makefile: 3,097
file content (616 lines) | stat: -rw-r--r-- 18,547 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
/*
 *
 *  Copyright (C) 1999-2005, OFFIS
 *
 *  This software and supporting documentation were developed by
 *
 *    Kuratorium OFFIS e.V.
 *    Healthcare Information and Communication Systems
 *    Escherweg 2
 *    D-26121 Oldenburg, Germany
 *
 *  THIS SOFTWARE IS MADE AVAILABLE,  AS IS,  AND OFFIS MAKES NO  WARRANTY
 *  REGARDING  THE  SOFTWARE,  ITS  PERFORMANCE,  ITS  MERCHANTABILITY  OR
 *  FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES  OR
 *  ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND
 *  PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
 *
 *  Module: dcmpstat
 *
 *  Author: Marco Eichelberg
 *
 *  Purpose:
 *    classes: DVPSPresentationLUT
 *
 *  Last Update:      $Author: meichel $
 *  Update Date:      $Date: 2005/12/08 15:46:38 $
 *  CVS/RCS Revision: $Revision: 1.27 $
 *  Status:           $State: Exp $
 *
 *  CVS/RCS Log at end of file
 *
 */

#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
#include "dcmtk/ofstd/ofstring.h"
#include "dcmtk/dcmpstat/dvpspl.h"
#include "dcmtk/dcmpstat/dvpsdef.h"     /* for constants and macros */
#include "dcmtk/dcmnet/dimse.h"

/* --------------- class DVPSPresentationLUT --------------- */

DVPSPresentationLUT::DVPSPresentationLUT()
: presentationLUT(DVPSP_identity)
, presentationLUTDescriptor(DCM_LUTDescriptor)
, presentationLUTExplanation(DCM_LUTExplanation)
, presentationLUTData(DCM_LUTData)
, sOPInstanceUID(DCM_SOPInstanceUID)
, logstream(&ofConsole)
, verboseMode(OFFalse)
, debugMode(OFFalse)
{
}

DVPSPresentationLUT::DVPSPresentationLUT(const DVPSPresentationLUT& copy)
: presentationLUT(copy.presentationLUT)
, presentationLUTDescriptor(copy.presentationLUTDescriptor)
, presentationLUTExplanation(copy.presentationLUTExplanation)
, presentationLUTData(copy.presentationLUTData)
, sOPInstanceUID(copy.sOPInstanceUID)
, logstream(copy.logstream)
, verboseMode(copy.verboseMode)
, debugMode(copy.debugMode)
{
}

DVPSPresentationLUT::~DVPSPresentationLUT()
{
}

void DVPSPresentationLUT::clear()
{
  presentationLUT = DVPSP_identity;
  presentationLUTDescriptor.clear();
  presentationLUTExplanation.clear();
  presentationLUTData.clear();
  sOPInstanceUID.clear();
}

OFCondition DVPSPresentationLUT::read(DcmItem &dset, OFBool withSOPInstance)
{
  DcmSequenceOfItems *seq;
  DcmItem *item;
  OFCondition result = EC_Normal;
  DcmStack stack;
  OFString aString;

  DcmCodeString presentationLUTShape(DCM_PresentationLUTShape);
  
  READ_FROM_DATASET(DcmCodeString, presentationLUTShape)
  if (withSOPInstance) { READ_FROM_DATASET(DcmUniqueIdentifier, sOPInstanceUID) }
  else sOPInstanceUID.clear();
  
  /* read Presentation LUT Sequence */
  if (result==EC_Normal)
  {
    stack.clear();
    if (EC_Normal == dset.search(DCM_PresentationLUTSequence, stack, ESM_fromHere, OFFalse))
    {
      seq=(DcmSequenceOfItems *)stack.top();
      if (seq->card() ==1)
      {
         item = seq->getItem(0);
         stack.clear();
         if (EC_Normal == item->search((DcmTagKey &)presentationLUTDescriptor.getTag(), 
           stack, ESM_fromHere, OFFalse))
         {
           presentationLUTDescriptor = *((DcmUnsignedShort *)(stack.top()));
         }
         stack.clear();
         if (EC_Normal == item->search((DcmTagKey &)presentationLUTExplanation.getTag(), 
           stack, ESM_fromHere, OFFalse))
         {
           presentationLUTExplanation = *((DcmLongString *)(stack.top()));
         }
         stack.clear();
         if (EC_Normal == item->search((DcmTagKey &)presentationLUTData.getTag(), 
           stack, ESM_fromHere, OFFalse))
         {
           presentationLUTData = *((DcmUnsignedShort *)(stack.top()));
         }
      } else {
        result=EC_TagNotFound;
        if (verboseMode)
        {
          logstream->lockCerr() << "Error: found Presentation LUT SQ with number of items != 1" << endl;
          logstream->unlockCerr();
        }
      } 
    }
  }


  /* Now perform basic sanity checks */

  if (presentationLUTShape.getLength() == 0)
  {
    presentationLUT = DVPSP_table;

    if (presentationLUTDescriptor.getLength() == 0)
    {
      result=EC_IllegalCall;
      if (verboseMode)
      {
        logstream->lockCerr() << "Error: presentationLUTShape and presentationLUTDescriptor absent or empty" << endl;
        logstream->unlockCerr();
      }
    }
    else if (presentationLUTDescriptor.getVM() != 3)
    {
      result=EC_IllegalCall;
      if (verboseMode)
      {
        logstream->lockCerr() << "Error: presentationLUTDescriptor present but VM != 3 in presentation state" << endl;
        logstream->unlockCerr();
      }
    }
    if (presentationLUTData.getLength() == 0)
    {
      result=EC_IllegalCall;
      if (verboseMode)
      {
        logstream->lockCerr() << "Error: presentationLUTShape and presentationLUTData absent or empty" << endl;
        logstream->unlockCerr();
      }
    }
  } else {
    if (presentationLUTShape.getVM() != 1)
    {
      result=EC_IllegalCall;
      if (verboseMode)
      {
        logstream->lockCerr() << "Error: presentationLUTShape present but VM != 1" << endl;
        logstream->unlockCerr();
      }
    } else {
      // check presentation LUT shape
      aString.clear();
      presentationLUTShape.getOFString(aString,0);
      if (aString=="IDENTITY") presentationLUT = DVPSP_identity;
      else if (aString=="INVERSE") presentationLUT = DVPSP_inverse;
      else if (aString=="LIN OD") presentationLUT = DVPSP_lin_od;
      else
      {
        result=EC_IllegalCall;
        if (verboseMode)
        {
          logstream->lockCerr() << "Error: unknown presentationLUTShape keyword: " << aString << endl;
          logstream->unlockCerr();
        }
      }
    }
  }

  if (withSOPInstance)
  {
    if (sOPInstanceUID.getLength() == 0)
    {
      result=EC_IllegalCall;
      if (verboseMode)
      {
        logstream->lockCerr() << "Error: sOPInstanceUID absent in Presentation LUT Content Sequence" << endl;
        logstream->unlockCerr();
      }
    }
    else if (sOPInstanceUID.getVM() != 1)
    {
      result=EC_IllegalCall;
      if (verboseMode)
      {
        logstream->lockCerr() << "Error: sOPInstanceUID VM != 1 in Presentation LUT Content Sequence" << endl;
        logstream->unlockCerr();
      }
    }
  }
  
  return result;
}

OFCondition DVPSPresentationLUT::write(DcmItem &dset, OFBool withSOPInstance)
{
  OFCondition result = EC_Normal;
  DcmElement *delem=NULL;
  DcmSequenceOfItems *dseq=NULL;
  DcmItem *ditem=NULL;
  DcmCodeString presentationLUTShape(DCM_PresentationLUTShape);
  
  if (presentationLUT==DVPSP_table)
  {
    if (result == EC_Normal)
    {
      ditem = new DcmItem();
      if (ditem)
      {
        dseq = new DcmSequenceOfItems(DCM_PresentationLUTSequence);
        if (dseq)
        {
          delem = new DcmUnsignedShort(presentationLUTDescriptor);
          if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
          delem = new DcmUnsignedShort(presentationLUTData);
          if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
          if (presentationLUTExplanation.getLength() >0)
          {
            delem = new DcmLongString(presentationLUTExplanation);
            if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
          }
          if (result==EC_Normal)
          {
            dseq->insert(ditem);
            dset.insert(dseq, OFTrue /*replaceOld*/);
          } else {
            // out of memory during creation of sequence contents.
            delete dseq;
            delete ditem;
            result = EC_MemoryExhausted;
          }
        } else {
          // could allocate item but not sequence. Bail out.
          delete ditem;
          result = EC_MemoryExhausted;
        }
      }
      else result = EC_MemoryExhausted;
    }
  } else {
    if (presentationLUT==DVPSP_inverse) presentationLUTShape.putString("INVERSE");
    else if (presentationLUT==DVPSP_lin_od) presentationLUTShape.putString("LIN OD");
    else presentationLUTShape.putString("IDENTITY");
    ADD_TO_DATASET(DcmCodeString, presentationLUTShape)
  }
  if (withSOPInstance) { ADD_TO_DATASET(DcmUniqueIdentifier, sOPInstanceUID) }

  return result;
}


OFBool DVPSPresentationLUT::haveTable()
{
  if ((presentationLUTDescriptor.getVM()==3)&&(presentationLUTData.getLength() > 0)) return OFTrue;
  else return OFFalse;
}

const char *DVPSPresentationLUT::getSOPInstanceUID()
{
  char *c = NULL;
  if (EC_Normal == sOPInstanceUID.getString(c)) return c; else return NULL;
}

const char *DVPSPresentationLUT::getCurrentExplanation()
{
  const char *value = NULL;
  switch (presentationLUT)
  {
    case DVPSP_identity:
      value = "Identity Presentation LUT Shape";
      break;
    case DVPSP_inverse:
      value = "Inverse Presentation LUT Shape";
      break;
    case DVPSP_lin_od:
      value = "Linear Optical Density Presentation LUT Shape";
      break;
    case DVPSP_table:
      value = getLUTExplanation();
      if (value==NULL) value = "Unnamed Presentation LUT";
      break;
  }
  return value;
}

const char *DVPSPresentationLUT::getLUTExplanation()
{
  char *value = NULL;
  if (EC_Normal != presentationLUTExplanation.getString(value)) return NULL;
  return value;
}

OFCondition DVPSPresentationLUT::setLUT(
    DcmUnsignedShort& lutDescriptor,
    DcmUnsignedShort& lutData,
    DcmLongString& lutExplanation)
{
  if ((lutDescriptor.getVM()==3)&&(lutData.getLength() > 0))
  {
    presentationLUTDescriptor = lutDescriptor;
    presentationLUTData = lutData;
    presentationLUTExplanation = lutExplanation;
    presentationLUT = DVPSP_table;
  } else return EC_IllegalCall;
  return EC_Normal;
}

OFCondition DVPSPresentationLUT::setType(DVPSPresentationLUTType newType)
{
  if ((newType == DVPSP_table)&&(! haveTable())) return EC_IllegalCall;
  presentationLUT = newType;
  return EC_Normal;
}


OFCondition DVPSPresentationLUT::setSOPInstanceUID(const char *value)
{
  if ((value==NULL)||(strlen(value)==0)) return EC_IllegalCall;
  return sOPInstanceUID.putString(value);
}


OFBool DVPSPresentationLUT::isLegalPrintPresentationLUT()
{
  OFBool result = OFFalse;
  Uint16 val=0;
  switch (presentationLUT)
  {
    case DVPSP_table:
      if (EC_Normal == presentationLUTDescriptor.getUint16(val,2))
      {
        if ((val>=10)&&(val<=16)) result = OFTrue;
      }
      break;
    case DVPSP_inverse:
      break;
    case DVPSP_identity:
    case DVPSP_lin_od:
      result = OFTrue;
      break;
  }
  return result;
}
  
OFBool DVPSPresentationLUT::matchesImageDepth(OFBool is12bit)
{
  Uint16 numEntries=0;
  Uint16 firstMapped=0;
  OFBool result = OFFalse;
  switch (presentationLUT)
  {
    case DVPSP_table:

      if ((EC_Normal == presentationLUTDescriptor.getUint16(numEntries,0)) &&
         (EC_Normal == presentationLUTDescriptor.getUint16(firstMapped,1)))
      {
      	if ((firstMapped == 0)&&((is12bit && (numEntries == 4096))||((!is12bit) && (numEntries == 256)))) result = OFTrue;
      }
      break;
    case DVPSP_inverse:
      break;
    case DVPSP_identity:
    case DVPSP_lin_od:
      result = OFTrue;
      break;
  }
  return result;
}

DVPSPrintPresentationLUTAlignment DVPSPresentationLUT::getAlignment()
{
  if (presentationLUT == DVPSP_table)
  {
    Uint16 numberOfEntries = 0;
    Uint16 firstEntryMapped = 0xFFFF;
    if (EC_Normal != presentationLUTDescriptor.getUint16(numberOfEntries, 0)) numberOfEntries = 0;
    if (EC_Normal != presentationLUTDescriptor.getUint16(firstEntryMapped, 1)) firstEntryMapped = 0xFFFF;
    if ((numberOfEntries == 256)&&(firstEntryMapped == 0)) return DVPSK_table8;
    if ((numberOfEntries == 4096)&&(firstEntryMapped == 0)) return DVPSK_table12;
    return DVPSK_other;
  }
  return DVPSK_shape;
}


OFBool DVPSPresentationLUT::printSCPCreate(
  DcmDataset *rqDataset, 
  T_DIMSE_Message& rsp, 
  DcmDataset *& rspDataset, 
  OFBool matchRequired,
  OFBool supports12Bit)
{
  OFBool result = OFTrue;
  DcmStack stack;
  
  if ((rqDataset==NULL)||(EC_Normal != read(*rqDataset, OFFalse)))
  {
    if (verboseMode)
    {
      logstream->lockCerr() << "cannot create Presentation LUT: attribute list error." << endl;
      logstream->unlockCerr();
    }
    rsp.msg.NCreateRSP.DimseStatus = STATUS_N_NoSuchAttribute;
    result = OFFalse;
  }

  // read() has cleared sOPInstanceUID; assign UID now.
  if (EC_Normal != setSOPInstanceUID(rsp.msg.NCreateRSP.AffectedSOPInstanceUID))
  {
    rsp.msg.NCreateRSP.DimseStatus = STATUS_N_ProcessingFailure;
    result = OFFalse;
  }

  // browse through rqDataset and check for unsupported attributes
  if (result && rqDataset)
  {
    OFBool intoSub = OFTrue;
    stack.clear();
    while (EC_Normal == rqDataset->nextObject(stack, intoSub))
    {
      intoSub = OFFalse;
      const DcmTagKey& currentTag = (stack.top())->getTag();
      if (currentTag.getElement() == 0x0000) /* group length */ ;
      else if (currentTag == DCM_PresentationLUTShape) /* OK */ ;
      else if (currentTag == DCM_PresentationLUTSequence) /* OK */ ;
      else
      {
        if (verboseMode)
        {
          ostream &mycerr = logstream->lockCerr();
          mycerr << "cannot create Presentation LUT: unsupported attribute received:" << endl;
          (stack.top())->print(mycerr, DCMTypes::PF_shortenLongTagValues);
          logstream->unlockCerr();
        }
      	rsp.msg.NCreateRSP.DimseStatus = STATUS_N_NoSuchAttribute;
        result = OFFalse;
      }
    }
  }
  
  // if match between LUT and pixel data required, enforce rule
  if (result && matchRequired)
  {
    OFBool matches = OFTrue;
    switch (getAlignment())
    {
      case DVPSK_shape:
      case DVPSK_table8:
        break; // always OK
      case DVPSK_table12:
        // is OK if printer supports 12 bit
        matches = supports12Bit;
        break;
      case DVPSK_other: // never fits
        matches = OFFalse;
        break;  
    }
    if (!matches)
    {
      if (verboseMode)
      {
        logstream->lockCerr() << "cannot create Presentation LUT: Mismatch between LUT entries and image pixel depth." << endl;
        logstream->unlockCerr();
      }
      rsp.msg.NCreateRSP.DimseStatus = STATUS_N_NoSuchAttribute;
      result = OFFalse;
    }
  }

  // if n-create was successful, create response dataset
  if (result)
  {
    rspDataset = new DcmDataset;    
    if (rspDataset)
    {
      if (EC_Normal == write(*rspDataset, OFFalse))
      {
        rsp.msg.NCreateRSP.DataSetType = DIMSE_DATASET_PRESENT;
      } else {
      	delete rspDataset;
      	rspDataset = NULL;
        rsp.msg.NCreateRSP.DimseStatus = STATUS_N_ProcessingFailure;
        result = OFFalse;
      }     
    } else {
      rsp.msg.NCreateRSP.DimseStatus = STATUS_N_ProcessingFailure;
      result = OFFalse;
    }
  }
  return result;
}

void DVPSPresentationLUT::setLog(OFConsole *stream, OFBool verbMode, OFBool dbgMode)
{
  if (stream) logstream = stream; else logstream = &ofConsole;
  verboseMode = verbMode;
  debugMode = dbgMode;
}

/*
 *  $Log: dvpspl.cc,v $
 *  Revision 1.27  2005/12/08 15:46:38  meichel
 *  Changed include path schema for all DCMTK header files
 *
 *  Revision 1.26  2004/02/04 15:57:49  joergr
 *  Removed acknowledgements with e-mail addresses from CVS log.
 *
 *  Revision 1.25  2003/08/27 14:59:08  meichel
 *  Moved all methods of class DVPSPresentationLUT that depend on module dcmimgle
 *    into a separate implementation file
 *
 *  Revision 1.24  2003/03/12 17:34:22  meichel
 *  Updated DcmObject::print() flags
 *
 *  Revision 1.23  2001/11/28 13:56:58  joergr
 *  Check return value of DcmItem::insert() statements where appropriate to
 *  avoid memory leaks when insert procedure fails.
 *
 *  Revision 1.22  2001/09/26 15:36:29  meichel
 *  Adapted dcmpstat to class OFCondition
 *
 *  Revision 1.21  2001/06/01 15:50:34  meichel
 *  Updated copyright header
 *
 *  Revision 1.20  2001/05/25 10:07:57  meichel
 *  Corrected some DIMSE error status codes for Print SCP
 *
 *  Revision 1.19  2000/09/06 08:55:38  meichel
 *  Updated Print SCP to accept and silently ignore group length attributes.
 *
 *  Revision 1.18  2000/07/11 14:53:06  joergr
 *  Corrected rendering of presentation LUT shape LIN OD.
 *
 *  Revision 1.17  2000/07/07 14:15:14  joergr
 *  Added support for LIN OD presentation LUT shape.
 *
 *  Revision 1.16  2000/07/07 13:39:50  joergr
 *  Added support for LIN OD presentation LUT shape.
 *
 *  Revision 1.15  2000/06/09 10:15:36  joergr
 *  Added support for rendering inverse presentation LUT into print bitmaps.
 *
 *  Revision 1.14  2000/06/08 10:44:36  meichel
 *  Implemented Referenced Presentation LUT Sequence on Basic Film Session level.
 *    Empty film boxes (pages) are not written to file anymore.
 *
 *  Revision 1.13  2000/06/07 14:27:13  joergr
 *  Added support for rendering "hardcopy" and "softcopy" presentation LUTs.
 *
 *  Revision 1.12  2000/06/07 13:17:07  meichel
 *  now using DIMSE status constants and log facilities defined in dcmnet
 *
 *  Revision 1.11  2000/06/02 16:01:03  meichel
 *  Adapted all dcmpstat classes to use OFConsole for log and error output
 *
 *  Revision 1.10  2000/05/31 12:58:15  meichel
 *  Added initial Print SCP support
 *
 *  Revision 1.9  2000/03/08 16:29:07  meichel
 *  Updated copyright header.
 *
 *  Revision 1.8  2000/03/03 14:14:02  meichel
 *  Implemented library support for redirecting error messages into memory
 *    instead of printing them to stdout/stderr for GUI applications.
 *
 *  Revision 1.7  1999/11/24 15:15:05  joergr
 *  Replaced call of method invertTable() by mirrorTable() to invert a
 *  presentation LUT.
 *
 *  Revision 1.6  1999/10/20 10:55:19  joergr
 *  Enhanced method invertTable to distinguish between copy of LUT data and
 *  original (referenced) LUT data.
 *
 *  Revision 1.5  1999/10/07 17:22:00  meichel
 *  Reworked management of Presentation LUTs in order to create tighter
 *    coupling between Softcopy and Print.
 *
 *  Revision 1.4  1999/09/24 15:24:07  meichel
 *  Print spooler (dcmprtsv) now logs diagnostic messages in log files
 *    when operating in spool mode.
 *
 *  Revision 1.3  1999/09/24 13:22:07  joergr
 *  Corrected bug writing inverse Presentation LUT Shape.
 *
 *  Revision 1.2  1999/09/10 07:32:43  thiel
 *  Added Presentation LUT Shape LIN OD
 *
 *  Revision 1.1  1999/07/30 13:34:57  meichel
 *  Added new classes managing Stored Print objects
 *
 *
 */