1 /*************************************************************
2 Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved.
3 PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research
4 Group. If you use this software, you agree to the following: This
5 program package is purely experimental, and is licensed "as is".
6 Permission is granted to use, modify, and distribute this program
7 without charge for any purpose, provided this license/ disclaimer
8 notice appears in the copies.  No warranty or maintenance is given,
9 either expressed or implied.  In no event shall the author(s) be
10 liable to you or a third party for any special, incidental,
11 consequential, or other damages, arising out of the use or inability
12 to use the program for any purpose (or the loss of data), even if we
13 have been advised of such possibilities.  Any public reference or
14 advertisement of this source code should refer to it as the Portable
15 Video Research Group (PVRG) code, and not by any author(s) (or
16 Stanford University) name.
17 *************************************************************/
18 
19 /*
20 ************************************************************
21 marker.c
22 
23 This file contains the Marker library which uses the direct buffer
24 access routines bgetc...
25 
26 ************************************************************
27 */
28 
29 /*LABEL marker.c */
30 
31 /*Include files */
32 #include "globals.h"
33 #include "stream.h"
34 #include "marker.h"
35 #ifdef SYSV
36 #include <sys/fcntl.h>
37 #endif
38 #include <stdlib.h> /* exit */
39 
40 /*PUBLIC*/
41 extern void WriteSoi();
42 extern void WriteEoi();
43 extern void WriteJfif();
44 extern void WriteSof();
45 extern void WriteDri();
46 extern void WriteDqt();
47 extern void WriteSos();
48 extern void WriteDht();
49 extern void ReadSof();
50 extern void ReadDqt();
51 extern void ReadDht();
52 extern void ReadDri();
53 extern void ReadDnl();
54 extern int CheckMarker();
55 extern void CheckScan();
56 extern void ReadSos();
57 extern void MakeConsistentFrameSize();
58 /*PRIVATE*/
59 
60 /* External marker definition */
61 
62 extern FRAME *CFrame;
63 extern IMAGE *CImage;
64 extern SCAN *CScan;
65 extern int NumberMDU;
66 extern int Loud;
67 extern int izigzag_index[];
68 
69 #define Zigzag(i) izigzag_index[i]
70 
71 /*START*/
72 
73 /*BFUNC
74 
75 WriteSoi() puts an SOI marker onto the stream.
76 
77 EFUNC*/
78 
WriteSoi()79 void WriteSoi()
80 {
81   BEGIN("WriteSoi")
82 
83   swbytealign();
84   bputc(MARKER_MARKER);
85   bputc(MARKER_SOI);
86 }
87 
88 /*BFUNC
89 
90 WriteEoi() puts an EOI marker onto the stream.
91 
92 EFUNC*/
93 
WriteEoi()94 void WriteEoi()
95 {
96   BEGIN("WriteEoi")
97 
98   swbytealign();
99   bputc(MARKER_MARKER);
100   bputc(MARKER_EOI);
101 }
102 
103 /*BFUNC
104 
105 WriteJfif() puts an JFIF APP0 marker onto the stream.  This is a
106 generic 1x1 aspect ratio, no thumbnail specification.
107 
108 EFUNC*/
109 
WriteJfif()110 void WriteJfif()
111 {
112   BEGIN("WriteJfif")
113   int Start,End;
114 
115   swbytealign();
116   bputc(MARKER_MARKER);
117   bputc(MARKER_APP);
118   Start = swtell();              /* Find out the start of position. */
119   bputw(0);                      /* Put a 0 down onto the stream. */
120   bputc(0x4a); bputc(0x46); bputc(0x49); bputc(0x46); bputc(0x00);
121   bputc(0x01); bputc(0x02);   /*Version 1.02*/
122   bputc(0x00); /* No absolute DPI */
123   bputw(1);    /* Aspect ratio */
124   bputw(1);
125   bputc(0x00); /* No thumbnails */
126   bputc(0x00);
127 
128   End = swtell();                /* Find out end of the marker. */
129   swseek(Start);                 /* Rewind */
130   bputw((End-Start) >> 3);       /* Put marker there. */
131   if ((Start-End) & 0x7)         /* if not byte flush, then problems. */
132     {
133       WHEREAMI();
134       printf("Bad frame marker, not byte flush.\n");
135     }
136   swseek(End);
137 }
138 /*BFUNC
139 
140 WriteSof() puts an SOF marker onto the stream.
141 
142 EFUNC*/
143 
WriteSof()144 void WriteSof()
145 {
146   BEGIN("WriteSof")
147   int i,j,Start,End;
148 
149   swbytealign();
150   bputc(MARKER_MARKER);
151   bputc(MARKER_SOF|(CFrame->Type&0xf));
152   Start = swtell();              /* Find out the start of position. */
153   bputw(0);                      /* Put a 0 down onto the stream. */
154   bputc(CFrame->DataPrecision);
155   if (!CFrame->InsertDnl) {bputw(CFrame->GlobalHeight);}
156   else {bputw(0);}
157   bputw(CFrame->GlobalWidth);
158   bputc(CFrame->GlobalNumberComponents);
159   for(i=0;i<CFrame->GlobalNumberComponents;i++)
160     {
161       bputc(j=CFrame->cn[i]);               /* Store off in index */
162       bputn(CFrame->hf[j],CFrame->vf[j]);
163       bputc(CFrame->tq[j]);
164     }
165   End = swtell();                /* Find out end of the marker. */
166   swseek(Start);                 /* Rewind */
167   bputw((End-Start) >> 3);       /* Put marker there. */
168   if ((Start-End) & 0x7)         /* if not byte flush, then problems. */
169     {
170       WHEREAMI();
171       printf("Bad frame marker, not byte flush.\n");
172     }
173   swseek(End);
174 }
175 
176 /*BFUNC
177 
178 WriteDri() writes out a resync (or restart) interval out to the
179 stream. If unspecified, resync is not enabled.
180 
181 EFUNC*/
182 
WriteDri()183 void WriteDri()
184 {
185   BEGIN("WriteDri")
186 
187   swbytealign();
188   bputc(MARKER_MARKER);
189   bputc(MARKER_DRI);
190   bputw(4); /* Constant length of 4 */
191   bputw(CFrame->ResyncInterval);
192 }
193 
194 /*BFUNC
195 
196 WriteDnl() writes out a number of line marker out to the stream.  Note
197 that we must have defined number of lines before as 0.
198 
199 EFUNC*/
200 
201 
WriteDnl()202 void WriteDnl()
203 {
204   BEGIN("WriteDnl")
205 
206   swbytealign();
207   bputc(MARKER_MARKER);
208   bputc(MARKER_DNL);
209   bputw(4); /* Constant length of 4 */
210   bputw(CFrame->GlobalHeight);
211 }
212 
213 /*BFUNC
214 
215 WriteDqt() writes out the quantization matrices in the CImage
216 structure.
217 
218 EFUNC*/
219 
WriteDqt()220 void WriteDqt()
221 {
222   BEGIN("WriteDqt")
223   int i,j,bignum_p,Start,End,*qmatrix;
224 
225   if (!(CScan->NumberQTablesSend))
226     return;   /* No tables to transmit, then ignore. */
227   swbytealign();
228   bputc(MARKER_MARKER);
229   bputc(MARKER_DQT);
230   Start = swtell();
231   bputw(0);
232   for(i=0;i<CScan->NumberQTablesSend;i++)
233     {
234       qmatrix = CImage->QuantizationMatrices[CScan->sq[i]];
235       for(bignum_p=0,j=63;j>=0;j--)
236   {
237     if(qmatrix[j]>255)
238       {
239         bignum_p=0x10;
240         break;
241       }
242   }
243       bputc((bignum_p|CScan->sq[i])); /* Precision defined for big numbers */
244       if (bignum_p)
245   {
246     for(j=0;j<64;j++)
247       bputw(qmatrix[Zigzag(j)]);
248   }
249       else
250   {
251     for(j=0;j<64;j++)
252       bputc(qmatrix[Zigzag(j)]);
253   }
254     }
255   CScan->NumberQTablesSend=0; /* Clear out queue */
256   End = swtell();       /* Assume a marker code will follow.*/
257   swseek(Start);        /* bputc(END_QUANTIZATION_TABLE);*/
258   bputw((End-Start) >> 3);
259   if ((Start-End) & 0x7)
260     {
261       WHEREAMI();
262       printf("DQT marker not byte flush.\n");
263     }
264   swseek(End);
265 }
266 
267 /*BFUNC
268 
269 WriteSos() writes a start of scan marker.
270 
271 EFUNC*/
272 
WriteSos()273 void WriteSos()
274 {
275   BEGIN("WriteSos")
276   int i,Start,End;
277 
278   swbytealign();
279   bputc(MARKER_MARKER);
280   bputc(MARKER_SOS);
281   Start = swtell();
282   bputw(0);
283   bputc(CScan->NumberComponents);
284   for(i=0;i<CScan->NumberComponents;i++)
285     {
286       bputc(CScan->ci[i]);
287       bputn(CScan->td[i],CScan->ta[i]);
288     }
289   bputc(CScan->SSS);
290   bputc(CScan->SSE);
291   bputn(CScan->SAH,CScan->SAL);
292   End = swtell();
293   swseek(Start);
294   bputw((End-Start) >> 3);
295   if ((Start-End) & 0x7)
296     {
297       WHEREAMI();
298       printf("Bad scan marker not byte flush.\n");
299     }
300   swseek(End);
301 }
302 
303 /*BFUNC
304 
305 WriteDht() writes out the Huffman tables to send.
306 
307 EFUNC*/
308 
WriteDht()309 void WriteDht()
310 {
311   BEGIN("WriteDht")
312   int i,Start,End;
313 
314   if (!(CScan->NumberDCTablesSend) && !(CScan->NumberACTablesSend))
315     return;   /* No tables to transmit, then ignore. */
316   swbytealign();
317   bputc(MARKER_MARKER);
318   bputc(MARKER_DHT);
319   Start = swtell();
320   bputw(0);
321   for(i=0;i<CScan->NumberDCTablesSend;i++)
322     {
323       bputc(CScan->sd[i]);
324       UseDCHuffman(CScan->sd[i]);
325       WriteHuffman();
326     }
327   for(i=0;i<CScan->NumberACTablesSend;i++)
328     {
329       bputc(CScan->sa[i]|0x10);
330       UseACHuffman(CScan->sa[i]);
331       WriteHuffman();
332     }
333   CScan->NumberDCTablesSend=0; /* Clear out send queue */
334   CScan->NumberACTablesSend=0;
335   /*
336     We end on a new marker... so an end of code table is unnecessary.
337     bputc(END_CODE_TABLE);
338     */
339   End = swtell();
340   swseek(Start);
341   bputw((End-Start) >> 3);
342   if ((Start-End) & 0x7)
343     {
344       WHEREAMI();
345       printf("Bad scan marker not byte flush.\n");
346     }
347   swseek(End);
348 }
349 
350 
351 /*BFUNC
352 
353   ReadSof() reads a start of frame marker from the stream. We assume that
354   the first two bytes (marker prefix) have already been stripped.
355 
356   EFUNC*/
357 
ReadSof(Type)358 void ReadSof(Type)
359      int Type;
360 {
361   BEGIN("ReadSof")
362   int i,j,Length,Start,End,rb;
363 
364   Start = srtell();
365   Length = bgetw();
366   if (Loud > MUTE)
367     printf("Frame Length %d\n",Length);
368   CFrame->Type=Type;
369   CFrame->DataPrecision = bgetc();
370   CFrame->GlobalHeight = bgetw();
371   CFrame->GlobalWidth = bgetw();
372 
373   for(i=0;i<MAXIMUM_COMPONENTS;i++)
374     CFrame->hf[i]=CFrame->vf[i]=CFrame->tq[i]=0;
375   CFrame->GlobalNumberComponents = bgetc();
376   for(i=0;i<CFrame->GlobalNumberComponents;i++)
377     {
378       j = bgetc();
379       rb = bgetc();
380       CFrame->cn[i] = j;
381       CFrame->hf[j] = hinyb(rb);
382       CFrame->vf[j] = lonyb(rb);
383       CFrame->tq[j] = bgetc();
384     }
385   MakeConsistentFrameSize();
386   End = srtell();
387   if ((End-Start) != (Length<<3))
388     {
389       WHEREAMI();
390       printf("Bad read frame length.\n");
391     }
392   if (Loud > MUTE)
393     {
394       PrintImage();
395       PrintFrame();
396     }
397 }
398 
399 /*BFUNC
400 
401   ReadDqt() reads a quantization table marker from the stream.
402   The first two bytes have been stripped off.
403 
404   EFUNC*/
405 
ReadDqt()406 void ReadDqt()
407 {
408   BEGIN("ReadDqt")
409   int i,Length,Qget,Index,Precision,Start,End;
410 
411   Start = srtell();
412   Length = bgetw();
413   if (Loud > MUTE)
414     printf("Quantization Length %d\n",Length);
415   while((Qget=bgetc()) != END_QUANTIZATION_TABLE)
416     {
417       Index = Qget & 0xf;
418       Precision = (Qget >> 4)&0xf;
419       if (Precision > 1)
420   {
421     printf("Bad Precision: %d  in Quantization Download\n",
422      Precision);
423     printf("*** Dumping Image ***\n");
424     PrintImage();
425     printf("*** Dumping Frame ***\n");
426     PrintFrame();
427     exit(ERROR_MARKER);
428   }                             /* Load in q-matrices */
429       CImage->QuantizationMatrices[Index] = (int *) calloc(65,sizeof(int));
430       if (Precision)               /* If precision then word quantization*/
431   {
432     for(i=0;i<64;i++)
433       {
434         if (!(CImage->QuantizationMatrices[Index][Zigzag(i)]=bgetw()))
435     {
436       printf("marker.c:ReadDqt: Quantization value of zero.\n");
437       if (i)
438         {
439           printf("marker.c:ReadDqt: Changing to i-1.\n");
440           CImage->QuantizationMatrices[Index][Zigzag(i)]=
441       CImage->QuantizationMatrices[Index][Zigzag(i-1)];
442         }
443       else
444         {
445           printf("marker.c:ReadDqt: Changing to 16.\n");
446           CImage->QuantizationMatrices[Index][Zigzag(i)]=16;
447         }
448     }
449       }
450   }
451       else                       /* Otherwise byte quantization */
452   {
453     for(i=0;i<64;i++)
454       {
455         if (!(CImage->QuantizationMatrices[Index][Zigzag(i)]=bgetc()))
456     {
457       printf("marker.c:ReadDqt: Quantization value of zero.\n");
458       if (i)
459         {
460           printf("marker.c:ReadDqt: Changing to i-1.\n");
461           CImage->QuantizationMatrices[Index][Zigzag(i)]=
462       CImage->QuantizationMatrices[Index][Zigzag(i-1)];
463         }
464       else
465         {
466           printf("marker.c:ReadDqt: Changing to 16.\n");
467           CImage->QuantizationMatrices[Index][Zigzag(i)]=16;
468         }
469     }
470       }
471   }
472     }
473   bpushc(END_QUANTIZATION_TABLE);
474   End = srtell();
475   if ((End-Start) != (Length<<3))
476     {
477       WHEREAMI();
478       printf("Bad DQT read length.\n");
479     }
480   if (Loud > MUTE)
481     {
482       PrintImage();
483       PrintFrame();
484     }
485 }
486 
487 
488 /*BFUNC
489 
490   ReadDht() reads a Huffman marker from the stream. We assume that the
491   first two bytes have been stripped off.
492 
493   EFUNC*/
494 
ReadDht()495 void ReadDht()
496 {
497   BEGIN("ReadDht")
498   int Index,Where,Length,Start,End;
499 
500   Start = srtell();
501   Length = bgetw();
502   if (Loud > MUTE)
503     printf("Define Huffman length %d\n",Length);
504   while((Index = bgetc()) != END_CODE_TABLE)
505     {
506       Where = (Index >> 4) & 0x0f;       /* Find location to place it in */
507       Index = Index & 0x0f;
508       MakeXhuff();                       /* Make Huffman table */
509       MakeDhuff();
510       ReadHuffman();
511       if (Where)
512   {
513     SetACHuffman(Index);           /* Set current Huffman limit */
514     CImage->NumberACTables = MAX(CImage->NumberACTables,(Index+1));
515   }
516       else
517   {
518     SetDCHuffman(Index);
519     CImage->NumberDCTables = MAX(CImage->NumberDCTables,(Index+1));
520   }
521     }
522   bpushc(END_CODE_TABLE);
523   End = srtell();
524   if ((End-Start) != (Length<<3))
525     {
526       WHEREAMI();
527       printf("Bad DHT length.\n");
528     }
529   if (Loud > MUTE)
530     PrintImage();
531 }
532 
533 /*BFUNC
534 
535   ReadDri() reads a resync interval marker from the stream. We assume
536   the first two bytes are stripped off.
537 
538   EFUNC*/
539 
ReadDri()540 void ReadDri()
541 {
542   BEGIN("ReadDri")
543   int Length;
544 
545   if ((Length=bgetw())!=4)            /* Constant length of 4 */
546     {
547       WHEREAMI();
548       printf("Bad length %d, should be 4.\n",Length);
549     }
550   CFrame->ResyncInterval = bgetw();
551 }
552 
553 /*BFUNC
554 
555   ReadDnl() reads a number of lines marker from the stream. The first
556   two bytes should be stripped off.
557 
558   EFUNC*/
559 
ReadDnl()560 void ReadDnl()
561 {
562   BEGIN("ReadDnl")
563   int Length;
564 
565   if ((Length=bgetw())!=4)             /* Constant length of 4 */
566     printf("marker.c:ReadDnl: Bad length %d, should be 4.\n",Length);
567   CFrame->GlobalHeight = bgetw();
568   if (CScan->NumberComponents)
569     {
570       MakeConsistentFrameSize();
571       CheckScan();
572       ResizeIob();
573       if (CFrame->GlobalHeight)
574   {
575     InstallIob(0);
576     if (CFrame->Type==3)
577       NumberMDU = CScan->MDUWide*CScan->MDUHigh;
578     else
579       NumberMDU = CScan->MDUWide*CScan->MDUHigh;
580   }
581       else
582   NumberMDU = -1;
583     }
584 }
585 
586 /*BFUNC
587 
588 CheckMarker() checks to see if there is a marker in the stream ahead.
589 This function presumes that ungetc is not allowed to push more than
590 one byte back.
591 
592 EFUNC*/
593 
CheckMarker()594 int CheckMarker()
595 {
596   BEGIN("CheckMarker")
597   int Length;
598   int v1;
599 
600   Length = brtell();
601   v1=bgetw();
602 
603   if (v1>=0xffc0)
604     {
605       brseek(Length,0L);
606       return(v1&0xff);
607     }
608   brseek(Length,0L);
609   return(0);
610 }
611 
612 /*BFUNC
613 
614 ReadSos() reads in a start of scan from the stream. The first two
615 bytes should have been stripped off.
616 
617 EFUNC*/
618 
ReadSos()619 void ReadSos()
620 {
621   BEGIN("ReadSos")
622   int i,Length,Start,End,rb;
623 
624   Start = srtell();
625   Length = bgetw();
626   if (Loud > MUTE)
627     {
628       WHEREAMI();
629       printf("Scan length %d\n",Length);
630     }
631   CScan->NumberComponents = bgetc();
632   for(i=0;i<CScan->NumberComponents;i++)
633     {
634       CScan->ci[i] = bgetc();
635       rb = bgetc();
636       CScan->td[i] =  hinyb(rb);
637       CScan->ta[i] = lonyb(rb);
638     }
639   CScan->SSS = bgetc();
640   CScan->SSE = bgetc();
641   rb = bgetc();
642   CScan->SAH = hinyb(rb);
643   CScan->SAL = lonyb(rb);
644 
645   End = srtell();
646   if ((End-Start) != (Length<<3))
647     {
648       WHEREAMI();
649       printf("Bad scan length.\n");
650     }
651   if (Loud > MUTE)
652     PrintScan();
653   MakeConsistentFileNames();   /* A Scan marker always makes new files */
654   CheckValidity();
655   CheckBaseline();
656   CheckScan();
657   /* Create the io buffer structure */
658 
659   if (CFrame->Type==3)
660     {
661       MakeIob(IOB_LINE,O_RDWR | O_CREAT,
662         ((CFrame->DataPrecision>8)?2:1));
663       if (CFrame->GlobalHeight)
664   {
665     InstallIob(0);
666     NumberMDU = CScan->MDUWide*CScan->MDUHigh;
667   }
668       else NumberMDU = -1;
669     }
670   else
671     {
672       MakeIob(IOB_BLOCK,O_RDWR | O_CREAT | O_TRUNC,
673         ((CFrame->DataPrecision>8)?2:1));
674       if (CFrame->GlobalHeight)
675   {
676     InstallIob(0);
677     NumberMDU = CScan->MDUWide*CScan->MDUHigh;
678   }
679       else NumberMDU = -1;
680     }
681 
682   /* Sometimes rewinding is necessary */
683   /* for(i=0;i<CScan->NumberComponents;i++)
684     {
685       InstallIob(i);
686       RewindIob();
687     } */
688   ResetCodec();                /* Reset codec for information */
689 }
690 
691 /*BFUNC
692 
693 CheckScan() sets the MDU dimensions for the CScan structure.
694 
695 EFUNC*/
696 
CheckScan()697 void CheckScan()
698 {
699   int i;
700 
701   if (CScan->NumberComponents==1)
702     {
703       i = (((CFrame->GlobalWidth*CFrame->hf[CScan->ci[0]])-1)/CFrame->Maxh)+1;
704       if (CFrame->Type!=3)
705   i = ((i-1)/8)+1;
706       CScan->MDUWide = i;
707 
708       i = (((CFrame->GlobalHeight*CFrame->vf[CScan->ci[0]])-1)/CFrame->Maxv)+1;
709       if (CFrame->Type!=3)
710   i = ((i-1)/8)+1;
711       CScan->MDUHigh = i;
712     }
713   else
714     {
715       CScan->MDUWide=CFrame->MDUWide;
716       CScan->MDUHigh=CFrame->MDUHigh;
717     }
718 }
719 
720 /*BFUNC
721 
722 MakeConsistentFrameSize() makes a consistent frame size for all of the
723 horizontal and vertical frequencies read.
724 
725 EFUNC*/
726 
MakeConsistentFrameSize()727 void MakeConsistentFrameSize()
728 {
729   BEGIN("MakeConsistentFrameSize")
730   int i,Maxh,Maxv;
731   int TestWide, TestHigh;
732 
733   Maxv = Maxh = 1;
734   for(i=0;i<MAXIMUM_COMPONENTS;i++)
735     {
736       if (CFrame->vf[i] > Maxv)
737   Maxv = CFrame->vf[i];
738       if (CFrame->hf[i] > Maxh)
739   Maxh = CFrame->hf[i];
740     }
741 
742   for(i=0;i<MAXIMUM_COMPONENTS;i++)       /* Define estimated actual width */
743     {                                     /* ignoring replications */
744       if (CFrame->hf[i])
745   {
746     if (!CFrame->Width[i])
747       CFrame->Width[i] =
748         (((CFrame->GlobalWidth*CFrame->hf[i])-1)/Maxh)+1;
749     if (!CFrame->Height[i])
750       CFrame->Height[i] =
751         (((CFrame->GlobalHeight*CFrame->vf[i])-1)/Maxv)+1;
752   }
753     }
754 
755   CFrame->Maxv = Maxv;  CFrame->Maxh = Maxh;
756 
757   CFrame->MDUWide = (CFrame->GlobalWidth-1)/Maxh +1;
758   if (CFrame->GlobalHeight)
759     CFrame->MDUHigh = (CFrame->GlobalHeight-1)/Maxv +1;
760   else
761     CFrame->MDUHigh = 0;
762 
763   if (CFrame->Type!=3)
764     {
765       CFrame->MDUWide= (CFrame->MDUWide-1)/8 +1;
766       if (CFrame->MDUHigh)
767   CFrame->MDUHigh= (CFrame->MDUHigh-1)/8 +1;
768     }
769 
770   for(i=0;i<MAXIMUM_COMPONENTS;i++)
771     {
772       if (CFrame->hf[i])
773   {
774     TestWide = ((CFrame->Width[i]-1)/(CFrame->hf[i]))+1;
775     if (CFrame->Type!=3) TestWide= (TestWide-1)/8 +1;
776 
777     if (CFrame->MDUWide!=TestWide)
778       {
779         WHEREAMI();
780         printf("Inconsistent frame width.\n");
781         printf("Component[%dx%d]\n",
782          CFrame->Width[i],CFrame->Height[i]);
783         printf("MDU Wide: Image, Component %d!= %d.\n",
784          CFrame->MDUWide,TestWide);
785       }
786     if (CFrame->MDUHigh)
787       {
788         TestHigh = ((CFrame->Height[i]-1)/(CFrame->vf[i]))+1;
789         if (CFrame->Type!=3) TestHigh= (TestHigh-1)/8 +1;
790         if (CFrame->MDUHigh!=TestHigh)
791     {
792       WHEREAMI();
793       printf("Inconsistent frame height.\n");
794       printf("Component[%dx%d]\n",
795        CFrame->Width[i],CFrame->Height[i]);
796       printf("MDU High: Image, Component %d!= %d.\n",
797        CFrame->MDUHigh,TestHigh);
798     }
799       }
800   }
801     }
802 }
803 
804 
805 
806 /*END*/
807