home *** CD-ROM | disk | FTP | other *** search
/ Compressed Image File Formats / CompressedImageFileFormatsJohnMiano.iso / pc / Library / source / jpdedu.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-12-17  |  16.4 KB  |  576 lines

  1. //
  2. // Copyright (c) 1997,1998 Colosseum Builders, Inc.
  3. // All rights reserved.
  4. //
  5. // Colosseum Builders, Inc. makes no warranty, expressed or implied
  6. // with regards to this software. It is provided as is.
  7. //
  8. // See the README.TXT file that came with this software for restrictions
  9. // on the use and redistribution of this file or send E-mail to
  10. // info@colosseumbuilders.com
  11. //
  12.  
  13. //
  14. // JPEG Decoder Data Unit class implementation
  15. //
  16. // Author:  John M. Miano miano@colosseumbuilders.com
  17. //
  18. // This class represents an 8x8 sample block for one
  19. // component of the JPEG image. Its main function is to perform the
  20. // Inverse Discrete Cosine Transform.
  21. //
  22. // We have two IDCT implementation defined here. One uses floating point
  23. // and the other uses scaled integers. The integer implementation is much
  24. // faster but it is slightly less precise than the floating point.
  25. //
  26. // (Right now the choice of the two is made at compile time. In the
  27. //  future there may be a run-time switch).
  28. //
  29. // The algorithm is a matrix factorization that makes use extensive of the
  30. // cosine product formula. The first phase of the IDCT is merged with
  31. // quantization.
  32. //
  33.  
  34. #include <math.h>
  35.  
  36. #include "jpdedu.h"
  37.  
  38. using namespace std ;
  39.  
  40. #if defined (_MSC_VER) // For whatever reason MSVC++ does not define PI.
  41. const double M_PI = acos (-1.0) ;
  42. #endif 
  43.  
  44. JpegDecoderDataUnit::IDctFunction JpegDecoderDataUnit::idct_function
  45.                                   = &JpegDecoderDataUnit::IntegerInverseDCT ;
  46. // Could also be set to &JpegDecoderDataUnit::FloatInverseDCT ;
  47.  
  48. const int IntegerScale = 6 ;
  49.  
  50. const long IC4 = (long)((1<<IntegerScale) * cos (M_PI * 4.0/16.0)) ;
  51. const long ISEC2 = (long)((1<<(IntegerScale - 1)) / cos (M_PI * 2.0 / 16.0)) ;
  52. const long ISEC6 = (long)((1<<(IntegerScale - 1)) / cos (M_PI * 6.0 / 16.0)) ;
  53.  
  54. const double FC4 = cos (M_PI * 4.0 / 16.0) ;
  55. const double FSEC2 = 0.5 / cos (M_PI * 2.0 / 16.0) ;
  56. const double FSEC6 = 0.5 / cos (M_PI * 6.0 / 16.0) ;
  57.  
  58. //
  59. //  Description:
  60. //
  61. //    The IDCT process can produce rounding errors that result in sample
  62. //    values being outside the legal range.  This function clamps
  63. //    sample value into the legal range.
  64. //
  65. //    Unclamped values give strange results when converted to bytes.
  66. //     -1 (0xFFFFFFFF) would be converted to 255 (0xFF) instead of 0 and
  67. //    256 (0x00000100) gets converted to 0.
  68. //
  69. //  Parameters:
  70. //    value: The value to clamp
  71. //
  72. //  Return Value:
  73. //    "value" clamped to MinSampleValue..MaxSampleValue
  74. //
  75.  
  76. static inline JPEGSAMPLE SampleRange (long value)
  77. {
  78.   if (value < JpegMinSampleValue)
  79.     return JpegMinSampleValue ;
  80.   else if (value > JpegMaxSampleValue)
  81.     return JpegMaxSampleValue ;
  82.   else
  83.     return (JPEGSAMPLE) value ;
  84. }
  85.  
  86. //
  87. //  Description:
  88. //
  89. //    This function descales a scaled integer value.
  90. //
  91. //    This implementation is simplay a shift operation. We
  92. //    use an inline function to give one place to change in case
  93. //    we want to switch to a rounded scale.
  94. //
  95. //  Parameters:
  96. //    value: The value to descale
  97. //    amount:  The amount to descale
  98. //
  99. //  Return Value:
  100. //    The descaled value.
  101. //
  102. static inline long Descale (long value, int amount)
  103. {
  104.   // A more precise value would be
  105.   // result = (value + (1 << (amount - 1))) >> amount ;
  106.   return value >> amount ;
  107. }
  108.  
  109. //
  110. //  Description:
  111. //
  112. //    Class Copy Constructor
  113. //
  114. JpegDecoderDataUnit::JpegDecoderDataUnit(const JpegDecoderDataUnit &du)
  115. {
  116.   memcpy (values, du.values, sizeof (values)) ;
  117.   return ;
  118. }
  119.  
  120. //
  121. //  Description:
  122. //
  123. //    Class assignment operator
  124. //
  125. JpegDecoderDataUnit &JpegDecoderDataUnit::operator=(const JpegDecoderDataUnit&du)
  126. {
  127.   memcpy (values, du.values, sizeof (values)) ;
  128.   return *this ;
  129. }
  130.  
  131. //
  132. //  Description:
  133. //
  134. //    This is a floating point implementation of the Inverse
  135. //    Discrete Cosine Transform (IDCT).
  136. //
  137. //    This implementation uses a factorization of the DCT matrix.
  138. //    The first steps in this factorization is a matrix multiplication
  139. //    is the multiplication of each row/column by a scale. This
  140. //    scalor multipliation has been combined with quantization
  141. //    to eliminate 128 multiplication steps.
  142. //
  143. //    We use a lot of temporaries here in order to clearly
  144. //    show the matrix multiplication steps.  Hopefully
  145. //    your compiler will optimize out the unnecessary
  146. //    intermediate variables.
  147. //
  148. //    If your compiler does not aggressively optimize. It is possible
  149. //    to reorder the operations to reduce the number of temporaries
  150. //    required.
  151. //
  152. //  Parameters:
  153. //    data: The 8x8 matrix to perform the IDCT on.
  154. //    qt: The prescaled quantization table.
  155. //
  156. JpegDecoderDataUnit &JpegDecoderDataUnit::FloatInverseDCT (
  157.                             const JpegDecoderCoefficientBlock data,
  158.                             const JpegDecoderQuantizationTable &qt)
  159. {
  160.   double tmp [JpegSampleWidth][JpegSampleWidth] ;
  161.   unsigned int ii ;
  162.   for (ii = 0 ; ii < JpegSampleWidth ; ++ ii)
  163.   {
  164.     double a0 = data [ii][0] * qt.float_scaling [ii][0] ;
  165.     double a1 = data [ii][4] * qt.float_scaling [ii][4] ;
  166.     double a2 = data [ii][2] * qt.float_scaling [ii][2] ;
  167.     double a3 = data [ii][6] * qt.float_scaling [ii][6] ;
  168.     double a4 = data [ii][1] * qt.float_scaling [ii][1] ;
  169.     double a5 = data [ii][5] * qt.float_scaling [ii][5] ;
  170.     double a6 = data [ii][3] * qt.float_scaling [ii][3] ;
  171.     double a7 = data [ii][7] * qt.float_scaling [ii][7] ;
  172.  
  173.     double b0 = a0 ;
  174.     double b1 = a1 ;
  175.     double b2 = a2 - a3 ;
  176.     double b3 = a2 + a3 ;
  177.     double b4 = a4 - a7 ;
  178.     double b5 = a5 + a6;
  179.     double b6 = a5 - a6 ;
  180.     double b7 = a4 + a7 ;
  181.  
  182.     double c0 = b0 ;
  183.     double c1 = b1 ;
  184.     double c2 = b2 ;
  185.     double c3 = b3 ;
  186.     double c4 = FSEC2 * b4 ;
  187.     double c5 = b7 - b5 ;
  188.     double c6 = FSEC6 * b6 ;
  189.     double c7 = b5 + b7 ;
  190.  
  191.     double d0 = c0 ;
  192.     double d1 = c1 ;
  193.     double d2 = c2 ;
  194.     double d3 = c3 ;
  195.     double d4 = c4 + c6 ;
  196.     double d5 = c5 ;
  197.     double d6 = c4 - c6 ;
  198.     double d7 = c7 ;
  199.  
  200.     double e0 = d0 + d1 ;
  201.     double e1 = d0 - d1 ;
  202.     double e2 = d2 * FC4 ;
  203.     double e3 = d3 ;
  204.     double e4 = d4 * FC4 ;
  205.     double e5 = d5 * FC4 ;
  206.     double e6 = d6 ;
  207.     double e7 = d7 ;
  208.  
  209.     double f0 = e0 ;
  210.     double f1 = e1 ;
  211.     double f2 = e2 ;
  212.     double f3 = e3 ;
  213.     double f4 = e4 ;
  214.     double f5 = e5 ;
  215.     double f6 = e4 + e6 ;
  216.     double f7 = e7 ;
  217.  
  218.     double g0 = f0 ;
  219.     double g1 = f1 ;
  220.     double g2 = f2 ;
  221.     double g3 = f2 + f3 ;
  222.     double g4 = f4 ;
  223.     double g5 = f4 + f5 ;
  224.     double g6 = f5 + f6 ;
  225.     double g7 = f6 + f7 ;
  226.  
  227.     double h0 = g0 + g3 ;
  228.     double h1 = g1 + g2 ;
  229.     double h2 = g1 - g2 ;
  230.     double h3 = g0 - g3 ;
  231.     double h4 = g4 ;
  232.     double h5 = g5 ;
  233.     double h6 = g6 ;
  234.     double h7 = g7 ;
  235.  
  236.     tmp [ii][0] = h0 + h7 ;
  237.     tmp [ii][1] = h1 + h6 ;
  238.     tmp [ii][2] = h2 + h5 ;
  239.     tmp [ii][3] = h3 + h4 ;
  240.     tmp [ii][4] = h3 - h4 ;
  241.     tmp [ii][5] = h2 - h5 ;
  242.     tmp [ii][6] = h1 - h6 ;
  243.     tmp [ii][7] = h0 - h7 ;
  244.   }
  245.  
  246.   for (ii = 0 ; ii < JpegSampleWidth ; ++ ii)
  247.   {
  248.     double a0 = tmp [0][ii] ;
  249.     double a1 = tmp [4][ii] ;
  250.     double a2 = tmp [2][ii] ;
  251.     double a3 = tmp [6][ii] ;
  252.     double a4 = tmp [1][ii] ;
  253.     double a5 = tmp [5][ii] ;
  254.     double a6 = tmp [3][ii] ;
  255.     double a7 = tmp [7][ii] ;
  256.  
  257.     double b0 = a0 ;
  258.     double b1 = a1 ;
  259.     double b2 = a2 - a3 ;
  260.     double b3 = a2 + a3 ;
  261.     double b4 = a4 - a7 ;
  262.     double b5 = a5 + a6;
  263.     double b6 = a5 - a6 ;
  264.     double b7 = a4 + a7 ;
  265.  
  266.     double c0 = b0 ;
  267.     double c1 = b1 ;
  268.     double c2 = b2 ;
  269.     double c3 = b3 ;
  270.     double c4 = FSEC2 * b4 ;
  271.     double c5 = b7 - b5 ;
  272.     double c6 = FSEC6 * b6 ;
  273.     double c7 = b5 + b7 ;
  274.  
  275.     double d0 = c0 ;
  276.     double d1 = c1 ;
  277.     double d2 = c2 ;
  278.     double d3 = c3 ;
  279.     double d4 = c4 + c6 ;
  280.     double d5 = c5 ;
  281.     double d6 = c4 - c6 ;
  282.     double d7 = c7 ;
  283.  
  284.     double e0 = d0 + d1 ;
  285.     double e1 = d0 - d1 ;
  286.     double e2 = d2 * FC4 ;
  287.     double e3 = d3 ;
  288.     double e4 = d4 * FC4 ;
  289.     double e5 = d5 * FC4 ;
  290.     double e6 = d6 ;
  291.     double e7 = d7 ;
  292.  
  293.     double f0 = e0 ;
  294.     double f1 = e1 ;
  295.     double f2 = e2 ;
  296.     double f3 = e3 ;
  297.     double f4 = e4 ;
  298.     double f5 = e5 ;
  299.     double f6 = e4 + e6 ;
  300.     double f7 = e7 ;
  301.  
  302.     double g0 = f0 ;
  303.     double g1 = f1 ;
  304.     double g2 = f2 ;
  305.     double g3 = f2 + f3 ;
  306.     double g4 = f4 ;
  307.     double g5 = f4 + f5 ;
  308.     double g6 = f5 + f6 ;
  309.     double g7 = f6 + f7 ;
  310.  
  311.     double h0 = g0 + g3 ;
  312.     double h1 = g1 + g2 ;
  313.     double h2 = g1 - g2 ;
  314.     double h3 = g0 - g3 ;
  315.     double h4 = g4 ;
  316.     double h5 = g5 ;
  317.     double h6 = g6 ;
  318.     double h7 = g7 ;
  319.  
  320.     static const double rounding = JpegMidpointSampleValue + 0.5 ;
  321.     values [0][ii] = SampleRange ((long)((h0 + h7) + rounding)) ;
  322.     values [1][ii] = SampleRange ((long)((h1 + h6) + rounding)) ;
  323.     values [2][ii] = SampleRange ((long)((h2 + h5) + rounding)) ;
  324.     values [3][ii] = SampleRange ((long)((h3 + h4) + rounding)) ;
  325.     values [4][ii] = SampleRange ((long)((h3 - h4) + rounding)) ;
  326.     values [5][ii] = SampleRange ((long)((h2 - h5) + rounding)) ;
  327.     values [6][ii] = SampleRange ((long)((h1 - h6) + rounding)) ;
  328.     values [7][ii] = SampleRange ((long)((h0 - h7) + rounding)) ;
  329.   }
  330.   return *this ;
  331. }
  332. //
  333. //  Description:
  334. //
  335. //    This is a scaled integer implementation of the Inverse
  336. //    Discrete Cosine Transform (IDCT).
  337. //
  338. //    This implementation uses a factorization of the DCT matrix.
  339. //    The first steps in this factorization is a matrix multiplication
  340. //    is the multiplication of each row/column by a scale. This
  341. //    scalor multipliation has been combined with quantization
  342. //    to eliminate 128 multiplication steps.
  343. //
  344. //    We use a lot of temporaries here in order to clearly
  345. //    show the matrix multiplication steps.  Hopefully
  346. //    your compiler will optimize out the unnecessary
  347. //    intermediate variables.
  348. //
  349. //    If your compiler does not aggressively optimize. It is possible
  350. //    to reorder the operations to reduce the number of temporaries
  351. //    required.
  352. //
  353. //  Parameters:
  354. //    data: The 8x8 matrix to perform the IDCT on.
  355. //    qt: The prescaled quantization table.
  356. //
  357. JpegDecoderDataUnit &JpegDecoderDataUnit::IntegerInverseDCT (
  358.                           const JpegDecoderCoefficientBlock data,
  359.                           const JpegDecoderQuantizationTable  &qt)
  360. {
  361.   unsigned int ii ; 
  362.   long tmp [JpegSampleWidth][JpegSampleWidth] ;
  363.  
  364.   for (ii = 0 ; ii < JpegSampleWidth ; ++ ii)
  365.   {
  366.     // This optimization does not seem to be worth the trouble in the
  367.     // second loop.
  368.     if ((data [ii][1] | data [ii][2] | data [ii][3] | data [ii][4] |
  369.         data [ii][5] | data [ii][6] | data [ii][7]) == 0)
  370.     {
  371.       tmp [ii][0] = data [ii][0] * qt.integer_scaling [ii][0] ;
  372.       tmp [ii][1] = tmp [ii][0] ;
  373.       tmp [ii][2] = tmp [ii][0] ;
  374.       tmp [ii][3] = tmp [ii][0] ;
  375.       tmp [ii][4] = tmp [ii][0] ;
  376.       tmp [ii][5] = tmp [ii][0] ;
  377.       tmp [ii][6] = tmp [ii][0] ;
  378.       tmp [ii][7] = tmp [ii][0] ;
  379.     }
  380.     else
  381.     {
  382.       long a0 = data [ii][0] * qt.integer_scaling [ii][0] ;
  383.       long a1 = data [ii][4] * qt.integer_scaling [ii][4] ;
  384.       long a2 = data [ii][2] * qt.integer_scaling [ii][2] ;
  385.       long a3 = data [ii][6] * qt.integer_scaling [ii][6] ;
  386.       long a4 = data [ii][1] * qt.integer_scaling [ii][1] ;
  387.       long a5 = data [ii][5] * qt.integer_scaling [ii][5] ;
  388.       long a6 = data [ii][3] * qt.integer_scaling [ii][3] ;
  389.       long a7 = data [ii][7] * qt.integer_scaling [ii][7] ;
  390.  
  391.       long b0 = a0 ;
  392.       long b1 = a1 ;
  393.       long b2 = a2 - a3 ;
  394.       long b3 = a2 + a3 ;
  395.       long b4 = a4 - a7 ;
  396.       long b5 = a5 + a6;
  397.       long b6 = a5 - a6 ;
  398.       long b7 = a4 + a7 ;
  399.  
  400.       long c0 = b0 ;
  401.       long c1 = b1 ;
  402.       long c2 = b2 ;
  403.       long c3 = b3 ;
  404.       long c4 = Descale (ISEC2 * b4, IntegerScale) ;
  405.       long c5 = b7 - b5 ;
  406.       long c6 = Descale (ISEC6 * b6, IntegerScale) ;
  407.       long c7 = b5 + b7 ;
  408.  
  409.       long d0 = c0 ;
  410.       long d1 = c1 ;
  411.       long d2 = c2 ;
  412.       long d3 = c3 ;
  413.       long d4 = c4 + c6 ;
  414.       long d5 = c5 ;
  415.       long d6 = c4 - c6 ;
  416.       long d7 = c7 ;
  417.  
  418.       long e0 = d0 + d1 ;
  419.       long e1 = d0 - d1 ;
  420.       long e2 = Descale (d2 * IC4, IntegerScale) ;
  421.       long e3 = d3 ;
  422.       long e4 = Descale (d4 * IC4, IntegerScale) ;
  423.       long e5 = Descale (d5 * IC4, IntegerScale) ;
  424.       long e6 = d6 ;
  425.       long e7 = d7 ;
  426.  
  427.       long f0 = e0 ;
  428.       long f1 = e1 ;
  429.       long f2 = e2 ;
  430.       long f3 = e3 ;
  431.       long f4 = e4 ;
  432.       long f5 = e5 ;
  433.       long f6 = e4 + e6 ;
  434.       long f7 = e7 ;
  435.  
  436.       long g0 = f0 ;
  437.       long g1 = f1 ;
  438.       long g2 = f2 ;
  439.       long g3 = f2 + f3 ;
  440.       long g4 = f4 ;
  441.       long g5 = f4 + f5 ;
  442.       long g6 = f5 + f6 ;
  443.       long g7 = f6 + f7 ;
  444.  
  445.       long h0 = g0 + g3 ;
  446.       long h1 = g1 + g2 ;
  447.       long h2 = g1 - g2 ;
  448.       long h3 = g0 - g3 ;
  449.       long h4 = g4 ;
  450.       long h5 = g5 ;
  451.       long h6 = g6 ;
  452.       long h7 = g7 ;
  453.  
  454.       tmp [ii][0] = h0 + h7 ;
  455.       tmp [ii][1] = h1 + h6 ;
  456.       tmp [ii][2] = h2 + h5 ;
  457.       tmp [ii][3] = h3 + h4 ;
  458.       tmp [ii][4] = h3 - h4 ;
  459.       tmp [ii][5] = h2 - h5 ;
  460.       tmp [ii][6] = h1 - h6 ;
  461.       tmp [ii][7] = h0 - h7 ;
  462.     }
  463.   }
  464.  
  465.   for (ii = 0 ; ii < JpegSampleWidth ; ++ ii)
  466.   {
  467.     long a0 = tmp [0][ii] ;
  468.     long a1 = tmp [4][ii] ;
  469.     long a2 = tmp [2][ii] ;
  470.     long a3 = tmp [6][ii] ;
  471.     long a4 = tmp [1][ii] ;
  472.     long a5 = tmp [5][ii] ;
  473.     long a6 = tmp [3][ii] ;
  474.     long a7 = tmp [7][ii] ;
  475.  
  476.     long b0 = a0 ;
  477.     long b1 = a1 ;
  478.     long b2 = a2 - a3 ;
  479.     long b3 = a2 + a3 ;
  480.     long b4 = a4 - a7 ;
  481.     long b5 = a5 + a6;
  482.     long b6 = a5 - a6 ;
  483.     long b7 = a4 + a7 ;
  484.  
  485.     long c0 = b0 ;
  486.     long c1 = b1 ;
  487.     long c2 = b2 ;
  488.     long c3 = b3 ;
  489.     long c4 = Descale (ISEC2 * b4, IntegerScale) ;
  490.     long c5 = b7 - b5 ;
  491.     long c6 = Descale (ISEC6 * b6, IntegerScale) ;
  492.     long c7 = b5 + b7 ;
  493.  
  494.     long d0 = c0 ;
  495.     long d1 = c1 ;
  496.     long d2 = c2 ;
  497.     long d3 = c3 ;
  498.     long d4 = c4 + c6 ;
  499.     long d5 = c5 ;
  500.     long d6 = c4 - c6 ;
  501.     long d7 = c7 ;
  502.  
  503.     long e0 = d0 + d1 ;
  504.     long e1 = d0 - d1 ;
  505.     long e2 = Descale (d2 * IC4, IntegerScale) ;
  506.     long e3 = d3 ;
  507.     long e4 = Descale (d4 * IC4, IntegerScale) ;
  508.     long e5 = Descale (d5 * IC4, IntegerScale) ;
  509.     long e6 = d6 ;
  510.     long e7 = d7 ;
  511.  
  512.     long f0 = e0 ;
  513.     long f1 = e1 ;
  514.     long f2 = e2 ;
  515.     long f3 = e3 ;
  516.     long f4 = e4 ;
  517.     long f5 = e5 ;
  518.     long f6 = e4 + e6 ;
  519.     long f7 = e7 ;
  520.  
  521.     const long rounding = (JpegMaxSampleValue + 2) << (JpegDecoderQuantizationTable::QuantizationIntegerScale-1) ;
  522.     long g0 = f0 + rounding ;
  523.     long g1 = f1 + rounding ;
  524.     long g2 = f2 ;
  525.     long g3 = f2 + f3 ;
  526.     long g4 = f4 ;
  527.     long g5 = f4 + f5 ;
  528.     long g6 = f5 + f6 ;
  529.     long g7 = f6 + f7 ;
  530.  
  531.     long h0 = g0 + g3 ;
  532.     long h1 = g1 + g2 ;
  533.     long h2 = g1 - g2 ;
  534.     long h3 = g0 - g3 ;
  535.     long h4 = g4 ;
  536.     long h5 = g5 ;
  537.     long h6 = g6 ;
  538.     long h7 = g7 ;
  539.  
  540.     values [0][ii] = SampleRange (Descale (h0 + h7, JpegDecoderQuantizationTable::QuantizationIntegerScale)) ;
  541.     values [1][ii] = SampleRange (Descale (h1 + h6, JpegDecoderQuantizationTable::QuantizationIntegerScale)) ;
  542.     values [2][ii] = SampleRange (Descale (h2 + h5, JpegDecoderQuantizationTable::QuantizationIntegerScale)) ;
  543.     values [3][ii] = SampleRange (Descale (h3 + h4, JpegDecoderQuantizationTable::QuantizationIntegerScale)) ;
  544.     values [4][ii] = SampleRange (Descale (h3 - h4, JpegDecoderQuantizationTable::QuantizationIntegerScale)) ;
  545.     values [5][ii] = SampleRange (Descale (h2 - h5, JpegDecoderQuantizationTable::QuantizationIntegerScale)) ;
  546.     values [6][ii] = SampleRange (Descale (h1 - h6, JpegDecoderQuantizationTable::QuantizationIntegerScale)) ;
  547.     values [7][ii] = SampleRange (Descale (h0 - h7, JpegDecoderQuantizationTable::QuantizationIntegerScale)) ;
  548.   }
  549.   return *this ;
  550. }
  551.  
  552. //
  553. //  Description:
  554. //
  555. //    This function writes the contents of the data unit to a stream.
  556. //    It is only for debugging.
  557. //
  558. //  Parameters:
  559. //    strm:  The output stream
  560. //
  561. void JpegDecoderDataUnit::Print (std::ostream &strm) const
  562. {
  563.   for (int ii = 0 ; ii < JpegSampleWidth ; ++ ii)
  564.   {
  565.     for (int jj = 0 ; jj < JpegSampleWidth ; ++ jj)
  566.     {
  567.       strm << (int) values [ii][jj] << " " ;
  568.     }
  569.     strm << endl ;
  570.   }
  571.   return ;
  572. }
  573.  
  574.  
  575.  
  576.