1 /*_______________________________ epson-escpage-comp.c _____________________________*/
\r
3 /* 1 2 3 4 5 6 7 8 */
\r
4 /*34567890123456789012345678901234567890123456789012345678901234567890123456789012345678*/
\r
5 /*******************************************|********************************************/
\r
7 * Copyright (c) 2010 Seiko Epson Corporation All rights reserved.
\r
9 * Copyright protection claimed includes all forms and matters of
\r
10 * copyrightable material and information now allowed by statutory or judicial
\r
11 * law or hereinafter granted, including without limitation, material generated
\r
12 * from the software programs which are displayed on the screen such as icons,
\r
13 * screen display looks, etc.
\r
17 /*------------------------------------ Includes -------------------------------------*/
\r
18 /*******************************************|********************************************/
\r
19 #include "epson-escpr-mem.h"
\r
20 #include "epson-escpage-comp.h"
\r
22 /*----------------------------------- Definitions ------------------------------------*/
\r
23 /*******************************************|********************************************/
\r
25 #ifdef EPS_LOG_MODULE_PAGE
\r
26 #define EPS_LOG_MODULE EPS_LOG_MODULE_PAGE
\r
28 #define EPS_LOG_MODULE 0
\r
31 /* Define Bitmap Format */
\r
35 #define ConvertEndianWord(w) ((EPS_UINT16) ((((w) >> 8) & 0xFF) | (((w) << 8) & 0xFF00)))
\r
36 #define ConvertEndianDWORD(d) (((EPS_UINT32) (d) << 24) | (((EPS_UINT32) (d) << 8) & 0x00FF0000) | (((EPS_UINT32) (d) >> 8) & 0x0000FF00) | ((EPS_UINT32) (d) >> 24))
\r
37 #define GetCompressMode(d) ((EPS_UINT16) ((d) >> 16))
\r
38 #define GetCompressQuality(d) ((EPS_UINT16) ((d) & 0xFFFF))
\r
40 #define BAND_PIXEL 4
\r
41 #define MakeCompress20Mode(q) (0x20 + (q))
\r
42 #define MakeUncompress20Mode(q) (0x00 + (q))
\r
44 /*--------------------------- Data Structure Declarations ---------------------------*/
\r
45 /*******************************************|********************************************/
\r
46 typedef struct tagCODINGDATA {
\r
47 EPS_UINT16 hufCode[256] ;
\r
48 EPS_UINT8 hufCodeLen[256] ;
\r
49 EPS_UINT8* lpCurPtr ;
\r
50 EPS_UINT32 leftCount ;
\r
52 EPS_UINT16 codeBits ;
\r
55 typedef struct tagCOMPRESSBUFFER {
\r
56 EPS_UINT16 wMode ; /* Compress Mode */
\r
57 EPS_UINT16 wQuality ; /* Compress Quality */
\r
58 EPS_UINT8* lpBuffer ; /* Output Buffer */
\r
59 EPS_UINT32 sizeBuffer ; /* Output Buffer Size */
\r
60 EPS_UINT32 dwWidth ;
\r
61 EPS_UINT32 dwHeight ;
\r
62 EPS_UINT32 format ; /* Align Format */
\r
63 EPS_UINT16 biBitCount ; /* Bitmap Bit Count */
\r
64 EPS_INT32 nextLine ;
\r
65 EPS_BOOL bInvertX ; /* Invert Image X */
\r
66 EPS_UINT8* lpBitsOrg ; /* Start Address */
\r
70 typedef struct tagBLOCKHEADER20 {
\r
71 EPS_UINT32 size ; /* 0 */
\r
72 EPS_UINT16 width ; /* 4 */
\r
73 EPS_UINT16 bandPixel ; /* 6 */
\r
74 EPS_UINT16 mode ; /* 8 */
\r
76 #define SIZEOF_BLOCKHEADER20 (4+2+2+2)
\r
78 typedef struct tagCOMPBUFFER20 {
\r
79 COMPRESSBUFFER cbuf ;
\r
82 EPS_UINT32 bandLimit ;
\r
86 /*---------------------------- ESC/P-R Lib Global Variables --------------------------*/
\r
87 /*******************************************|********************************************/
\r
88 extern EPS_CMN_FUNC epsCmnFnc;
\r
90 /*------------------------------ Local Global Variables ------------------------------*/
\r
91 /*******************************************|********************************************/
\r
92 static const EPS_UINT16 HufmanDefTable2[]
\r
93 = {0, 0, 1, 2, 2, 4, 4, 7, 9, 14, 17, 24, 172} ;
\r
94 static const EPS_UINT16 HufmanDefTable3[][2]
\r
95 = { 0x00, 2, 0x02, 2, 0x01, 2, 0x03, 4, 0x0b, 4,
\r
96 0x07, 5, 0x17, 5, 0x0f, 5, 0x1f, 5,
\r
99 /*-------------------------- Private Functions Declaration --------------------------*/
\r
100 /*******************************************|********************************************/
\r
101 static EPS_UINT32 EPGetCompressBufferSize(EPS_UINT32 dwMode) ;
\r
102 static EPS_UINT32 EPCompressImage(
\r
103 EPS_UINT32 dwMode,
\r
104 EPS_UINT32 xSrc, EPS_UINT32 ySrc, EPS_UINT32 dwWidth, EPS_UINT32 dwHeight,
\r
105 EPS_BITMAPINFO *lpbmi, EPS_UINT32 biFormat, EPS_UINT8* lpBits,
\r
106 EPS_UINT8* lpBuf, EPS_UINT32 sizeBuf,
\r
107 EPS_UINT8* lpWorkBuf ) ;
\r
108 static EPS_UINT32 Compress20(COMPBUFFER20* lpC20Buf) ;
\r
109 static EPS_BOOL MakeHufmanCodeTable(EPS_UINT16 wMode, EPS_UINT16 wQuality, CODINGDATA* lpcd) ;
\r
110 static EPS_BOOL WriteBandData20(EPS_INT32 band, EPS_INT32 incptr, EPS_UINT8* lpSrc, COMPBUFFER20* lpC20Buf) ;
\r
111 static EPS_UINT8 GetByteBLOCKHEADER20(BLOCKHEADER20 *p, EPS_INT32 n);
\r
112 static void MakeHufmanTable1(const EPS_UINT16 cdn[], CODINGDATA* lpcd) ;
\r
113 static void CodeHufmanData(const EPS_UINT8 d, CODINGDATA* const lpcd);
\r
114 static void WriteDataToBuffer(CODINGDATA* const lpcd);
\r
117 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
\r
118 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
\r
119 /*%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%*/
\r
120 /*-------------------- Public Functions ---------------------*/
\r
121 /*%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%*/
\r
122 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
\r
123 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
\r
125 EPS_UINT8* CompressBitImage(
\r
128 EPS_BITMAPINFO *pBitMapInfo,
\r
129 EPS_UINT8* pRealBits,
\r
130 EPS_UINT32 ulDataFormat,
\r
131 EPS_UINT32 *pulCompressType,
\r
132 EPS_UINT32 *pulImageSize
\r
135 EPS_BITMAPINFO bmi;
\r
136 EPS_UINT32 dwComMode = 0;
\r
137 EPS_UINT32 dwwkBufferSize;
\r
138 EPS_UINT8* pwkBuffer = NULL;
\r
139 EPS_UINT32 dwBuffer;
\r
140 EPS_UINT8* pTmp = NULL;
\r
141 EPS_UINT32 dwCompressedSize;
\r
143 EPS_INT32 ulSrcleft, ulSrcright, ulSrcbottom, ulSrctop;
\r
145 ulSrcleft = pRec->left;
\r
146 ulSrcright= pRec->right;
\r
147 ulSrcbottom = pRec->bottom;
\r
148 ulSrctop= pRec->top;
\r
150 bmi = *pBitMapInfo;
\r
152 dwComMode = ulDataFormat;
\r
154 *pulCompressType = dwComMode;
\r
155 dwComMode = dwComMode << 16;
\r
157 dwwkBufferSize = EPGetCompressBufferSize( dwComMode);
\r
159 if(dwwkBufferSize == 0){
\r
160 *pulCompressType = 0;
\r
164 if(!(pwkBuffer = (EPS_UINT8*)EPS_ALLOC( dwwkBufferSize ))){
\r
165 *pulCompressType = 0;
\r
169 dwBuffer = (((ulSrcright - ulSrcleft ) * 24 + 31) / 32) * 4 * (ulSrcbottom - ulSrctop );
\r
170 if(!(pTmp = (EPS_UINT8*)EPS_ALLOC( dwBuffer ))){
\r
171 EPS_FREE(pwkBuffer );
\r
172 *pulCompressType = 0;
\r
176 dwCompressedSize = EPCompressImage( dwComMode,
\r
179 ulSrcright - ulSrcleft ,
\r
180 ulSrcbottom - ulSrctop ,
\r
188 EPS_FREE(pwkBuffer);
\r
189 if(dwCompressedSize == 0){
\r
191 *pulCompressType = 0;
\r
195 *pulImageSize = dwCompressedSize;
\r
200 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
\r
201 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
\r
202 /*%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%*/
\r
203 /*-------------------- Local Functions ---------------------*/
\r
204 /*%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%*/
\r
205 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
\r
206 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
\r
208 static EPS_UINT32 EPGetCompressBufferSize (EPS_UINT32 dwMode)
\r
214 mode = GetCompressMode(dwMode) ;
\r
218 case EP_COMPRESS20 :
\r
219 EPS_RETURN( sizeof(COMPBUFFER20) )
\r
228 static EPS_UINT32 EPCompressImage (
\r
232 EPS_UINT32 dwWidth,
\r
233 EPS_UINT32 dwHeight,
\r
234 EPS_BITMAPINFO *lpbmi,
\r
235 EPS_UINT32 biFormat,
\r
238 EPS_UINT32 sizeBuf,
\r
239 EPS_UINT8* lpWorkBuf )
\r
241 COMPRESSBUFFER* lpCBuf ;
\r
242 EPS_UINT32 height ;
\r
246 if (dwWidth == 0 || dwHeight == 0) {
\r
249 if (lpWorkBuf == NULL) {
\r
253 lpCBuf = (COMPRESSBUFFER*) lpWorkBuf ;
\r
255 /* Check Width and calculate Scan Size */
\r
257 if (lpbmi->biWidth <= 0 || (EPS_UINT32) lpbmi->biWidth < xSrc + dwWidth) {
\r
261 lpCBuf->dwWidth = dwWidth ;
\r
262 lpCBuf->biBitCount = lpbmi->biBitCount ;
\r
263 lpCBuf->format = biFormat ;
\r
265 lpCBuf->nextLine = ((lpbmi->biWidth * lpCBuf->biBitCount + 7) / 8 + 3) & 0xFFFFFFFC ;
\r
266 lpCBuf->lpBitsOrg = lpBits + (xSrc*lpCBuf->biBitCount / 8) ;
\r
267 /*lpCBuf->bitOffset = (EPS_INT16) (xSrc*lpCBuf->biBitCount % 8) ;*/
\r
269 /* Check Height and calculate start addr */
\r
271 lpCBuf->dwHeight = dwHeight ;
\r
272 if (lpbmi->biHeight > 0) {
\r
273 /* bottom up bitmap */
\r
274 height = (EPS_UINT32) lpbmi->biHeight ;
\r
275 lpCBuf->lpBitsOrg += lpCBuf->nextLine * (ySrc + dwHeight - 1);
\r
276 lpCBuf->nextLine = -lpCBuf->nextLine ;
\r
279 /* top down bitmap */
\r
280 height = (EPS_UINT32) -lpbmi->biHeight;
\r
281 lpCBuf->lpBitsOrg += lpCBuf->nextLine * ySrc;
\r
283 if (height == 0 || height < ySrc + dwHeight) {
\r
287 /* Fill Other fields */
\r
288 lpCBuf->wMode = GetCompressMode(dwMode) ;
\r
289 lpCBuf->wQuality = GetCompressQuality(dwMode) ;
\r
290 lpCBuf->lpBuffer = lpBuf ;
\r
291 lpCBuf->sizeBuffer = sizeBuf ;
\r
292 lpCBuf->bInvertX = FALSE ;
\r
294 switch (lpCBuf->wMode) {
\r
295 case EP_COMPRESS20 :
\r
296 EPS_RETURN( Compress20((COMPBUFFER20*) lpCBuf) )
\r
304 /* 24BPP Image Compress Mode 20 */
\r
305 static EPS_UINT32 Compress20(COMPBUFFER20* lpC20Buf)
\r
308 EPS_INT32 nextBand ;
\r
309 EPS_UINT32 y, yblock, ymod ;
\r
314 if (lpC20Buf->cbuf.biBitCount == 24) {
\r
317 else if (lpC20Buf->cbuf.biBitCount == 32) {
\r
324 if (lpC20Buf->cbuf.bInvertX) {
\r
326 lpSrc = lpC20Buf->cbuf.lpBitsOrg + (lpC20Buf->cbuf.dwWidth - 1) * incptr ;
\r
330 lpSrc = lpC20Buf->cbuf.lpBitsOrg ;
\r
333 if (lpC20Buf->cbuf.format == EP_RGB) {
\r
334 lpC20Buf->mode[0] = 2 ;
\r
335 lpC20Buf->mode[1] = 1 ;
\r
336 lpC20Buf->mode[2] = 0 ;
\r
339 lpC20Buf->mode[0] = 0 ;
\r
340 lpC20Buf->mode[1] = 1 ;
\r
341 lpC20Buf->mode[2] = 2 ;
\r
344 /* Make Hufman Code Table */
\r
345 MakeHufmanCodeTable(lpC20Buf->cbuf.wMode, lpC20Buf->cbuf.wQuality, &lpC20Buf->cd) ;
\r
347 /* Make Block Header */
\r
348 lpC20Buf->bh.width = ConvertEndianWord(lpC20Buf->cbuf.dwWidth) ;
\r
349 lpC20Buf->bh.bandPixel = ConvertEndianWord(BAND_PIXEL) ;
\r
352 lpC20Buf->cd.lpCurPtr = lpC20Buf->cbuf.lpBuffer ;
\r
353 lpC20Buf->cd.leftCount = lpC20Buf->cbuf.sizeBuffer ;
\r
355 yblock = lpC20Buf->cbuf.dwHeight / BAND_PIXEL ;
\r
356 ymod = lpC20Buf->cbuf.dwHeight % BAND_PIXEL ;
\r
358 nextBand = lpC20Buf->cbuf.nextLine * BAND_PIXEL ;
\r
360 lpC20Buf->bandLimit = SIZEOF_BLOCKHEADER20 + lpC20Buf->cbuf.dwWidth * BAND_PIXEL ;
\r
362 for (y = 0 ; y < yblock ; y++) {
\r
363 if (! WriteBandData20(BAND_PIXEL, incptr, lpSrc, lpC20Buf)) {
\r
366 lpSrc += nextBand ;
\r
369 lpC20Buf->bh.bandPixel = ConvertEndianWord(ymod) ;
\r
370 lpC20Buf->bandLimit = SIZEOF_BLOCKHEADER20 + lpC20Buf->cbuf.dwWidth * ymod ;
\r
372 if (! WriteBandData20((EPS_UINT16) ymod, incptr, lpSrc, lpC20Buf)) {
\r
377 if (lpC20Buf->cd.leftCount == 0) {
\r
381 EPS_RETURN( lpC20Buf->cbuf.sizeBuffer - lpC20Buf->cd.leftCount )
\r
385 static EPS_BOOL WriteBandData20(EPS_INT32 band, EPS_INT32 incptr, EPS_UINT8* lpSrc, COMPBUFFER20* lpC20Buf)
\r
387 EPS_UINT32 sizeBlockData ;
\r
388 EPS_UINT8* lpBandStart ;
\r
389 EPS_UINT32 countBandStart ;
\r
390 EPS_UINT8 *lpBand, *lpPt, *lpPrePt;
\r
398 for (i = 0 ; i <= 2 ; i++) {
\r
399 if (lpC20Buf->cd.leftCount <= SIZEOF_BLOCKHEADER20) {
\r
400 EPS_RETURN( FALSE )
\r
403 lpBandStart = lpC20Buf->cd.lpCurPtr ;
\r
404 countBandStart = lpC20Buf->cd.leftCount ;
\r
406 lpC20Buf->cd.lpCurPtr += SIZEOF_BLOCKHEADER20;
\r
407 lpC20Buf->cd.leftCount -= SIZEOF_BLOCKHEADER20;
\r
408 lpC20Buf->cd.code = 0 ;
\r
409 lpC20Buf->cd.codeBits = 0 ;
\r
411 lpBand = lpSrc + i ;
\r
415 for (x = 0 ; x < lpC20Buf->cbuf.dwWidth ; x++) {
\r
416 CodeHufmanData((EPS_UINT8) (*lpPt-left), &lpC20Buf->cd) ;
\r
421 for (j = 1 ; j < band ; j++) {
\r
423 lpBand += lpC20Buf->cbuf.nextLine ;
\r
427 for (x = 0 ; x < lpC20Buf->cbuf.dwWidth ; x++) {
\r
428 CodeHufmanData((EPS_UINT8) (*lpPt-((left+*lpPrePt)>>1)), &lpC20Buf->cd) ;
\r
431 lpPrePt += incptr ;
\r
434 if (lpC20Buf->cd.codeBits) WriteDataToBuffer(&lpC20Buf->cd) ;
\r
436 if (countBandStart <= lpC20Buf->cd.leftCount + lpC20Buf->bandLimit) {
\r
437 /* Write Block Header */
\r
438 sizeBlockData = countBandStart - lpC20Buf->cd.leftCount ;
\r
439 lpC20Buf->bh.size = ConvertEndianDWORD(sizeBlockData) ;
\r
440 lpC20Buf->bh.mode = ConvertEndianWord(MakeCompress20Mode(lpC20Buf->mode[i])) ;
\r
442 for (x = 0 ; x < SIZEOF_BLOCKHEADER20 ; x++) {
\r
443 *lpBandStart++ = GetByteBLOCKHEADER20(&lpC20Buf->bh, x);
\r
447 /* Output Un-Compress Data */
\r
448 if (countBandStart < lpC20Buf->bandLimit) {
\r
449 EPS_RETURN( FALSE )
\r
452 sizeBlockData = lpC20Buf->bandLimit ;
\r
453 lpC20Buf->bh.size = ConvertEndianDWORD(sizeBlockData) ;
\r
454 lpC20Buf->bh.mode = ConvertEndianWord(MakeUncompress20Mode(lpC20Buf->mode[i])) ;
\r
456 for (x = 0 ; x < SIZEOF_BLOCKHEADER20; x++) {
\r
457 *lpBandStart++ = GetByteBLOCKHEADER20(&lpC20Buf->bh, x);
\r
460 lpBand = lpSrc + i ;
\r
461 for (j = 0 ; j < band ; j++) {
\r
463 lpBand += lpC20Buf->cbuf.nextLine ;
\r
464 for (x = 0 ; x < lpC20Buf->cbuf.dwWidth ; x++) {
\r
465 *lpBandStart++ = *lpPt ;
\r
470 lpC20Buf->cd.lpCurPtr = lpBandStart ;
\r
471 lpC20Buf->cd.leftCount = countBandStart - lpC20Buf->bandLimit ;
\r
479 static EPS_UINT8 GetByteBLOCKHEADER20(BLOCKHEADER20 *p, EPS_INT32 n)
\r
483 case 0: b = (EPS_UINT8)(p->size) & 0x000000FF; break;
\r
484 case 1: b = (EPS_UINT8)(p->size >> 8) & 0x000000FF; break;
\r
485 case 2: b = (EPS_UINT8)(p->size >> 16) & 0x000000FF; break;
\r
486 case 3: b = (EPS_UINT8)(p->size >> 24) & 0x000000FF; break;
\r
488 case 4: b = (EPS_UINT8)(p->width) & 0x00FF; break;
\r
489 case 5: b = (EPS_UINT8)(p->width >> 8) & 0x00FF; break;
\r
491 case 6: b = (EPS_UINT8)(p->bandPixel) & 0x00FF; break;
\r
492 case 7: b = (EPS_UINT8)(p->bandPixel >> 8) & 0x00FF; break;
\r
494 case 8: b = (EPS_UINT8)(p->mode) & 0x00FF; break;
\r
495 case 9: b = (unsigned char)(p->mode >> 8) & 0x00FF; break;
\r
503 static void WriteDataToBuffer(CODINGDATA* const lpcd)
\r
505 if (lpcd->leftCount) {
\r
506 *lpcd->lpCurPtr++ = (EPS_UINT8) lpcd->code ;
\r
507 lpcd->leftCount-- ;
\r
510 lpcd->codeBits -= 8 ;
\r
514 static void CodeHufmanData(const EPS_UINT8 d, CODINGDATA* const lpcd)
\r
516 lpcd->code |= ((EPS_UINT32) lpcd->hufCode[d]) << (lpcd->codeBits) ;
\r
517 lpcd->codeBits += lpcd->hufCodeLen[d] ;
\r
519 while (lpcd->codeBits >= 8) WriteDataToBuffer(lpcd) ;
\r
523 static EPS_BOOL MakeHufmanCodeTable(EPS_UINT16 wMode, EPS_UINT16 wQuality, CODINGDATA* lpcd)
\r
526 case EP_COMPRESS20 :
\r
527 MakeHufmanTable1(HufmanDefTable2, lpcd) ;
\r
535 static void MakeHufmanTable1(const EPS_UINT16 cdn[], CODINGDATA* lpcd)
\r
538 EPS_UINT16 huf, rhuf, temp, i ;
\r
539 EPS_INT32 len, num, j ;
\r
544 for(len = 1 ; len <= 12; len++) {
\r
547 for(i = 0; i < cdn[len] ; i++) {
\r
551 for (j = 0 ; j < len ; j++) {
\r
552 rhuf = (rhuf << 1) | (temp & 1) ;
\r
558 if ((num & 0x1) == 0) j = 256 - j ;
\r
564 lpcd->hufCode[j] = rhuf ;
\r
565 lpcd->hufCodeLen[j] = (EPS_UINT8) len ;
\r
574 /*_______________________________ epson-escpage-comp.c _____________________________*/
\r
576 /*34567890123456789012345678901234567890123456789012345678901234567890123456789012345678*/
\r
577 /* 1 2 3 4 5 6 7 8 */
\r
578 /*******************************************|********************************************/
\r
579 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
\r
580 /***** End of File *** End of File *** End of File *** End of File *** End of File ******/
\r
581 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
\r