Question

CacheKey method of QImage returns not really a plain hash of image. Does anyone know, what the upper 32 bits mean? And can I really ignore them when comparing two images? (Compare only the lower 32 bits?)


For illustration only, this code reading the same image multiple times (yet storing them in different QImage objects):

printf("%llx\n",QImage("image.png").cacheKey());
printf("%llx\n",QImage("image.png").cacheKey());
printf("%llx\n",QImage("image.png").cacheKey());

returns this?

144300000002
144400000002
144500000002

or this? (seems like the upper 32 bits depend on current memory position)

140800000002
140900000002
140a00000002
Was it helpful?

Solution

No, you can't use any part of the cacheKey to compare image content, it only exists to make sure an image hasn't changed since the last cacheKey value was taken. It identifies the buffer and changes whenever any non-const function of the QImage is called.

But as the name of the cacheKey property implies, you can use it as a key for a QCache<qint64, QByteArray> where you would store the actual hash of the image that you would only recalculate with QCryptographicHash only if the image was changed (= only if it isn't already in the cache).

Also QImage doesn't use a cache like QPixmap for reading an image, so reading 3 times the same image file will allocate 3 distinct buffers, each time with a different cacheKey. To avoid calculating the hashes each time, you should take a look at the source code of the QPixmap::load function.

OTHER TIPS

The upper 32 bit depend on nothing, but the 32 bit of the previous image. It is a serial number, which in incremented with each new QImage.

Looking at the source for QImage :

qint64 QImage::cacheKey() const
{
    if (!d)
        return 0;
    else
        return (((qint64) d->ser_no) << 32) | ((qint64) d->detach_no);
}

looks like the upper 32 bits are d->ser_no which is initialized with QImageData:

QBasicAtomicInt qimage_serial_number = Q_BASIC_ATOMIC_INITIALIZER(1);

QImageData::QImageData()
    : ref(0), width(0), height(0), depth(0), nbytes(0), data(0),
#ifdef QT3_SUPPORT
      jumptable(0),
#endif
      format(QImage::Format_ARGB32), bytes_per_line(0),
      ser_no(qimage_serial_number.fetchAndAddRelaxed(1)),
      detach_no(0),
      dpmx(qt_defaultDpiX() * 100 / qreal(2.54)),
      dpmy(qt_defaultDpiY() * 100 / qreal(2.54)),
      offset(0, 0), own_data(true), ro_data(false), has_alpha_clut(false),
      is_cached(false), paintEngine(0)
{
}

And it looks like QBasicAtomicInt is an atomic reference counter (see here). So it looks like every new image will have a different upper 32 bits in the cachekey value unless you copy it rather than create it anew.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top