JamesLee
JamesLee

Reputation: 21

how to use Pillow library in c++ program

I'm trying to create a c++ program based on Tensorflow for c and Pillow image processing library. not opencv.

The reason for wanting to use Pillow is making the same library environment with a python-tensorflow project that uses Pillow. Specifically, difference resize() function's result between opencv and pillow.

so, when I include imaging.h header file on my c++ code, compiler makes an error like below. even the header file included in "extern c" loop.

'ImagingMemoryArena': 'ImagingMemoryArena *' differs in levels of indirection from 'ImagingMemoryArena'

Below is the link to the ImagingMemoryArena struct code in imaging.h file.

https://github.com/python-pillow/Pillow/blob/ff40eaa9615b0c37fd4bd4192e3a3219a5867c2b/src/libImaging/Imaging.h#L161

I thought C code can be compiled in C++ code. so tried the below code in .C and .CPP file both. but only be compiled in C file, not CPP.

The compiling environment is on visual studio 2017 c++ project.

#if defined(__cplusplus)
extern "C" {
#endif

    typedef struct ImagingMemoryArena {
        int alignment;        /* Alignment in memory of each line of an image */
        int block_size;       /* Preferred block size, bytes */
        int blocks_max;       /* Maximum number of cached blocks */
        int blocks_cached;    /* Current number of blocks not associated with images */
        int stats_new_count;           /* Number of new allocated images */
        int stats_allocated_blocks;    /* Number of allocated blocks */
        int stats_reused_blocks;       /* Number of blocks which were retrieved from a pool */
        int stats_reallocated_blocks;  /* Number of blocks which were actually reallocated after retrieving */
        int stats_freed_blocks;        /* Number of freed blocks */
    } *ImagingMemoryArena;

#if defined(__cplusplus)
}
#endif

I want to know the reason, why c++ compiler makes an error for the above code even including "extern C". Thanks.

Upvotes: 2

Views: 4418

Answers (2)

xryl669
xryl669

Reputation: 3614

It's very likely because you have conflicting declarations in the posted header.

In C, a struct A and a typedef X A can exist and be different (since if you want to instantiate the former, you need to write struct A a;. But in C++, a struct declares a class and can be instantiated directly, without needing to repeat struct in front, like this: A a;

Then, looking at the header you've provided, it declares 2 different types with the same name: the struct ImagingMemoryArena {...}; and the pointer to this structure typedef struct ImagingMemoryArena * ImagingMemoryArena;

Thus, it's impossible for the compiler to know, when you write ImagingMemoryArena img; if you refer to the former (the aggregated struct) or the pointer, hence the error.

To solve this error, the easiest is to rename the struct with a leading underscore: typedef struct _ImagingMemoryArena { ... } * ImagingMemoryArena;, so there is no possible mismatch.

You can also rename the typedef'ed type, but if I were you, I would search for the Pillow source code how the name ImagingMemoryArena is used. If it's used mainly with struct ImagingMemoryArena then rename the typedef. If it's used mainly without the struct and as a pointer, rename the struct.

Upvotes: 1

AmitJhaIITBHU
AmitJhaIITBHU

Reputation: 63

This is due to a mismatch in the type definition for ImagingMemoryArena between C and C++ code. In C, the typedef struct ImagingMemoryArena creates a type alias for a pointer to the ImagingMemoryArena struct, while in C++ this is not automatically inferred, causing the type mismatch error.

Make type definition consistent across both C and C++ code by explicitly defining the struct and the typedef separately, here is how:

#if defined(__cplusplus)
extern "C" {
#endif

    struct ImagingMemoryArena {
        int alignment;        /* Alignment in memory of each line of an image */
        int block_size;       /* Preferred block size, bytes */
        int blocks_max;       /* Maximum number of cached blocks */
        int blocks_cached;    /* Current number of blocks not associated with images */
        int stats_new_count;           /* Number of new allocated images */
        int stats_allocated_blocks;    /* Number of allocated blocks */
        int stats_reused_blocks;       /* Number of blocks which were retrieved from a pool */
        int stats_reallocated_blocks;  /* Number of blocks which were actually reallocated after retrieving */
        int stats_freed_blocks;        /* Number of freed blocks */
    };

    typedef struct ImagingMemoryArena *ImagingMemoryArena;

#if defined(__cplusplus)
}
#endif

By defining the struct and the typedef separately, you ensure that the type definition is compatible in both C and C++ contexts.

Upvotes: 0

Related Questions