/*! * pixResizeImageData() * * Input: pixd (gets new uninitialized buffer for image data) * pixs (determines the size of the buffer; not changed) * Return: 0 if OK, 1 on error * * Notes: * (1) This removes any existing image data from pixd and * allocates an uninitialized buffer that will hold the * amount of image data that is in pixs. */ l_int32 pixResizeImageData(PIX *pixd, PIX *pixs) { l_int32 w, h, d, wpl, bytes; l_uint32 *data; PROCNAME("pixResizeImageData"); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (!pixd) return ERROR_INT("pixd not defined", procName, 1); if (pixSizesEqual(pixs, pixd)) /* nothing to do */ return 0; pixGetDimensions(pixs, &w, &h, &d); wpl = pixGetWpl(pixs); pixSetWidth(pixd, w); pixSetHeight(pixd, h); pixSetDepth(pixd, d); pixSetWpl(pixd, wpl); bytes = 4 * wpl * h; pixFreeData(pixd); /* free any existing image data */ if ((data = (l_uint32 *)pix_malloc(bytes)) == NULL) return ERROR_INT("pix_malloc fail for data", procName, 1); pixSetData(pixd, data); return 0; }
/*! * pixExtractData() * * Notes: * (1) This extracts the pix image data for use in another context. * The caller still needs to use pixDestroy() on the input pix. * (2) If refcount == 1, the data is extracted and the * pix->data ptr is set to NULL. * (3) If refcount > 1, this simply returns a copy of the data, * using the pix allocator, and leaving the input pix unchanged. */ l_uint32 * pixExtractData(PIX *pixs) { l_int32 count, bytes; l_uint32 *data, *datas; PROCNAME("pixExtractData"); if (!pixs) return (l_uint32 *)ERROR_PTR("pixs not defined", procName, NULL); count = pixGetRefcount(pixs); if (count == 1) { /* extract */ data = pixGetData(pixs); pixSetData(pixs, NULL); } else { /* refcount > 1; copy */ bytes = 4 * pixGetWpl(pixs) * pixGetHeight(pixs); datas = pixGetData(pixs); if ((data = (l_uint32 *)pix_malloc(bytes)) == NULL) return (l_uint32 *)ERROR_PTR("data not made", procName, NULL); memcpy((char *)data, (char *)datas, bytes); } return data; }
/*! * pixTransferAllData() * * Input: pixd (must be different from pixs) * &pixs (will be nulled if refcount goes to 0) * copytext (1 to copy the text field; 0 to skip) * copyformat (1 to copy the informat field; 0 to skip) * Return: 0 if OK, 1 on error * * Notes: * (1) This does a complete data transfer from pixs to pixd, * followed by the destruction of pixs (refcount permitting). * (2) If the refcount of pixs is 1, pixs is destroyed. Otherwise, * the data in pixs is copied (rather than transferred) to pixd. * (3) This operation, like all others with a pre-existing pixd, * will side-effect any existing clones of pixd. The pixd * refcount does not change. * (4) When might you use this? Suppose you have an in-place Pix * function (returning void) with the typical signature: * void function-inplace(PIX *pix, ...) * where "..." are non-pointer input parameters, and suppose * further that you sometimes want to return an arbitrary Pix * in place of the input Pix. There are two ways you can do this: * (a) The straightforward way is to change the function * signature to take the address of the Pix ptr: * void function-inplace(PIX **ppix, ...) { * PIX *pixt = function-makenew(*ppix); * pixDestroy(ppix); * *ppix = pixt; * return; * } * Here, the input and returned pix are different, as viewed * by the calling function, and the inplace function is * expected to destroy the input pix to avoid a memory leak. * (b) Keep the signature the same and use pixTransferAllData() * to return the new Pix in the input Pix struct: * void function-inplace(PIX *pix, ...) { * PIX *pixt = function-makenew(pix); * pixTransferAllData(pix, &pixt); // pixt is destroyed * return; * } * Here, the input and returned pix are the same, as viewed * by the calling function, and the inplace function must * never destroy the input pix, because the calling function * maintains an unchanged handle to it. */ l_int32 pixTransferAllData(PIX *pixd, PIX **ppixs, l_int32 copytext, l_int32 copyformat) { l_int32 nbytes; PIX *pixs; PROCNAME("pixTransferAllData"); if (!ppixs) return ERROR_INT("&pixs not defined", procName, 1); if ((pixs = *ppixs) == NULL) return ERROR_INT("pixs not defined", procName, 1); if (!pixd) return ERROR_INT("pixd not defined", procName, 1); if (pixs == pixd) /* no-op */ return ERROR_INT("pixd == pixs", procName, 1); if (pixGetRefcount(pixs) == 1) { /* transfer the data, cmap, text */ pixFreeData(pixd); /* dealloc any existing data */ pixSetData(pixd, pixGetData(pixs)); /* transfer new data from pixs */ pixs->data = NULL; /* pixs no longer owns data */ pixSetColormap(pixd, pixGetColormap(pixs)); /* frees old; sets new */ pixs->colormap = NULL; /* pixs no longer owns colormap */ if (copytext) { pixSetText(pixd, pixGetText(pixs)); pixSetText(pixs, NULL); } } else { /* preserve pixs by making a copy of the data, cmap, text */ pixResizeImageData(pixd, pixs); nbytes = 4 * pixGetWpl(pixs) * pixGetHeight(pixs); memcpy((char *)pixGetData(pixd), (char *)pixGetData(pixs), nbytes); pixCopyColormap(pixd, pixs); if (copytext) pixCopyText(pixd, pixs); } pixCopyResolution(pixd, pixs); pixCopyDimensions(pixd, pixs); if (copyformat) pixCopyInputFormat(pixd, pixs); /* This will destroy pixs if data was transferred; * otherwise, it just decrements its refcount. */ pixDestroy(ppixs); return 0; }
/*! * pixCreateNoInit() * * Input: width, height, depth * Return: pixd (with data allocated but not initialized), * or null on error * * Notes: * (1) Must set pad bits to avoid reading unitialized data, because * some optimized routines (e.g., pixConnComp()) read from pad bits. */ PIX * pixCreateNoInit(l_int32 width, l_int32 height, l_int32 depth) { l_int32 wpl; PIX *pixd; l_uint32 *data; PROCNAME("pixCreateNoInit"); pixd = pixCreateHeader(width, height, depth); if (!pixd) return NULL; wpl = pixGetWpl(pixd); if ((data = (l_uint32 *)pix_malloc(4 * wpl * height)) == NULL) return (PIX *)ERROR_PTR("pix_malloc fail for data", procName, NULL); pixSetData(pixd, data); pixSetPadBits(pixd, 0); return pixd; }
main(int argc, char **argv) { l_int32 error; l_uint32 *data; PIX *pix1, *pix2, *pix3, *pix1c, *pix2c, *pix1t, *pix2t, *pixd; PIXA *pixa; static char mainName[] = "pixmem_reg"; error = 0; pixa = pixaCreate(0); /* Copy with internal resizing: onto a cmapped image */ pix1 = pixRead("weasel4.16c.png"); pix2 = pixRead("feyn-fract.tif"); pix3 = pixRead("lucasta.150.jpg"); fprintf(stderr, "before copy 2 --> 3\n"); pixCopy(pix3, pix2); Compare(pix2, pix3, &error); pixSaveTiled(pix3, pixa, 4, 1, 30, 32); fprintf(stderr, "before copy 3 --> 1\n"); pixCopy(pix1, pix3); Compare(pix2, pix1, &error); pixSaveTiled(pix1, pixa, 4, 0, 30, 32); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); /* Copy with internal resizing: from a cmapped image */ pix1 = pixRead("weasel4.16c.png"); pix2 = pixRead("feyn-fract.tif"); pix3 = pixRead("lucasta.150.jpg"); fprintf(stderr, "before copy 1 --> 2\n"); pixCopy(pix2, pix1); Compare(pix2, pix1, &error); pixSaveTiled(pix2, pixa, 1, 1, 30, 32); fprintf(stderr, "before copy 2 --> 3\n"); pixCopy(pix3, pix2); Compare(pix3, pix2, &error); pixSaveTiled(pix3, pixa, 1, 0, 30, 32); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); /* Transfer of data pixs --> pixd, when pixs is not cloned. * pixs is destroyed. */ pix1 = pixRead("weasel4.16c.png"); pix2 = pixRead("feyn-fract.tif"); pix3 = pixRead("lucasta.150.jpg"); pix1c = pixCopy(NULL, pix1); fprintf(stderr, "before transfer 1 --> 2\n"); pixTransferAllData(pix2, &pix1, 0, 0); Compare(pix2, pix1c, &error); pixSaveTiled(pix2, pixa, 1, 1, 30, 32); fprintf(stderr, "before transfer 2 --> 3\n"); pixTransferAllData(pix3, &pix2, 0, 0); Compare(pix3, pix1c, &error); pixSaveTiled(pix3, pixa, 1, 0, 30, 32); pixDestroy(&pix1c); pixDestroy(&pix3); /* Another transfer of data pixs --> pixd, when pixs is not cloned. * pixs is destroyed. */ pix1 = pixRead("weasel4.16c.png"); pix2 = pixRead("feyn-fract.tif"); pix3 = pixRead("lucasta.150.jpg"); pix1c = pixCopy(NULL, pix1); pix2c = pixCopy(NULL, pix2); fprintf(stderr, "before copy transfer 1 --> 2\n"); pixTransferAllData(pix2, &pix1c, 0, 0); Compare(pix2, pix1, &error); pixSaveTiled(pix2, pixa, 1, 0, 30, 32); fprintf(stderr, "before copy transfer 2 --> 3\n"); pixTransferAllData(pix3, &pix2, 0, 0); Compare(pix3, pix1, &error); pixSaveTiled(pix3, pixa, 1, 0, 30, 32); pixDestroy(&pix1); pixDestroy(&pix2c); pixDestroy(&pix3); /* Transfer of data pixs --> pixd, when pixs is cloned. * pixs has its refcount reduced by 1. */ pix1 = pixRead("weasel4.16c.png"); pix2 = pixRead("feyn-fract.tif"); pix3 = pixRead("lucasta.150.jpg"); pix1c = pixClone(pix1); pix2c = pixClone(pix2); fprintf(stderr, "before clone transfer 1 --> 2\n"); pixTransferAllData(pix2, &pix1c, 0, 0); Compare(pix2, pix1, &error); pixSaveTiled(pix2, pixa, 1, 0, 30, 32); fprintf(stderr, "before clone transfer 2 --> 3\n"); pixTransferAllData(pix3, &pix2c, 0, 0); Compare(pix3, pix1, &error); pixSaveTiled(pix3, pixa, 1, 0, 30, 32); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); /* Extraction of data when pixs is not cloned, putting * the data into a new template of pixs. */ pix2 = pixRead("feyn-fract.tif"); fprintf(stderr, "no clone: before extraction and reinsertion of 2\n"); pix2c = pixCopy(NULL, pix2); /* for later reference */ data = pixExtractData(pix2); pix2t = pixCreateTemplateNoInit(pix2); pixFreeData(pix2t); pixSetData(pix2t, data); Compare(pix2c, pix2t, &error); pixSaveTiled(pix2t, pixa, 4, 1, 30, 32); pixDestroy(&pix2); pixDestroy(&pix2c); pixDestroy(&pix2t); /* Extraction of data when pixs is cloned, putting * a copy of the data into a new template of pixs. */ pix1 = pixRead("weasel4.16c.png"); fprintf(stderr, "clone: before extraction and reinsertion of 1\n"); pix1c = pixClone(pix1); /* bump refcount of pix1 to 2 */ data = pixExtractData(pix1); /* should make a copy of data */ pix1t = pixCreateTemplateNoInit(pix1); pixFreeData(pix1t); pixSetData(pix1t, data); Compare(pix1c, pix1t, &error); pixSaveTiled(pix1t, pixa, 1, 0, 30, 32); pixDestroy(&pix1); pixDestroy(&pix1c); pixDestroy(&pix1t); pixd = pixaDisplay(pixa, 0, 0); pixDisplay(pixd, 100, 100); pixWrite("/tmp/junkpixmem.png", pixd, IFF_PNG); pixaDestroy(&pixa); pixDestroy(&pixd); if (error) fprintf(stderr, "Fail: an error occurred\n"); else fprintf(stderr, "Success: no errors\n"); return 0; }