Annotation of embedaddon/php/ext/gd/libgd/gd_gd2.c, revision 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>