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