2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
23 #include "VobSubImage.h"
25 CVobSubImage::CVobSubImage()
30 rect
= CRect(0,0,0,0);
31 lpPixels
= lpTemp1
= lpTemp2
= NULL
;
35 CVobSubImage::~CVobSubImage()
40 bool CVobSubImage::Alloc(int w
, int h
)
42 // if there is nothing to crop TrimSubImage might even add a 1 pixel
43 // wide border around the text, that's why we need a bit more memory
46 if(lpTemp1
== NULL
|| w
*h
> org
.cx
*org
.cy
|| (w
+2)*(h
+2) > (org
.cx
+2)*(org
.cy
+2))
50 lpTemp1
= new RGBQUAD
[w
*h
];
51 if(!lpTemp1
) return(false);
53 lpTemp2
= new RGBQUAD
[(w
+2)*(h
+2)];
54 if(!lpTemp2
) {delete [] lpTemp1
; lpTemp1
= NULL
; return(false);}
65 void CVobSubImage::Free()
67 if(lpTemp1
) delete [] lpTemp1
;
70 if(lpTemp2
) delete [] lpTemp2
;
76 bool CVobSubImage::Decode(BYTE
* lpData
, int packetsize
, int datasize
,
79 RGBQUAD
* orgpal
/*[16]*/, RGBQUAD
* cuspal
/*[4]*/,
82 GetPacketInfo(lpData
, packetsize
, datasize
);
84 if(!Alloc(rect
.Width(), rect
.Height())) return(false);
91 this->fCustomPal
= fCustomPal
;
92 this->orgpal
= orgpal
;
94 this->cuspal
= cuspal
;
96 CPoint
p(rect
.left
, rect
.top
);
98 int end0
= nOffset
[1];
101 while((nPlane
== 0 && nOffset
[0] < end0
) || (nPlane
== 1 && nOffset
[1] < end1
))
105 if((code
= GetNibble(lpData
)) >= 0x4
106 || (code
= (code
<< 4) | GetNibble(lpData
)) >= 0x10
107 || (code
= (code
<< 4) | GetNibble(lpData
)) >= 0x40
108 || (code
= (code
<< 4) | GetNibble(lpData
)) >= 0x100)
110 DrawPixels(p
, code
>> 2, code
& 3);
111 if((p
.x
+= code
>> 2) < rect
.right
) continue;
114 DrawPixels(p
, rect
.right
- p
.x
, code
& 3);
116 if(!fAligned
) GetNibble(lpData
); // align to byte
123 rect
.bottom
= min(p
.y
, rect
.bottom
);
125 if(fTrim
) TrimSubImage();
130 void CVobSubImage::GetPacketInfo(BYTE
* lpData
, int packetsize
, int datasize
)
134 int i
, nextctrlblk
= datasize
;
135 WORD pal
= 0, tr
= 0;
141 int t
= (lpData
[i
] << 8) | lpData
[i
+1]; i
+= 2;
142 nextctrlblk
= (lpData
[i
] << 8) | lpData
[i
+1]; i
+= 2;
144 if(nextctrlblk
> packetsize
|| nextctrlblk
< datasize
)
158 case 0x00: len
= 0; break;
159 case 0x01: len
= 0; break;
160 case 0x02: len
= 0; break;
161 case 0x03: len
= 2; break;
162 case 0x04: len
= 2; break;
163 case 0x05: len
= 6; break;
164 case 0x06: len
= 4; break;
165 default: len
= 0; break;
168 if(i
+len
>= packetsize
)
170 TRACE(_T("Warning: Wrong subpicture parameter block ending\n"));
176 case 0x00: // forced start displaying
179 case 0x01: // start displaying
182 case 0x02: // stop displaying
183 delay
= 1024 * t
/ 90;
186 pal
= (lpData
[i
] << 8) | lpData
[i
+1]; i
+= 2;
189 tr
= (lpData
[i
] << 8) | lpData
[i
+1]; i
+= 2;
193 rect
= CRect((lpData
[i
] << 4) + (lpData
[i
+1] >> 4),
194 (lpData
[i
+3] << 4) + (lpData
[i
+4] >> 4),
195 ((lpData
[i
+1] & 0x0f) << 8) + lpData
[i
+2] + 1,
196 ((lpData
[i
+4] & 0x0f) << 8) + lpData
[i
+5] + 1);
200 nOffset
[0] = (lpData
[i
] << 8) + lpData
[i
+1]; i
+= 2;
201 nOffset
[1] = (lpData
[i
] << 8) + lpData
[i
+1]; i
+= 2;
203 case 0xff: // end of ctrlblk
206 default: // skip this ctrlblk
212 while(i
<= nextctrlblk
&& i
< packetsize
);
214 for(i
= 0; i
< 4; i
++)
216 this->pal
[i
].pal
= (pal
>> (i
<< 2)) & 0xf;
217 this->pal
[i
].tr
= (tr
>> (i
<< 2)) & 0xf;
221 BYTE
CVobSubImage::GetNibble(BYTE
* lpData
)
223 WORD
& off
= nOffset
[nPlane
];
224 BYTE ret
= (lpData
[off
] >> (fAligned
<< 2)) & 0x0f;
225 fAligned
= !fAligned
;
230 void CVobSubImage::DrawPixels(CPoint p
, int length
, int colorid
)
233 || p
.x
+ length
< rect
.left
236 || p
.y
>= rect
.bottom
)
241 if(p
.x
< rect
.left
) p
.x
= rect
.left
;
242 if(p
.x
+ length
>= rect
.right
) length
= rect
.right
- p
.x
;
244 RGBQUAD
* ptr
= &lpPixels
[rect
.Width() * (p
.y
- rect
.top
) + (p
.x
- rect
.left
)];
250 c
= orgpal
[pal
[colorid
].pal
];
251 c
.rgbReserved
= (pal
[colorid
].tr
<<4)|pal
[colorid
].tr
;
258 while(length
-- > 0) *ptr
++ = c
;
261 void CVobSubImage::TrimSubImage()
264 r
.left
= rect
.Width();
265 r
.top
= rect
.Height();
269 RGBQUAD
* ptr
= lpTemp1
;
271 for(int j
= 0, y
= rect
.Height(); j
< y
; j
++)
273 for(int i
= 0, x
= rect
.Width(); i
< x
; i
++, ptr
++)
277 if(r
.top
> j
) r
.top
= j
;
278 if(r
.bottom
< j
) r
.bottom
= j
;
279 if(r
.left
> i
) r
.left
= i
;
280 if(r
.right
< i
) r
.right
= i
;
285 if(r
.left
> r
.right
|| r
.top
> r
.bottom
) return;
287 r
+= CRect(0, 0, 1, 1);
289 r
&= CRect(CPoint(0,0), rect
.Size());
291 int w
= r
.Width(), h
= r
.Height();
293 DWORD offset
= r
.top
*rect
.Width() + r
.left
;
295 r
+= CRect(1, 1, 1, 1);
297 DWORD
* src
= (DWORD
*)&lpTemp1
[offset
];
298 DWORD
* dst
= (DWORD
*)&lpTemp2
[1 + w
+ 1];
300 memset(lpTemp2
, 0, (1 + w
+ 1)*sizeof(RGBQUAD
));
302 for(int height
= h
; height
; height
--, src
+= rect
.Width())
305 memcpy(dst
, src
, w
*sizeof(RGBQUAD
)); dst
+= w
;
309 memset(dst
, 0, (1 + w
+ 1)*sizeof(RGBQUAD
));
313 rect
= r
+ rect
.TopLeft();
316 ////////////////////////////////
321 #define GP(xx, yy) (((xx) < 0 || (yy) < 0 || (xx) >= w || (yy) >= h) ? 0 : p[(yy)*w+(xx)])
323 CAutoPtrList
<COutline
>* CVobSubImage::GetOutlineList(CPoint
& topleft
)
325 int w
= rect
.Width(), h
= rect
.Height(), len
= w
*h
;
326 if(len
<= 0) return NULL
;
328 CAutoVectorPtr
<BYTE
> p
;
329 if(!p
.Allocate(len
)) return NULL
;
331 CAutoPtrList
<COutline
>* ol
= new CAutoPtrList
<COutline
>();
335 RGBQUAD
* rgbp
= (RGBQUAD
*)lpPixels
;
337 for(int i
= 0; i
< len
; i
++, cp
++, rgbp
++)
338 *cp
= !!rgbp
->rgbReserved
;
340 enum {UP
, RIGHT
, DOWN
, LEFT
};
342 topleft
.x
= topleft
.y
= INT_MAX
;
350 for(y
= 0; y
< h
; y
++)
352 for(x
= 0; x
< w
-1; x
++, cp
++)
354 if(cp
[0] == 0 && cp
[1] == 1) break;
364 int prevdir
, dir
= UP
;
366 int ox
= x
, oy
= y
, odir
= dir
;
368 CAutoPtr
<COutline
> o(new COutline
);
387 pp
= CPoint(x
+1, y
+1);
413 // o set, x empty, . can be anything
415 if(fl
==1) dir
= (dir
-1+4)&3;
416 else if(fl
!=1 && fr
!=1 && br
==1) dir
= (dir
+1)&3;
417 else if(p
[y
*w
+x
]&16) {ASSERT(0); break;} // we are going around in one place (this must not happen if the starting conditions were correct)
419 p
[y
*w
+x
] = (p
[y
*w
+x
]<<1) | 2; // increase turn count (== log2(highordbit(*p)))
424 if(prevdir
== LEFT
) {x
--; y
--;}
425 if(prevdir
== UP
) y
--;
428 if(prevdir
== UP
) {x
++; y
--;}
429 if(prevdir
== RIGHT
) x
++;
432 if(prevdir
== RIGHT
) {x
++; y
++;}
433 if(prevdir
== DOWN
) y
++;
436 if(prevdir
== DOWN
) {x
--; y
++;}
437 if(prevdir
== LEFT
) x
--;
441 int d
= dir
- prevdir
;
442 o
->Add(pp
, d
== 3 ? -1 : d
== -3 ? 1 : d
);
444 if(topleft
.x
> pp
.x
) topleft
.x
= pp
.x
;
445 if(topleft
.y
> pp
.y
) topleft
.y
= pp
.y
;
447 while(!(x
== ox
&& y
== oy
&& dir
== odir
));
449 if(o
->pa
.GetCount() > 0 && (x
== ox
&& y
== oy
&& dir
== odir
))
462 static bool FitLine(COutline
& o
, int& start
, int& end
)
464 int len
= o
.pa
.GetCount();
465 if(len
< 7) return(false); // small segments should be handled with beziers...
467 for(start
= 0; start
< len
&& !o
.da
[start
]; start
++);
468 for(end
= len
-1; end
> start
&& !o
.da
[end
]; end
--);
470 if(end
-start
< 8 || end
-start
< (len
-end
)+(start
-0)) return(false);
476 for(i
= start
+1, j
= end
, k
= start
; i
<= j
; i
++)
478 if(!o
.da
[i
]) continue;
479 if(o
.da
[i
] == o
.da
[k
]) return(false);
480 if(o
.da
[i
] == -1) la
.Add(i
-k
);
485 bool fl
= true, fr
= true;
487 // these tests are completly heuristic and might be redundant a bit...
489 for(i
= 0, j
= la
.GetSize(); i
< j
&& fl
; i
++) {if(la
[i
] != 1) fl
= false;}
490 for(i
= 0, j
= ra
.GetSize(); i
< j
&& fr
; i
++) {if(ra
[i
] != 1) fr
= false;}
492 if(!fl
&& !fr
) return(false); // can't be a line if there are bigger steps than one in both directions (lines are usually drawn by stepping one either horizontally or vertically)
493 if(fl
&& fr
&& 1.0*(end
-start
)/((len
-end
)*2+(start
-0)*2) > 0.4) return(false); // if this section is relatively too small it may only be a rounded corner
494 if(!fl
&& la
.GetSize() > 0 && la
.GetSize() <= 4 && (la
[0] == 1 && la
[la
.GetSize()-1] == 1)) return(false); // one step at both ends, doesn't sound good for a line (may be it was skewed, so only eliminate smaller sections where beziers going to look just as good)
495 if(!fr
&& ra
.GetSize() > 0 && ra
.GetSize() <= 4 && (ra
[0] == 1 && ra
[ra
.GetSize()-1] == 1)) return(false); // -''-
497 CUIntArray
& a
= !fl
? la
: ra
;
503 for(i
= 0, j
= INT_MAX
, k
= 0; i
< len
; i
++)
505 if(j
> a
[i
]) j
= a
[i
];
506 if(k
< a
[i
]) k
= a
[i
];
510 if(k
- j
> 2 && 1.0*sum
/len
< 2) return(false);
511 if(k
- j
> 2 && 1.0*sum
/len
>= 2 && len
< 4) return(false);
513 if((la
.GetSize()/2+ra
.GetSize()/2)/2 <= 2)
515 if((k
+j
)/2 < 2 && k
*j
!=1) return(false);
520 CPoint sp
= o
.pa
[start
], ep
= o
.pa
[end
];
522 double minerr
= 0, maxerr
= 0;
524 double vx
= ep
.x
- sp
.x
, vy
= ep
.y
- sp
.y
, l
= sqrt(vx
*vx
+vy
*vy
);
527 for(i
= start
+1, j
= end
-1; i
<= j
; i
++)
529 CPoint p
= o
.pa
[i
], dp
= p
- sp
;
530 double t
= vx
*dp
.x
+vy
*dp
.y
, dx
= vx
*t
+ sp
.x
- p
.x
, dy
= vy
*t
+ sp
.y
- p
.y
;
534 if(vy
*dx
-dy
*vx
< 0) {if(minerr
> -t
) minerr
= -t
;}
535 else {if(maxerr
< t
) maxerr
= t
;}
538 return((maxerr
-minerr
)/l
< 0.1 || err
/l
< 1.5 || (fabs(maxerr
) < 8 && fabs(minerr
) < 8));
541 static int CalcPossibleCurveDegree(COutline
& o
)
543 int len2
= o
.da
.GetCount();
547 for(int i
= 0, j
= 0; j
< len2
; j
++)
549 if(j
== len2
-1 || o
.da
[j
])
556 int len
= la
.GetCount();
560 // check if we can find a reason to add a penalty degree, or two :P
561 // it is mainly about looking for distant corners
566 for(int i
= 0; i
< len
; i
++) ma
[i
&1] += la
[i
];
568 int ca
[2] = {ma
[0], ma
[1]};
569 for(int i
= 0; i
< len
; i
++)
573 double c1
= 1.0*ca
[0]/ma
[0], c2
= 1.0*ca
[1]/ma
[1], c3
= 1.0*la
[i
]/ma
[i
&1];
575 if(len2
> 16 && (fabs(c1
-c2
) > 0.7 || (c3
> 0.6 && la
[i
] > 5)))
576 {penalty
= 2; break;}
578 if(fabs(c1
-c2
) > 0.6 || (c3
> 0.4 && la
[i
] > 5))
588 for(int i
= 0; i
< len
; i
+=2)
590 if(la
[i
] > 1) {ret
++; i
--;} // prependicular to the last chosen section and bigger then 1 -> add a degree and continue with the other dir
596 inline double vectlen(CPoint p
)
598 return(sqrt((double)(p
.x
*p
.x
+p
.y
*p
.y
)));
601 inline double vectlen(CPoint p1
, CPoint p2
)
603 return(vectlen(p2
- p1
));
606 static bool MinMaxCosfi(COutline
& o
, double& mincf
, double& maxcf
) // not really cosfi, it is weighted by the distance from the segment endpoints, and since it would be always between -1 and 0, the applied sign marks side
608 CAtlArray
<CPoint
>& pa
= o
.pa
;
610 int len
= (int)pa
.GetCount();
611 if(len
< 6) return(false);
616 CPoint p
= pa
[len
-1] - pa
[0];
617 double l
= vectlen(p
);
619 for(int i
= 2; i
< len
-2; i
++) // skip the endpoints, they aren't accurate
621 CPoint p1
= pa
[0] - pa
[i
], p2
= pa
[len
-1] - pa
[i
];
622 double l1
= vectlen(p1
), l2
= vectlen(p2
);
623 int sign
= p1
.x
*p
.y
-p1
.y
*p
.x
>= 0 ? 1 : -1;
625 double c
= (1.0*len
/2 - fabs(i
- 1.0*len
/2)) / len
* 2; // c: 0 -> 1 -> 0
627 double cosfi
= (1+(p1
.x
*p2
.x
+p1
.y
*p2
.y
)/(l1
*l2
)) * sign
* c
;
628 if(mincf
> cosfi
) mincf
= cosfi
;
629 if(maxcf
< cosfi
) maxcf
= cosfi
;
635 static bool FitBezierVH(COutline
& o
, CPoint
& p1
, CPoint
& p2
)
639 CAtlArray
<CPoint
>& pa
= o
.pa
;
641 int len
= (int)pa
.GetCount();
649 CPoint mid
= pa
[0]+pa
[1];
656 CPoint dir1
= pa
[1] - pa
[0], dir2
= pa
[len
-2] - pa
[len
-1];
657 if((dir1
.x
&&dir1
.y
)||(dir2
.x
&&dir2
.y
))
658 return(false); // we are only fitting beziers with hor./ver. endings
660 if(CalcPossibleCurveDegree(o
) > 3)
664 if(MinMaxCosfi(o
, mincf
, maxcf
))
667 || maxcf
-mincf
> 0.6 && (maxcf
>= 0.4 || mincf
<= -0.4))
671 CPoint p0
= p1
= pa
[0];
672 CPoint p3
= p2
= pa
[len
-1];
674 CAtlArray
<double> pl
;
677 double c10
= 0, c11
= 0, c12
= 0, c13
= 0, c1x
= 0, c1y
= 0;
678 double c20
= 0, c21
= 0, c22
= 0, c23
= 0, c2x
= 0, c2y
= 0;
681 for(pl
[0] = 0, i
= 1; i
< len
; i
++)
683 CPoint diff
= (pa
[i
] - pa
[i
-1]);
684 pl
[i
] = (length
+= sqrt((double)(diff
.x
*diff
.x
+diff
.y
*diff
.y
)));
687 for(i
= 0; i
< len
; i
++)
689 double t1
= pl
[i
] / length
;
693 double it2
= it1
*it1
;
694 double it3
= it2
*it1
;
696 double dc1
= 3.0*it2
*t1
;
697 double dc2
= 3.0*it1
*t2
;
714 if(dir1
.y
== 0 && dir2
.x
== 0)
716 p1
.x
= (int)((c1x
- c10
*p0
.x
- c12
*p3
.x
- c13
*p3
.x
) / c11
+ 0.5);
717 p2
.y
= (int)((c2y
- c20
*p0
.y
- c21
*p0
.y
- c23
*p3
.y
) / c22
+ 0.5);
719 else if(dir1
.x
== 0 && dir2
.y
== 0)
721 p2
.x
= (int)((c2x
- c20
*p0
.x
- c21
*p0
.x
- c23
*p3
.x
) / c22
+ 0.5);
722 p1
.y
= (int)((c1y
- c10
*p0
.y
- c12
*p3
.y
- c13
*p3
.y
) / c11
+ 0.5);
724 else if(dir1
.y
== 0 && dir2
.y
== 0)
727 double D
= c11
*c22
- c12
*c21
;
728 p1
.x
= (int)(((c1x
-c10
*p0
.x
-c13
*p3
.x
)*c22
- c12
*(c2x
-c20
*p0
.x
-c23
*p3
.x
)) / D
+ 0.5);
729 p2
.x
= (int)((c11
*(c2x
-c20
*p0
.x
-c23
*p3
.x
) - (c1x
-c10
*p0
.x
-c13
*p3
.x
)*c21
) / D
+ 0.5);
731 else if(dir1
.x
== 0 && dir2
.x
== 0)
734 double D
= c11
*c22
- c12
*c21
;
735 p1
.y
= (int)(((c1y
-c10
*p0
.y
-c13
*p3
.y
)*c22
- c12
*(c2y
-c20
*p0
.y
-c23
*p3
.y
)) / D
+ 0.5);
736 p2
.y
= (int)((c11
*(c2y
-c20
*p0
.y
-c23
*p3
.y
) - (c1y
-c10
*p0
.y
-c13
*p3
.y
)*c21
) / D
+ 0.5);
738 else // must not happen
744 // check for "inside-out" beziers
745 CPoint dir3
= p1
- p0
, dir4
= p2
- p3
;
746 if((dir1
.x
*dir3
.x
+dir1
.y
*dir3
.y
) <= 0 || (dir2
.x
*dir4
.x
+dir2
.y
*dir4
.y
) <= 0)
752 int CVobSubImage::GrabSegment(int start
, COutline
& o
, COutline
& ret
)
756 int len
= o
.pa
.GetCount();
758 int cur
= (start
)%len
, first
= -1, last
= -1;
759 int curDir
= 0, lastDir
= 0;
761 for(int i
= 0; i
< len
; i
++)
765 if(o
.da
[cur
] == 0) continue;
767 if(first
== -1) first
= cur
;
769 if(lastDir
== o
.da
[cur
])
771 CPoint startp
= o
.pa
[first
]+o
.pa
[start
]; startp
.x
>>= 1; startp
.y
>>= 1;
772 CPoint endp
= o
.pa
[last
]+o
.pa
[cur
]; endp
.x
>>= 1; endp
.y
>>= 1;
774 if(first
< start
) first
+= len
;
775 start
= ((start
+first
)>>1)+1;
776 if(start
>= len
) start
-= len
;
777 if(cur
< last
) cur
+= len
;
778 cur
= ((last
+cur
+1)>>1);
779 if(cur
>= len
) cur
-= len
;
785 ret
.Add(o
.pa
[start
], o
.da
[start
]);
788 if(start
>= len
) start
-= len
;
805 void CVobSubImage::SplitOutline(COutline
& o
, COutline
& o1
, COutline
& o2
)
807 int len
= o
.pa
.GetCount();
810 CAtlArray
<UINT
> la
, sa
, ea
;
814 for(i
= 0, j
= 0; j
< len
; j
++)
816 if(j
== len
-1 || o
.da
[j
])
825 int maxlen
= 0, maxidx
= -1;
826 int maxlen2
= 0, maxidx2
= -1;
828 for(i
= 0; i
< la
.GetCount(); i
++)
836 if(maxlen2
< la
[i
] && i
> 0 && i
< la
.GetCount()-1)
843 if(maxlen
== maxlen2
) maxidx
= maxidx2
; // if equal choose the inner section
845 j
= (sa
[maxidx
] + ea
[maxidx
]) >> 1, k
= (sa
[maxidx
] + ea
[maxidx
] + 1) >> 1;
850 for(i
= 0; i
<= j
; i
++)
851 o1
.Add(o
.pa
[i
], o
.da
[i
]);
855 CPoint mid
= o
.pa
[j
]+o
.pa
[k
]; mid
.x
>>= 1; mid
.y
>>= 1;
860 for(i
= k
; i
< len
; i
++)
861 o2
.Add(o
.pa
[i
], o
.da
[i
]);
864 void CVobSubImage::AddSegment(COutline
& o
, CAtlArray
<BYTE
>& pathTypes
, CAtlArray
<CPoint
>& pathPoints
)
866 int i
, len
= o
.pa
.GetCount();
869 int nLeftTurns
= 0, nRightTurns
= 0;
871 for(i
= 0; i
< len
; i
++)
873 if(o
.da
[i
] == -1) nLeftTurns
++;
874 else if(o
.da
[i
] == 1) nRightTurns
++;
877 if(nLeftTurns
== 0 && nRightTurns
== 0) // line
879 pathTypes
.Add(PT_LINETO
);
880 pathPoints
.Add(o
.pa
[len
-1]);
885 if(nLeftTurns
== 0 || nRightTurns
== 0) // b-spline
887 pathTypes
.Add(PT_MOVETONC
);
888 pathPoints
.Add(o
.pa
[0]+(o
.pa
[0]-o
.pa
[1]));
890 for(i
= 0; i
< 3; i
++)
892 pathTypes
.Add(PT_BSPLINETO
);
893 pathPoints
.Add(o
.pa
[i
]);
898 pathTypes
.Add(PT_BSPLINEPATCHTO
);
899 pathPoints
.Add(o
.pa
[i
]);
902 pathTypes
.Add(PT_BSPLINEPATCHTO
);
903 pathPoints
.Add(o
.pa
[len
-1]+(o
.pa
[len
-1]-o
.pa
[len
-2]));
905 pathTypes
.Add(PT_MOVETONC
);
906 pathPoints
.Add(o
.pa
[len
-1]);
912 if(FitLine(o
, start
, end
)) // b-spline, line, b-spline
914 pathTypes
.Add(PT_MOVETONC
);
915 pathPoints
.Add(o
.pa
[0]+(o
.pa
[0]-o
.pa
[1]));
917 pathTypes
.Add(PT_BSPLINETO
);
918 pathPoints
.Add(o
.pa
[0]);
920 pathTypes
.Add(PT_BSPLINETO
);
921 pathPoints
.Add(o
.pa
[1]);
923 CPoint p
[4], pp
, d
= o
.pa
[end
] - o
.pa
[start
];
924 double l
= sqrt((double)(d
.x
*d
.x
+d
.y
*d
.y
)), dx
= 1.0 * d
.x
/ l
, dy
= 1.0 * d
.y
/ l
;
926 pp
= o
.pa
[start
]-o
.pa
[start
-1];
927 double l1
= abs(pp
.x
)+abs(pp
.y
);
928 pp
= o
.pa
[end
]-o
.pa
[end
+1];
929 double l2
= abs(pp
.x
)+abs(pp
.y
);
930 p
[0] = CPoint((int)(1.0 * o
.pa
[start
].x
+ dx
*l1
+ 0.5), (int)(1.0 * o
.pa
[start
].y
+ dy
*l1
+ 0.5));
931 p
[1] = CPoint((int)(1.0 * o
.pa
[start
].x
+ dx
*l1
*2 + 0.5), (int)(1.0 * o
.pa
[start
].y
+ dy
*l1
*2 + 0.5));
932 p
[2] = CPoint((int)(1.0 * o
.pa
[end
].x
- dx
*l2
*2 + 0.5), (int)(1.0 * o
.pa
[end
].y
- dy
*l2
*2 + 0.5));
933 p
[3] = CPoint((int)(1.0 * o
.pa
[end
].x
- dx
*l2
+ 0.5), (int)(1.0 * o
.pa
[end
].y
- dy
*l2
+ 0.5));
937 pathTypes
.Add(PT_BSPLINETO
);
938 pathPoints
.Add(p
[0]);
942 pathTypes
.Add(PT_BSPLINETO
);
943 pathPoints
.Add(o
.pa
[2]);
945 for(int i
= 3; i
<= start
; i
++)
947 pathTypes
.Add(PT_BSPLINEPATCHTO
);
948 pathPoints
.Add(o
.pa
[i
]);
951 pathTypes
.Add(PT_BSPLINEPATCHTO
);
952 pathPoints
.Add(p
[0]);
955 pathTypes
.Add(PT_BSPLINEPATCHTO
);
956 pathPoints
.Add(p
[1]);
958 pathTypes
.Add(PT_MOVETONC
);
959 pathPoints
.Add(p
[0]);
961 pathTypes
.Add(PT_LINETO
);
962 pathPoints
.Add(p
[3]);
964 pathTypes
.Add(PT_MOVETONC
);
965 pathPoints
.Add(p
[2]);
967 pathTypes
.Add(PT_BSPLINEPATCHTO
);
968 pathPoints
.Add(p
[3]);
970 for(i
= end
; i
< len
; i
++)
972 pathTypes
.Add(PT_BSPLINEPATCHTO
);
973 pathPoints
.Add(o
.pa
[i
]);
976 pathTypes
.Add(PT_BSPLINEPATCHTO
);
977 pathPoints
.Add(o
.pa
[len
-1]+(o
.pa
[len
-1]-o
.pa
[len
-2]));
979 pathTypes
.Add(PT_MOVETONC
);
980 pathPoints
.Add(o
.pa
[len
-1]);
986 if(FitBezierVH(o
, p1
, p2
)) // bezier
988 pathTypes
.Add(PT_BEZIERTO
);
990 pathTypes
.Add(PT_BEZIERTO
);
992 pathTypes
.Add(PT_BEZIERTO
);
993 pathPoints
.Add(o
.pa
[o
.pa
.GetCount()-1]);
999 SplitOutline(o
, o1
, o2
);
1000 AddSegment(o1
, pathTypes
, pathPoints
);
1001 AddSegment(o2
, pathTypes
, pathPoints
);
1004 bool CVobSubImage::Polygonize(CAtlArray
<BYTE
>& pathTypes
, CAtlArray
<CPoint
>& pathPoints
, bool fSmooth
, int scale
)
1007 CAutoPtr
<CAutoPtrList
<COutline
> > ol(GetOutlineList(topleft
));
1008 if(!ol
) return(false);
1012 pos
= ol
->GetHeadPosition();
1015 CAtlArray
<CPoint
>& pa
= ol
->GetNext(pos
)->pa
;
1016 for(size_t i
= 0; i
< pa
.GetCount(); i
++)
1018 pa
[i
].x
= (pa
[i
].x
-topleft
.x
)<<scale
;
1019 pa
[i
].y
= (pa
[i
].y
-topleft
.y
)<<scale
;
1023 pos
= ol
->GetHeadPosition();
1026 COutline
& o
= *ol
->GetNext(pos
), o2
;
1030 int i
= 0, iFirst
= -1;
1034 i
= GrabSegment(i
, o
, o2
);
1036 if(i
== iFirst
) break;
1041 pathTypes
.Add(PT_MOVETO
);
1042 pathPoints
.Add(o2
.pa
[0]);
1045 AddSegment(o2
, pathTypes
, pathPoints
);
1051 for(int i = 1, len = o.pa.GetSize(); i < len; i++)
1053 if(int dir = o.da[i-1])
1055 CPoint dir2 = o.pa[i] - o.pa[i-1];
1056 dir2.x /= 2; dir2.y /= 2;
1057 CPoint dir1 = dir > 0 ? CPoint(dir2.y, -dir2.x) : CPoint(-dir2.y, dir2.x);
1060 o.pa.InsertAt(i, o.pa[i-1] + dir2);
1061 o.da.InsertAt(i, -dir);
1062 o.pa.InsertAt(i+1, o.pa[i] + dir1);
1063 o.da.InsertAt(i+1, dir);
1069 pathTypes
.Add(PT_MOVETO
);
1070 pathPoints
.Add(o
.pa
[0]);
1072 for(int i
= 1, len
= o
.pa
.GetCount(); i
< len
; i
++)
1074 pathTypes
.Add(PT_LINETO
);
1075 pathPoints
.Add(o
.pa
[i
]);
1080 return !pathTypes
.IsEmpty();
1083 bool CVobSubImage::Polygonize(CStringW
& assstr
, bool fSmooth
, int scale
)
1085 CAtlArray
<BYTE
> pathTypes
;
1086 CAtlArray
<CPoint
> pathPoints
;
1088 if(!Polygonize(pathTypes
, pathPoints
, fSmooth
, scale
))
1091 assstr
.Format(L
"{\\an7\\pos(%d,%d)\\p%d}", rect
.left
, rect
.top
, 1+scale
);
1092 // assstr.Format(L"{\\p%d}", 1+scale);
1096 int nPoints
= pathTypes
.GetCount();
1098 for(int i
= 0; i
< nPoints
; i
++)
1102 switch(pathTypes
[i
])
1105 if(lastType
!= PT_MOVETO
) assstr
+= L
"m ";
1106 s
.Format(L
"%d %d ", pathPoints
[i
].x
, pathPoints
[i
].y
);
1109 if(lastType
!= PT_MOVETONC
) assstr
+= L
"n ";
1110 s
.Format(L
"%d %d ", pathPoints
[i
].x
, pathPoints
[i
].y
);
1113 if(lastType
!= PT_LINETO
) assstr
+= L
"l ";
1114 s
.Format(L
"%d %d ", pathPoints
[i
].x
, pathPoints
[i
].y
);
1119 if(lastType
!= PT_BEZIERTO
) assstr
+= L
"b ";
1120 s
.Format(L
"%d %d %d %d %d %d ", pathPoints
[i
].x
, pathPoints
[i
].y
, pathPoints
[i
+1].x
, pathPoints
[i
+1].y
, pathPoints
[i
+2].x
, pathPoints
[i
+2].y
);
1127 if(lastType
!= PT_BSPLINETO
) assstr
+= L
"s ";
1128 s
.Format(L
"%d %d %d %d %d %d ", pathPoints
[i
].x
, pathPoints
[i
].y
, pathPoints
[i
+1].x
, pathPoints
[i
+1].y
, pathPoints
[i
+2].x
, pathPoints
[i
+2].y
);
1132 case PT_BSPLINEPATCHTO
:
1133 if(lastType
!= PT_BSPLINEPATCHTO
) assstr
+= L
"p ";
1134 s
.Format(L
"%d %d ", pathPoints
[i
].x
, pathPoints
[i
].y
);
1138 lastType
= pathTypes
[i
];
1143 assstr
+= L
"{\\p0}";
1148 void CVobSubImage::Scale2x()
1150 int w
= rect
.Width(), h
= rect
.Height();
1152 DWORD
* src
= (DWORD
*)lpPixels
;
1153 DWORD
* dst
= new DWORD
[w
*h
];
1155 for(int y
= 0; y
< h
; y
++)
1157 for(int x
= 0; x
< w
; x
++, src
++, dst
++)
1161 DWORD A
= x
> 0 && y
> 0 ? src
[-w
-1] : E
;
1162 DWORD B
= y
> 0 ? src
[-w
] : E
;
1163 DWORD C
= x
< w
-1 && y
> 0 ? src
[-w
+1] : E
;
1165 DWORD D
= x
> 0 ? src
[-1] : E
;;
1166 DWORD F
= x
< w
-1 ? src
[+1] : E
;;
1168 DWORD G
= x
> 0 && y
< h
-1 ? src
[+w
-1] : E
;
1169 DWORD H
= y
< h
-1 ? src
[+w
] : E
;
1170 DWORD I
= x
< w
-1 && y
< h
-1 ? src
[+w
+1] : E
;
1172 DWORD E0
= D
== B
&& B
!= F
&& D
!= H
? D
: E
;
1173 DWORD E1
= B
== F
&& B
!= D
&& F
!= H
? F
: E
;
1174 DWORD E2
= D
== H
&& D
!= B
&& H
!= F
? D
: E
;
1175 DWORD E3
= H
== F
&& D
!= H
&& B
!= F
? F
: E
;
1177 *dst
= ((((E0
&0x00ff00ff)+(E1
&0x00ff00ff)+(E2
&0x00ff00ff)+(E3
&0x00ff00ff)+2)>>2)&0x00ff00ff)
1178 | (((((E0
>>8)&0x00ff00ff)+((E1
>>8)&0x00ff00ff)+((E2
>>8)&0x00ff00ff)+((E3
>>8)&0x00ff00ff)+2)<<6)&0xff00ff00);
1185 memcpy(src
, dst
, w
*h
*4);