Annotation of embedaddon/php/ext/gd/libgd/gd_gd2.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:    * gd_gd2.c
                      3:    *
                      4:    * Implements the I/O and support for the GD2 format.
                      5:    *
                      6:    * Changing the definition of GD2_DBG (below) will cause copious messages
                      7:    * to be displayed while it processes requests.
                      8:    *
                      9:    * Designed, Written & Copyright 1999, Philip Warner.
                     10:    *
                     11:  */
                     12: 
                     13: #include <stdio.h>
                     14: #include <errno.h>
                     15: #include <math.h>
                     16: #include <string.h>
                     17: #include <stdlib.h>
                     18: #include "gd.h"
                     19: #include "gdhelpers.h"
                     20: 
                     21: #include <zlib.h>
                     22: 
                     23: #define TRUE 1
                     24: #define FALSE 0
                     25: 
                     26: /* 2.11: not part of the API, as the save routine can figure it out
                     27:  *     from im->trueColor, and the load routine doesn't need to tell
                     28:  *     the end user the saved format. NOTE: adding 2 is assumed
                     29:  *     to result in the correct format value for truecolor!
                     30: */
                     31: #define GD2_FMT_TRUECOLOR_RAW 3
                     32: #define GD2_FMT_TRUECOLOR_COMPRESSED 4
                     33: 
                     34: #define gd2_compressed(fmt) (((fmt) == GD2_FMT_COMPRESSED) || ((fmt) == GD2_FMT_TRUECOLOR_COMPRESSED))
                     35: #define gd2_truecolor(fmt) (((fmt) == GD2_FMT_TRUECOLOR_RAW) || ((fmt) == GD2_FMT_TRUECOLOR_COMPRESSED))
                     36: 
                     37: /* Use this for commenting out debug-print statements. */
                     38: /* Just use the first '#define' to allow all the prints... */
                     39: /* #define GD2_DBG(s) (s) */
                     40: #define GD2_DBG(s)
                     41: 
                     42: typedef struct
                     43: {
                     44:        int offset;
                     45:        int size;
                     46: } t_chunk_info;
                     47: 
                     48: extern int _gdGetColors(gdIOCtx * in, gdImagePtr im, int gd2xFlag);
                     49: extern void _gdPutColors(gdImagePtr im, gdIOCtx * out);
                     50: 
                     51: /* */
                     52: /* Read the extra info in the gd2 header. */
                     53: /* */
                     54: static int _gd2GetHeader(gdIOCtxPtr in, int *sx, int *sy, int *cs, int *vers, int *fmt, int *ncx, int *ncy, t_chunk_info ** chunkIdx)
                     55: {
                     56:        int i;
                     57:        int ch;
                     58:        char id[5];
                     59:        t_chunk_info *cidx;
                     60:        int sidx;
                     61:        int nc;
                     62: 
                     63:        GD2_DBG(php_gd_error("Reading gd2 header info"));
                     64: 
                     65:        for (i = 0; i < 4; i++) {
                     66:                ch = gdGetC(in);
                     67:                if (ch == EOF) {
                     68:                        goto fail1;
                     69:                }
                     70:                id[i] = ch;
                     71:        }
                     72:        id[4] = 0;
                     73: 
                     74:        GD2_DBG(php_gd_error("Got file code: %s", id));
                     75: 
                     76:        /* Equiv. of 'magick'.  */
                     77:        if (strcmp(id, GD2_ID) != 0) {
                     78:                GD2_DBG(php_gd_error("Not a valid gd2 file"));
                     79:                goto fail1;
                     80:        }
                     81: 
                     82:        /* Version */
                     83:        if (gdGetWord(vers, in) != 1) {
                     84:                goto fail1;
                     85:        }
                     86:        GD2_DBG(php_gd_error("Version: %d", *vers));
                     87: 
                     88:        if ((*vers != 1) && (*vers != 2)) {
                     89:                GD2_DBG(php_gd_error("Bad version: %d", *vers));
                     90:                goto fail1;
                     91:        }
                     92: 
                     93:        /* Image Size */
                     94:        if (!gdGetWord(sx, in)) {
                     95:                GD2_DBG(php_gd_error("Could not get x-size"));
                     96:                goto fail1;
                     97:        }
                     98:        if (!gdGetWord(sy, in)) {
                     99:                GD2_DBG(php_gd_error("Could not get y-size"));
                    100:                goto fail1;
                    101:        }
                    102:        GD2_DBG(php_gd_error("Image is %dx%d", *sx, *sy));
                    103: 
                    104:        /* Chunk Size (pixels, not bytes!) */
                    105:        if (gdGetWord(cs, in) != 1) {
                    106:                goto fail1;
                    107:        }
                    108:        GD2_DBG(php_gd_error("ChunkSize: %d", *cs));
                    109: 
                    110:        if ((*cs < GD2_CHUNKSIZE_MIN) || (*cs > GD2_CHUNKSIZE_MAX)) {
                    111:                GD2_DBG(php_gd_error("Bad chunk size: %d", *cs));
                    112:                goto fail1;
                    113:        }
                    114: 
                    115:        /* Data Format */
                    116:        if (gdGetWord(fmt, in) != 1) {
                    117:                goto fail1;
                    118:        }
                    119:        GD2_DBG(php_gd_error("Format: %d", *fmt));
                    120: 
                    121:        if ((*fmt != GD2_FMT_RAW) && (*fmt != GD2_FMT_COMPRESSED) && (*fmt != GD2_FMT_TRUECOLOR_RAW) && (*fmt != GD2_FMT_TRUECOLOR_COMPRESSED)) {
                    122:                GD2_DBG(php_gd_error("Bad data format: %d", *fmt));
                    123:                goto fail1;
                    124:        }
                    125: 
                    126:        /* # of chunks wide */
                    127:        if (gdGetWord(ncx, in) != 1) {
                    128:                goto fail1;
                    129:        }
                    130:        GD2_DBG(php_gd_error("%d Chunks Wide", *ncx));
                    131: 
                    132:        /* # of chunks high */
                    133:        if (gdGetWord(ncy, in) != 1) {
                    134:                goto fail1;
                    135:        }
                    136:        GD2_DBG(php_gd_error("%d Chunks vertically", *ncy));
                    137: 
                    138:        if (gd2_compressed(*fmt)) {
                    139:                nc = (*ncx) * (*ncy);
                    140:                GD2_DBG(php_gd_error("Reading %d chunk index entries", nc));
                    141:                sidx = sizeof(t_chunk_info) * nc;
                    142:                if (sidx <= 0) {
                    143:                        goto fail1;
                    144:                }
                    145:                cidx = gdCalloc(sidx, 1);
                    146:                for (i = 0; i < nc; i++) {
                    147:                        if (gdGetInt(&cidx[i].offset, in) != 1) {
                    148:                                goto fail1;
                    149:                        }
                    150:                        if (gdGetInt(&cidx[i].size, in) != 1) {
                    151:                                goto fail1;
                    152:                        }
                    153:                }
                    154:                *chunkIdx = cidx;
                    155:        }
                    156: 
                    157:        GD2_DBG(php_gd_error("gd2 header complete"));
                    158: 
                    159:        return 1;
                    160: 
                    161: fail1:
                    162:        return 0;
                    163: }
                    164: 
                    165: static gdImagePtr _gd2CreateFromFile (gdIOCtxPtr in, int *sx, int *sy, int *cs, int *vers, int *fmt, int *ncx, int *ncy, t_chunk_info ** cidx)
                    166: {
                    167:        gdImagePtr im;
                    168: 
                    169:        if (_gd2GetHeader (in, sx, sy, cs, vers, fmt, ncx, ncy, cidx) != 1) {
                    170:                GD2_DBG(php_gd_error("Bad GD2 header"));
                    171:                goto fail1;
                    172:        }
                    173: 
                    174:        if (gd2_truecolor(*fmt)) {
                    175:                im = gdImageCreateTrueColor(*sx, *sy);
                    176:        } else {
                    177:                im = gdImageCreate(*sx, *sy);
                    178:        }
                    179:        if (im == NULL) {
                    180:                GD2_DBG(php_gd_error("Could not create gdImage"));
                    181:                goto fail1;
                    182:        }
                    183: 
                    184:        if (!_gdGetColors(in, im, (*vers) == 2)) {
                    185:                GD2_DBG(php_gd_error("Could not read color palette"));
                    186:                goto fail2;
                    187:        }
                    188:        GD2_DBG(php_gd_error("Image palette completed: %d colours", im->colorsTotal));
                    189: 
                    190:        return im;
                    191: 
                    192: fail2:
                    193:        gdImageDestroy(im);
                    194:        return 0;
                    195: 
                    196: fail1:
                    197:        return 0;
                    198: }
                    199: 
                    200: static int _gd2ReadChunk (int offset, char *compBuf, int compSize, char *chunkBuf, uLongf * chunkLen, gdIOCtx * in)
                    201: {
                    202:        int zerr;
                    203: 
                    204:        if (gdTell(in) != offset) {
                    205:                GD2_DBG(php_gd_error("Positioning in file to %d", offset));
                    206:                gdSeek(in, offset);
                    207:        } else {
                    208:                GD2_DBG(php_gd_error("Already Positioned in file to %d", offset));
                    209:        }
                    210: 
                    211:        /* Read and uncompress an entire chunk. */
                    212:        GD2_DBG(php_gd_error("Reading file"));
                    213:        if (gdGetBuf(compBuf, compSize, in) != compSize) {
                    214:                return FALSE;
                    215:        }
                    216:        GD2_DBG(php_gd_error("Got %d bytes. Uncompressing into buffer of %d bytes", compSize, (int)*chunkLen));
                    217:        zerr = uncompress((unsigned char *) chunkBuf, chunkLen, (unsigned char *) compBuf, compSize);
                    218:        if (zerr != Z_OK) {
                    219:                GD2_DBG(php_gd_error("Error %d from uncompress", zerr));
                    220:                return FALSE;
                    221:        }
                    222:        GD2_DBG(php_gd_error("Got chunk"));
                    223: 
                    224:        return TRUE;
                    225: }
                    226: 
                    227: gdImagePtr gdImageCreateFromGd2 (FILE * inFile)
                    228: {
                    229:        gdIOCtx *in = gdNewFileCtx(inFile);
                    230:        gdImagePtr im;
                    231: 
                    232:        im = gdImageCreateFromGd2Ctx(in);
                    233: 
                    234:        in->gd_free(in);
                    235: 
                    236:        return im;
                    237: }
                    238: 
                    239: gdImagePtr gdImageCreateFromGd2Ptr (int size, void *data)
                    240: {
                    241:        gdImagePtr im;
                    242:        gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
                    243:        im = gdImageCreateFromGd2Ctx(in);
                    244:        in->gd_free(in);
                    245: 
                    246:        return im;
                    247: }
                    248: 
                    249: gdImagePtr gdImageCreateFromGd2Ctx (gdIOCtxPtr in)
                    250: {
                    251:        int sx, sy;
                    252:        int i;
                    253:        int ncx, ncy, nc, cs, cx, cy;
                    254:        int x, y, ylo, yhi, xlo, xhi;
                    255:        int vers, fmt;
                    256:        t_chunk_info *chunkIdx = NULL;  /* So we can gdFree it with impunity. */
                    257:        unsigned char *chunkBuf = NULL; /* So we can gdFree it with impunity. */
                    258:        int chunkNum = 0;
                    259:        int chunkMax = 0;
                    260:        uLongf chunkLen;
                    261:        int chunkPos = 0;
                    262:        int compMax = 0;
                    263:        int bytesPerPixel;
                    264:        char *compBuf = NULL;           /* So we can gdFree it with impunity. */
                    265: 
                    266:        gdImagePtr im;
                    267: 
                    268:        /* Get the header */
                    269:        if (!(im = _gd2CreateFromFile(in, &sx, &sy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx))) {
                    270:                 return 0;
                    271:        }
                    272: 
                    273:        bytesPerPixel = im->trueColor ? 4 : 1;
                    274:        nc = ncx * ncy;
                    275: 
                    276:        if (gd2_compressed(fmt)) {
                    277:                /* Find the maximum compressed chunk size. */
                    278:                compMax = 0;
                    279:                for (i = 0; (i < nc); i++) {
                    280:                        if (chunkIdx[i].size > compMax) {
                    281:                                compMax = chunkIdx[i].size;
                    282:                        }
                    283:                }
                    284:                compMax++;
                    285: 
                    286:                /* Allocate buffers */
                    287:                chunkMax = cs * bytesPerPixel * cs;
                    288:                if (chunkMax <= 0) {
                    289:                        return 0;
                    290:                }
                    291:                chunkBuf = gdCalloc(chunkMax, 1);
                    292:                compBuf = gdCalloc(compMax, 1);
                    293: 
                    294:                GD2_DBG(php_gd_error("Largest compressed chunk is %d bytes", compMax));
                    295:        }
                    296: 
                    297:        /* Read the data... */
                    298:        for (cy = 0; (cy < ncy); cy++) {
                    299:                for (cx = 0; (cx < ncx); cx++) {
                    300:                        ylo = cy * cs;
                    301:                        yhi = ylo + cs;
                    302:                        if (yhi > im->sy) {
                    303:                                yhi = im->sy;
                    304:                        }
                    305: 
                    306:                        GD2_DBG(php_gd_error("Processing Chunk %d (%d, %d), y from %d to %d", chunkNum, cx, cy, ylo, yhi));
                    307: 
                    308:                        if (gd2_compressed(fmt)) {
                    309:                                chunkLen = chunkMax;
                    310: 
                    311:                                if (!_gd2ReadChunk(chunkIdx[chunkNum].offset, compBuf, chunkIdx[chunkNum].size, (char *) chunkBuf, &chunkLen, in)) {
                    312:                                        GD2_DBG(php_gd_error("Error reading comproessed chunk"));
                    313:                                        goto fail2;
                    314:                                }
                    315: 
                    316:                                chunkPos = 0;
                    317:                        }
                    318: 
                    319:                        for (y = ylo; (y < yhi); y++) {
                    320:                                xlo = cx * cs;
                    321:                                xhi = xlo + cs;
                    322:                                if (xhi > im->sx) {
                    323:                                        xhi = im->sx;
                    324:                                }
                    325: 
                    326:                                if (!gd2_compressed(fmt)) {
                    327:                                        for (x = xlo; x < xhi; x++) {
                    328:                                                if (im->trueColor) {
                    329:                                                        if (!gdGetInt(&im->tpixels[y][x], in)) {
                    330:                                                                im->tpixels[y][x] = 0;
                    331:                                                        }
                    332:                                                } else {
                    333:                                                        int ch;
                    334:                                                        if (!gdGetByte(&ch, in)) {
                    335:                                                                ch = 0;
                    336:                                                        }
                    337:                                                        im->pixels[y][x] = ch;
                    338:                                                }
                    339:                                        }
                    340:                                } else {
                    341:                                        for (x = xlo; x < xhi; x++) {
                    342:                                                if (im->trueColor) {
                    343:                                                        /* 2.0.1: work around a gcc bug by being verbose. TBB */
                    344:                                                        int a = chunkBuf[chunkPos++] << 24;
                    345:                                                        int r = chunkBuf[chunkPos++] << 16;
                    346:                                                        int g = chunkBuf[chunkPos++] << 8;
                    347:                                                        int b = chunkBuf[chunkPos++];
                    348:                                                        im->tpixels[y][x] = a + r + g + b;
                    349:                                                } else {
                    350:                                                        im->pixels[y][x] = chunkBuf[chunkPos++];
                    351:                                                }
                    352:                                        }
                    353:                                }
                    354:                        }
                    355:                        chunkNum++;
                    356:                }
                    357:        }
                    358: 
                    359:        GD2_DBG(php_gd_error("Freeing memory"));
                    360: 
                    361:        if (chunkBuf) {
                    362:                gdFree(chunkBuf);
                    363:        }
                    364:        if (compBuf) {
                    365:                gdFree(compBuf);
                    366:        }
                    367:        if (chunkIdx) {
                    368:                gdFree(chunkIdx);
                    369:        }
                    370: 
                    371:        GD2_DBG(php_gd_error("Done"));
                    372: 
                    373:        return im;
                    374: 
                    375: fail2:
                    376:        gdImageDestroy(im);
                    377:        if (chunkBuf) {
                    378:                gdFree(chunkBuf);
                    379:        }
                    380:        if (compBuf) {
                    381:                gdFree(compBuf);
                    382:        }
                    383:        if (chunkIdx) {
                    384:                gdFree(chunkIdx);
                    385:        }
                    386: 
                    387:        return 0;
                    388: }
                    389: 
                    390: gdImagePtr gdImageCreateFromGd2PartPtr (int size, void *data, int srcx, int srcy, int w, int h)
                    391: {
                    392:        gdImagePtr im;
                    393:        gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
                    394:        im = gdImageCreateFromGd2PartCtx(in, srcx, srcy, w, h);
                    395:        in->gd_free(in);
                    396: 
                    397:        return im;
                    398: }
                    399: 
                    400: gdImagePtr gdImageCreateFromGd2Part (FILE * inFile, int srcx, int srcy, int w, int h)
                    401: {
                    402:        gdImagePtr im;
                    403:        gdIOCtx *in = gdNewFileCtx(inFile);
                    404: 
                    405:        im = gdImageCreateFromGd2PartCtx(in, srcx, srcy, w, h);
                    406: 
                    407:        in->gd_free(in);
                    408: 
                    409:        return im;
                    410: }
                    411: 
                    412: gdImagePtr gdImageCreateFromGd2PartCtx (gdIOCtx * in, int srcx, int srcy, int w, int h)
                    413: {
                    414:        int scx, scy, ecx, ecy, fsx, fsy;
                    415:        int nc, ncx, ncy, cs, cx, cy;
                    416:        int x, y, ylo, yhi, xlo, xhi;
                    417:        int dstart, dpos;
                    418:        int i;
                    419:        /* 2.0.12: unsigned is correct; fixes problems with color munging. Thanks to Steven Brown. */
                    420:        unsigned int ch;
                    421:        int vers, fmt;
                    422:        t_chunk_info *chunkIdx = NULL;
                    423:        unsigned char *chunkBuf = NULL;
                    424:        int chunkNum;
                    425:        int chunkMax = 0;
                    426:        uLongf chunkLen;
                    427:        int chunkPos = 0;
                    428:        int compMax;
                    429:        char *compBuf = NULL;
                    430: 
                    431:        gdImagePtr im;
                    432: 
                    433:        if (w<1 || h <1) {
                    434:                return 0;
                    435:        }
                    436: 
                    437:        /* The next few lines are basically copied from gd2CreateFromFile
                    438:         * we change the file size, so don't want to use the code directly.
                    439:         * but we do need to know the file size.
                    440:         */
                    441:        if (_gd2GetHeader(in, &fsx, &fsy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx) != 1) {
                    442:                goto fail1;
                    443:        }
                    444: 
                    445:        GD2_DBG(php_gd_error("File size is %dx%d", fsx, fsy));
                    446: 
                    447:        /* This is the difference - make a file based on size of chunks. */
                    448:        if (gd2_truecolor(fmt)) {
                    449:                im = gdImageCreateTrueColor(w, h);
                    450:        } else {
                    451:                im = gdImageCreate(w, h);
                    452:        }
                    453:        if (im == NULL) {
                    454:                goto fail1;
                    455:        }
                    456: 
                    457:        if (!_gdGetColors(in, im, vers == 2)) {
                    458:                goto fail2;
                    459:        }
                    460:        GD2_DBG(php_gd_error("Image palette completed: %d colours", im->colorsTotal));
                    461: 
                    462:        /* Process the header info */
                    463:        nc = ncx * ncy;
                    464: 
                    465:        if (gd2_compressed(fmt)) {
                    466:                /* Find the maximum compressed chunk size. */
                    467:                compMax = 0;
                    468:                for (i = 0; (i < nc); i++) {
                    469:                        if (chunkIdx[i].size > compMax) {
                    470:                                compMax = chunkIdx[i].size;
                    471:                        }
                    472:                }
                    473:                compMax++;
                    474: 
                    475:                if (im->trueColor) {
                    476:                        chunkMax = cs * cs * 4;
                    477:                } else {
                    478:                        chunkMax = cs * cs;
                    479:                }
                    480:                if (chunkMax <= 0) {
                    481:                        goto fail2;
                    482:                }
                    483: 
                    484:                chunkBuf = gdCalloc(chunkMax, 1);
                    485:                compBuf = gdCalloc(compMax, 1);
                    486:        }
                    487: 
                    488:        /* Work out start/end chunks */
                    489:        scx = srcx / cs;
                    490:        scy = srcy / cs;
                    491:        if (scx < 0) {
                    492:                scx = 0;
                    493:        }
                    494:        if (scy < 0) {
                    495:                scy = 0;
                    496:        }
                    497: 
                    498:        ecx = (srcx + w) / cs;
                    499:        ecy = (srcy + h) / cs;
                    500:        if (ecx >= ncx) {
                    501:                ecx = ncx - 1;
                    502:        }
                    503:        if (ecy >= ncy) {
                    504:                ecy = ncy - 1;
                    505:        }
                    506: 
                    507:        /* Remember file position of image data. */
                    508:        dstart = gdTell(in);
                    509:        GD2_DBG(php_gd_error("Data starts at %d", dstart));
                    510: 
                    511:        /* Loop through the chunks. */
                    512:        for (cy = scy; (cy <= ecy); cy++) {
                    513:                ylo = cy * cs;
                    514:                yhi = ylo + cs;
                    515:                if (yhi > fsy) {
                    516:                        yhi = fsy;
                    517:                }
                    518: 
                    519:                for (cx = scx; cx <= ecx; cx++) {
                    520: 
                    521:                        xlo = cx * cs;
                    522:                        xhi = xlo + cs;
                    523:                        if (xhi > fsx) {
                    524:                                xhi = fsx;
                    525:                        }
                    526: 
                    527:                        GD2_DBG(php_gd_error("Processing Chunk (%d, %d), from %d to %d", cx, cy, ylo, yhi));
                    528: 
                    529:                        if (!gd2_compressed(fmt)) {
                    530:                                GD2_DBG(php_gd_error("Using raw format data"));
                    531:                                if (im->trueColor) {
                    532:                                        dpos = (cy * (cs * fsx) * 4 + cx * cs * (yhi - ylo) * 4) + dstart;
                    533:                                } else {
                    534:                                        dpos = cy * (cs * fsx) + cx * cs * (yhi - ylo) + dstart;
                    535:                                }
                    536: 
                    537:                                /* gd 2.0.11: gdSeek returns TRUE on success, not 0. Longstanding bug. 01/16/03 */
                    538:                                if (!gdSeek(in, dpos)) {
                    539:                                        php_gd_error_ex(E_WARNING, "Error from seek: %d", errno);
                    540:                                        goto fail2;
                    541:                                }
                    542:                                GD2_DBG(php_gd_error("Reading (%d, %d) from position %d", cx, cy, dpos - dstart));
                    543:                        } else {
                    544:                                chunkNum = cx + cy * ncx;
                    545: 
                    546:                                chunkLen = chunkMax;
                    547:                                if (!_gd2ReadChunk (chunkIdx[chunkNum].offset, compBuf, chunkIdx[chunkNum].size, (char *)chunkBuf, &chunkLen, in)) {
                    548:                                        php_gd_error("Error reading comproessed chunk");
                    549:                                        goto fail2;
                    550:                                }
                    551:                                chunkPos = 0;
                    552:                                GD2_DBG(php_gd_error("Reading (%d, %d) from chunk %d", cx, cy, chunkNum));
                    553:                        }
                    554: 
                    555:                        GD2_DBG(php_gd_error("   into (%d, %d) - (%d, %d)", xlo, ylo, xhi, yhi));
                    556: 
                    557:                        for (y = ylo; (y < yhi); y++) {
                    558:                                for (x = xlo; x < xhi; x++) {
                    559:                                        if (!gd2_compressed(fmt)) {
                    560:                                                if (im->trueColor) {
                    561:                                                        if (!gdGetInt((int *)&ch, in)) {
                    562:                                                                ch = 0;
                    563:                                                        }
                    564:                                                } else {
                    565:                                                        ch = gdGetC(in);
                    566:                                                        if ((int)ch == EOF) {
                    567:                                                                ch = 0;
                    568:                                                        }
                    569:                                                }
                    570:                                        } else {
                    571:                                                if (im->trueColor) {
                    572:                                                        ch = chunkBuf[chunkPos++];
                    573:                                                        ch = (ch << 8) + chunkBuf[chunkPos++];
                    574:                                                        ch = (ch << 8) + chunkBuf[chunkPos++];
                    575:                                                        ch = (ch << 8) + chunkBuf[chunkPos++];
                    576:                                                } else {
                    577:                                                        ch = chunkBuf[chunkPos++];
                    578:                                                }
                    579:                                        }
                    580: 
                    581:                                        /* Only use a point that is in the image. */
                    582:                                        if ((x >= srcx) && (x < (srcx + w)) && (x < fsx) && (x >= 0) && (y >= srcy) && (y < (srcy + h)) && (y < fsy) && (y >= 0)) {
                    583:                                                if (im->trueColor) {
                    584:                                                        im->tpixels[y - srcy][x - srcx] = ch;
                    585:                                                } else {
                    586:                                                        im->pixels[y - srcy][x - srcx] = ch;
                    587:                                                }
                    588:                                        }
                    589:                                }
                    590:                        }
                    591:                }
                    592:        }
                    593: 
                    594:        if (chunkBuf) {
                    595:                gdFree(chunkBuf);
                    596:        }
                    597:        if (compBuf) {
                    598:                gdFree(compBuf);
                    599:        }
                    600:        if (chunkIdx) {
                    601:                gdFree(chunkIdx);
                    602:        }
                    603: 
                    604:        return im;
                    605: 
                    606: fail2:
                    607:        gdImageDestroy(im);
                    608: fail1:
                    609:        if (chunkBuf) {
                    610:                gdFree(chunkBuf);
                    611:        }
                    612:        if (compBuf) {
                    613:                gdFree(compBuf);
                    614:        }
                    615:        if (chunkIdx) {
                    616:                gdFree(chunkIdx);
                    617:        }
                    618: 
                    619:        return 0;
                    620: }
                    621: 
                    622: static void _gd2PutHeader (gdImagePtr im, gdIOCtx * out, int cs, int fmt, int cx, int cy)
                    623: {
                    624:        int i;
                    625: 
                    626:        /* Send the gd2 id, to verify file format. */
                    627:        for (i = 0; i < 4; i++) {
                    628:                gdPutC((unsigned char) (GD2_ID[i]), out);
                    629:        }
                    630: 
                    631:        /* We put the version info first, so future versions can easily change header info. */
                    632: 
                    633:        gdPutWord(GD2_VERS, out);
                    634:        gdPutWord(im->sx, out);
                    635:        gdPutWord(im->sy, out);
                    636:        gdPutWord(cs, out);
                    637:        gdPutWord(fmt, out);
                    638:        gdPutWord(cx, out);
                    639:        gdPutWord(cy, out);
                    640: }
                    641: 
                    642: static void _gdImageGd2 (gdImagePtr im, gdIOCtx * out, int cs, int fmt)
                    643: {
                    644:        int ncx, ncy, cx, cy;
                    645:        int x, y, ylo, yhi, xlo, xhi;
                    646:        int chunkLen;
                    647:        int chunkNum = 0;
                    648:        char *chunkData = NULL; /* So we can gdFree it with impunity. */
                    649:        char *compData = NULL;  /* So we can gdFree it with impunity. */
                    650:        uLongf compLen;
                    651:        int idxPos = 0;
                    652:        int idxSize;
                    653:        t_chunk_info *chunkIdx = NULL; /* So we can gdFree it with impunity. */
                    654:        int posSave;
                    655:        int bytesPerPixel = im->trueColor ? 4 : 1;
                    656:        int compMax = 0;
                    657: 
                    658:        /* Force fmt to a valid value since we don't return anything. */
                    659:        if ((fmt != GD2_FMT_RAW) && (fmt != GD2_FMT_COMPRESSED)) {
                    660:                fmt = im->trueColor ? GD2_FMT_TRUECOLOR_COMPRESSED : GD2_FMT_COMPRESSED;
                    661:        }
                    662:        if (im->trueColor) {
                    663:                fmt += 2;
                    664:        }
                    665:        /* Make sure chunk size is valid. These are arbitrary values; 64 because it seems
                    666:         * a little silly to expect performance improvements on a 64x64 bit scale, and
                    667:         * 4096 because we buffer one chunk, and a 16MB buffer seems a little large - it may be
                    668:         * OK for one user, but for another to read it, they require the buffer.
                    669:         */
                    670:        if (cs == 0) {
                    671:                cs = GD2_CHUNKSIZE;
                    672:        } else if (cs < GD2_CHUNKSIZE_MIN) {
                    673:                cs = GD2_CHUNKSIZE_MIN;
                    674:        } else if (cs > GD2_CHUNKSIZE_MAX) {
                    675:                cs = GD2_CHUNKSIZE_MAX;
                    676:        }
                    677: 
                    678:        /* Work out number of chunks. */
                    679:        ncx = im->sx / cs + 1;
                    680:        ncy = im->sy / cs + 1;
                    681: 
                    682:        /* Write the standard header. */
                    683:        _gd2PutHeader (im, out, cs, fmt, ncx, ncy);
                    684: 
                    685:        if (gd2_compressed(fmt)) {
                    686:                /* Work out size of buffer for compressed data, If CHUNKSIZE is large,
                    687:                 * then these will be large!
                    688:                 */
                    689: 
                    690:                /* The zlib notes say output buffer size should be (input size) * 1.01 * 12
                    691:                 * - we'll use 1.02 to be paranoid.
                    692:                 */
                    693:                compMax = (int)(cs * bytesPerPixel * cs * 1.02f) + 12;
                    694: 
                    695:                /* Allocate the buffers.  */
                    696:                chunkData = safe_emalloc(cs * bytesPerPixel, cs, 0);
                    697:                memset(chunkData, 0, cs * bytesPerPixel * cs);
                    698:                if (compMax <= 0) {
                    699:                        goto fail;
                    700:                }
                    701:                compData = gdCalloc(compMax, 1);
                    702: 
                    703:                /* Save the file position of chunk index, and allocate enough space for
                    704:                 * each chunk_info block .
                    705:                 */
                    706:                idxPos = gdTell(out);
                    707:                idxSize = ncx * ncy * sizeof(t_chunk_info);
                    708:                GD2_DBG(php_gd_error("Index size is %d", idxSize));
                    709:                gdSeek(out, idxPos + idxSize);
                    710: 
                    711:                chunkIdx = safe_emalloc(idxSize, sizeof(t_chunk_info), 0);
                    712:                memset(chunkIdx, 0, idxSize * sizeof(t_chunk_info));
                    713:        }
                    714: 
                    715:        _gdPutColors (im, out);
                    716: 
                    717:        GD2_DBG(php_gd_error("Size: %dx%d", im->sx, im->sy));
                    718:        GD2_DBG(php_gd_error("Chunks: %dx%d", ncx, ncy));
                    719: 
                    720:        for (cy = 0; (cy < ncy); cy++) {
                    721:                for (cx = 0; (cx < ncx); cx++) {
                    722:                        ylo = cy * cs;
                    723:                        yhi = ylo + cs;
                    724:                        if (yhi > im->sy) {
                    725:                                yhi = im->sy;
                    726:                        }
                    727: 
                    728:                        GD2_DBG(php_gd_error("Processing Chunk (%dx%d), y from %d to %d", cx, cy, ylo, yhi));
                    729:                        chunkLen = 0;
                    730:                        for (y = ylo; (y < yhi); y++) {
                    731:                                GD2_DBG(php_gd_error("y=%d: ",y));
                    732:                                xlo = cx * cs;
                    733:                                xhi = xlo + cs;
                    734:                                if (xhi > im->sx) {
                    735:                                        xhi = im->sx;
                    736:                                }
                    737: 
                    738:                                if (gd2_compressed(fmt)) {
                    739:                                        for (x = xlo; x < xhi; x++) {
                    740:                                                GD2_DBG(php_gd_error("%d...",x));
                    741:                                                if (im->trueColor) {
                    742:                                                        int p = im->tpixels[y][x];
                    743:                                                        chunkData[chunkLen++] = gdTrueColorGetAlpha(p);
                    744:                                                        chunkData[chunkLen++] = gdTrueColorGetRed(p);
                    745:                                                        chunkData[chunkLen++] = gdTrueColorGetGreen(p);
                    746:                                                        chunkData[chunkLen++] = gdTrueColorGetBlue(p);
                    747:                                                } else {
                    748:                                                        chunkData[chunkLen++] = im->pixels[y][x];
                    749:                                                }
                    750:                                        }
                    751:                                } else {
                    752:                                        for (x = xlo; x < xhi; x++) {
                    753:                                                GD2_DBG(php_gd_error("%d, ",x));
                    754: 
                    755:                                                if (im->trueColor) {
                    756:                                                        gdPutInt(im->tpixels[y][x], out);
                    757:                                                } else {
                    758:                                                        gdPutC((unsigned char) im->pixels[y][x], out);
                    759:                                                }
                    760:                                        }
                    761:                                }
                    762:                                GD2_DBG(php_gd_error("y=%d done.",y));
                    763:                        }
                    764: 
                    765:                        if (gd2_compressed(fmt)) {
                    766:                                compLen = compMax;
                    767:                                if (compress((unsigned char *) &compData[0], &compLen, (unsigned char *) &chunkData[0], chunkLen) != Z_OK) {
                    768:                                        php_gd_error("Error from compressing");
                    769:                                } else {
                    770:                                        chunkIdx[chunkNum].offset = gdTell(out);
                    771:                                        chunkIdx[chunkNum++].size = compLen;
                    772:                                        GD2_DBG(php_gd_error("Chunk %d size %d offset %d", chunkNum, chunkIdx[chunkNum - 1].size, chunkIdx[chunkNum - 1].offset));
                    773: 
                    774:                                        if (gdPutBuf (compData, compLen, out) <= 0) {
                    775:                                                /* Any alternate suggestions for handling this? */
                    776:                                                php_gd_error_ex(E_WARNING, "Error %d on write", errno);
                    777:                                        }
                    778:                                }
                    779:                        }
                    780:                }
                    781:        }
                    782: 
                    783:        if (gd2_compressed(fmt)) {
                    784:                /* Save the position, write the index, restore position (paranoia). */
                    785:                GD2_DBG(php_gd_error("Seeking %d to write index", idxPos));
                    786:                posSave = gdTell(out);
                    787:                gdSeek(out, idxPos);
                    788:                GD2_DBG(php_gd_error("Writing index"));
                    789:                for (x = 0; x < chunkNum; x++) {
                    790:                        GD2_DBG(php_gd_error("Chunk %d size %d offset %d", x, chunkIdx[x].size, chunkIdx[x].offset));
                    791:                        gdPutInt(chunkIdx[x].offset, out);
                    792:                        gdPutInt(chunkIdx[x].size, out);
                    793:                }
                    794:                gdSeek(out, posSave);
                    795:        }
                    796: fail:
                    797:        GD2_DBG(php_gd_error("Freeing memory"));
                    798:        if (chunkData) {
                    799:                gdFree(chunkData);
                    800:        }
                    801:        if (compData) {
                    802:                gdFree(compData);
                    803:        }
                    804:        if (chunkIdx) {
                    805:                gdFree(chunkIdx);
                    806:        }
                    807:        GD2_DBG(php_gd_error("Done"));
                    808: }
                    809: 
                    810: void gdImageGd2 (gdImagePtr im, FILE * outFile, int cs, int fmt)
                    811: {
                    812:        gdIOCtx *out = gdNewFileCtx(outFile);
                    813: 
                    814:        _gdImageGd2(im, out, cs, fmt);
                    815: 
                    816:        out->gd_free(out);
                    817: }
                    818: 
                    819: void *gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size)
                    820: {
                    821:        void *rv;
                    822:        gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
                    823: 
                    824:        _gdImageGd2(im, out, cs, fmt);
                    825:        rv = gdDPExtractData(out, size);
                    826:        out->gd_free(out);
                    827: 
                    828:        return rv;
                    829: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>