2014-05-30 08:53:19 +00:00
/*
This file is part of Telegram Desktop ,
2018-01-03 10:23:14 +00:00
the official desktop application for the Telegram messaging service .
2014-05-30 08:53:19 +00:00
2018-01-03 10:23:14 +00:00
For license and copyright information please follow this link :
https : //github.com/telegramdesktop/tdesktop/blob/master/LEGAL
2014-05-30 08:53:19 +00:00
*/
2016-04-07 18:05:28 +00:00
# include "ui/images.h"
2014-05-30 08:53:19 +00:00
# include "mainwidget.h"
2017-03-04 10:23:56 +00:00
# include "storage/localstorage.h"
2018-08-27 11:35:58 +00:00
# include "storage/cache/storage_cache_database.h"
2017-03-04 10:23:56 +00:00
# include "platform/platform_specific.h"
2017-04-06 16:49:42 +00:00
# include "auth_session.h"
2018-01-11 19:33:26 +00:00
# include "history/history_item.h"
2018-01-13 12:45:11 +00:00
# include "history/history.h"
2018-08-27 11:35:58 +00:00
# include "data/data_session.h"
2015-11-26 17:34:52 +00:00
2016-11-28 15:45:07 +00:00
namespace Images {
2014-05-30 08:53:19 +00:00
namespace {
2018-07-28 21:08:29 +00:00
TG_FORCE_INLINE uint64 blurGetColors ( const uchar * p ) {
2016-11-28 15:45:07 +00:00
return ( uint64 ) p [ 0 ] + ( ( uint64 ) p [ 1 ] < < 16 ) + ( ( uint64 ) p [ 2 ] < < 32 ) + ( ( uint64 ) p [ 3 ] < < 48 ) ;
2016-03-18 10:18:30 +00:00
}
2016-11-28 15:45:07 +00:00
const QPixmap & circleMask ( int width , int height ) {
2017-08-17 09:06:26 +00:00
Assert ( Global : : started ( ) ) ;
2016-11-21 20:26:54 +00:00
2016-11-28 15:45:07 +00:00
uint64 key = uint64 ( uint32 ( width ) ) < < 32 | uint64 ( uint32 ( height ) ) ;
2016-11-21 20:26:54 +00:00
2016-11-28 15:45:07 +00:00
Global : : CircleMasksMap & masks ( Global : : RefCircleMasks ( ) ) ;
auto i = masks . constFind ( key ) ;
if ( i = = masks . cend ( ) ) {
QImage mask ( width , height , QImage : : Format_ARGB32_Premultiplied ) ;
{
Painter p ( & mask ) ;
2016-12-03 12:10:35 +00:00
PainterHighQualityEnabler hq ( p ) ;
2016-11-28 15:45:07 +00:00
p . setCompositionMode ( QPainter : : CompositionMode_Source ) ;
p . fillRect ( 0 , 0 , width , height , Qt : : transparent ) ;
p . setBrush ( Qt : : white ) ;
p . setPen ( Qt : : NoPen ) ;
p . drawEllipse ( 0 , 0 , width , height ) ;
2014-11-12 20:18:00 +00:00
}
2016-11-28 15:45:07 +00:00
mask . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
2017-02-21 13:45:56 +00:00
i = masks . insert ( key , App : : pixmapFromImageInPlace ( std : : move ( mask ) ) ) ;
2014-11-12 20:18:00 +00:00
}
2016-11-22 08:36:02 +00:00
return i . value ( ) ;
2014-11-12 20:18:00 +00:00
}
2016-11-28 15:45:07 +00:00
} // namespace
2014-09-20 21:35:46 +00:00
2018-01-02 19:10:49 +00:00
QPixmap PixmapFast ( QImage & & image ) {
Expects ( image . format ( ) = = QImage : : Format_ARGB32_Premultiplied
| | image . format ( ) = = QImage : : Format_RGB32 ) ;
return QPixmap : : fromImage ( std : : move ( image ) , Qt : : NoFormatConversion ) ;
}
2016-11-28 15:45:07 +00:00
QImage prepareBlur ( QImage img ) {
2017-05-24 14:36:58 +00:00
auto ratio = img . devicePixelRatio ( ) ;
auto fmt = img . format ( ) ;
2015-01-05 20:17:33 +00:00
if ( fmt ! = QImage : : Format_RGB32 & & fmt ! = QImage : : Format_ARGB32_Premultiplied ) {
img = img . convertToFormat ( QImage : : Format_ARGB32_Premultiplied ) ;
2017-05-24 14:36:58 +00:00
img . setDevicePixelRatio ( ratio ) ;
2017-08-17 09:06:26 +00:00
Assert ( ! img . isNull ( ) ) ;
2014-08-11 09:03:45 +00:00
}
2014-09-20 21:35:46 +00:00
uchar * pix = img . bits ( ) ;
if ( pix ) {
2015-01-05 20:17:33 +00:00
int w = img . width ( ) , h = img . height ( ) , wold = w , hold = h ;
const int radius = 3 ;
2014-09-20 21:35:46 +00:00
const int r1 = radius + 1 ;
const int div = radius * 2 + 1 ;
2015-01-05 20:17:33 +00:00
const int stride = w * 4 ;
2014-09-20 21:35:46 +00:00
if ( radius < 16 & & div < w & & div < h & & stride < = w * 4 ) {
2015-01-05 20:17:33 +00:00
bool withalpha = img . hasAlphaChannel ( ) ;
if ( withalpha ) {
QImage imgsmall ( w , h , img . format ( ) ) ;
{
2016-12-03 12:10:35 +00:00
Painter p ( & imgsmall ) ;
PainterHighQualityEnabler hq ( p ) ;
2015-01-05 20:17:33 +00:00
p . setCompositionMode ( QPainter : : CompositionMode_Source ) ;
2016-10-31 12:29:26 +00:00
p . fillRect ( 0 , 0 , w , h , Qt : : transparent ) ;
2015-01-05 20:17:33 +00:00
p . drawImage ( QRect ( radius , radius , w - 2 * radius , h - 2 * radius ) , img , QRect ( 0 , 0 , w , h ) ) ;
}
2017-05-24 14:36:58 +00:00
imgsmall . setDevicePixelRatio ( ratio ) ;
auto was = img ;
img = std : : move ( imgsmall ) ;
2015-01-05 20:17:33 +00:00
imgsmall = QImage ( ) ;
2017-08-17 09:06:26 +00:00
Assert ( ! img . isNull ( ) ) ;
2016-02-28 13:23:03 +00:00
2015-01-05 20:17:33 +00:00
pix = img . bits ( ) ;
if ( ! pix ) return was ;
}
2014-09-20 21:35:46 +00:00
uint64 * rgb = new uint64 [ w * h ] ;
int x , y , i ;
int yw = 0 ;
const int we = w - r1 ;
for ( y = 0 ; y < h ; y + + ) {
2016-11-28 15:45:07 +00:00
uint64 cur = blurGetColors ( & pix [ yw ] ) ;
2014-09-20 21:35:46 +00:00
uint64 rgballsum = - radius * cur ;
uint64 rgbsum = cur * ( ( r1 * ( r1 + 1 ) ) > > 1 ) ;
for ( i = 1 ; i < = radius ; i + + ) {
2016-11-28 15:45:07 +00:00
uint64 cur = blurGetColors ( & pix [ yw + i * 4 ] ) ;
2014-09-20 21:35:46 +00:00
rgbsum + = cur * ( r1 - i ) ;
rgballsum + = cur ;
2014-08-11 09:03:45 +00:00
}
2014-09-20 21:35:46 +00:00
x = 0 ;
# define update(start, middle, end) \
2015-01-05 20:17:33 +00:00
rgb [ y * w + x ] = ( rgbsum > > 4 ) & 0x00FF00FF00FF00FFLL ; \
2016-11-28 15:45:07 +00:00
rgballsum + = blurGetColors ( & pix [ yw + ( start ) * 4 ] ) - 2 * blurGetColors ( & pix [ yw + ( middle ) * 4 ] ) + blurGetColors ( & pix [ yw + ( end ) * 4 ] ) ; \
2014-09-22 03:52:37 +00:00
rgbsum + = rgballsum ; \
x + + ;
2014-09-20 21:35:46 +00:00
while ( x < r1 ) {
update ( 0 , x , x + r1 ) ;
}
while ( x < we ) {
update ( x - r1 , x , x + r1 ) ;
}
while ( x < w ) {
update ( x - r1 , x , w - 1 ) ;
}
# undef update
yw + = stride ;
2014-08-11 09:03:45 +00:00
}
2014-09-20 21:35:46 +00:00
const int he = h - r1 ;
for ( x = 0 ; x < w ; x + + ) {
uint64 rgballsum = - radius * rgb [ x ] ;
uint64 rgbsum = rgb [ x ] * ( ( r1 * ( r1 + 1 ) ) > > 1 ) ;
for ( i = 1 ; i < = radius ; i + + ) {
rgbsum + = rgb [ i * w + x ] * ( r1 - i ) ;
rgballsum + = rgb [ i * w + x ] ;
}
y = 0 ;
int yi = x * 4 ;
# define update(start, middle, end) \
2015-01-05 20:17:33 +00:00
uint64 res = rgbsum > > 4 ; \
2014-09-22 03:52:37 +00:00
pix [ yi ] = res & 0xFF ; \
pix [ yi + 1 ] = ( res > > 16 ) & 0xFF ; \
pix [ yi + 2 ] = ( res > > 32 ) & 0xFF ; \
2015-01-05 20:17:33 +00:00
pix [ yi + 3 ] = ( res > > 48 ) & 0xFF ; \
2014-09-22 03:52:37 +00:00
rgballsum + = rgb [ x + ( start ) * w ] - 2 * rgb [ x + ( middle ) * w ] + rgb [ x + ( end ) * w ] ; \
rgbsum + = rgballsum ; \
y + + ; \
yi + = stride ;
2014-09-20 21:35:46 +00:00
while ( y < r1 ) {
update ( 0 , y , y + r1 ) ;
}
while ( y < he ) {
update ( y - r1 , y , y + r1 ) ;
}
while ( y < h ) {
update ( y - r1 , y , h - 1 ) ;
2014-08-11 09:03:45 +00:00
}
2014-09-20 21:35:46 +00:00
2016-11-28 15:45:07 +00:00
# undef update
}
delete [ ] rgb ;
}
}
return img ;
}
void prepareCircle ( QImage & img ) {
2017-08-17 09:06:26 +00:00
Assert ( ! img . isNull ( ) ) ;
2016-11-28 15:45:07 +00:00
img . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
img = img . convertToFormat ( QImage : : Format_ARGB32_Premultiplied ) ;
2017-08-17 09:06:26 +00:00
Assert ( ! img . isNull ( ) ) ;
2016-11-28 15:45:07 +00:00
QPixmap mask = circleMask ( img . width ( ) , img . height ( ) ) ;
Painter p ( & img ) ;
p . setCompositionMode ( QPainter : : CompositionMode_DestinationIn ) ;
p . drawPixmap ( 0 , 0 , mask ) ;
}
2017-12-25 19:26:08 +00:00
void prepareRound (
QImage & image ,
QImage * cornerMasks ,
RectParts corners ,
QRect target ) {
if ( target . isNull ( ) ) {
target = QRect ( QPoint ( ) , image . size ( ) ) ;
} else {
Assert ( QRect ( QPoint ( ) , image . size ( ) ) . contains ( target ) ) ;
2016-11-28 15:45:07 +00:00
}
2017-07-13 14:42:46 +00:00
auto cornerWidth = cornerMasks [ 0 ] . width ( ) ;
auto cornerHeight = cornerMasks [ 0 ] . height ( ) ;
2016-11-28 15:45:07 +00:00
auto imageWidth = image . width ( ) ;
auto imageHeight = image . height ( ) ;
if ( imageWidth < 2 * cornerWidth | | imageHeight < 2 * cornerHeight ) {
return ;
}
constexpr auto imageIntsPerPixel = 1 ;
auto imageIntsPerLine = ( image . bytesPerLine ( ) > > 2 ) ;
2017-08-17 09:06:26 +00:00
Assert ( image . depth ( ) = = static_cast < int > ( ( imageIntsPerPixel * sizeof ( uint32 ) ) < < 3 ) ) ;
Assert ( image . bytesPerLine ( ) = = ( imageIntsPerLine < < 2 ) ) ;
2016-11-28 15:45:07 +00:00
auto ints = reinterpret_cast < uint32 * > ( image . bits ( ) ) ;
2017-12-25 19:26:08 +00:00
auto intsTopLeft = ints + target . x ( ) + target . y ( ) * imageWidth ;
auto intsTopRight = ints + target . x ( ) + target . width ( ) - cornerWidth + target . y ( ) * imageWidth ;
auto intsBottomLeft = ints + target . x ( ) + ( target . y ( ) + target . height ( ) - cornerHeight ) * imageWidth ;
auto intsBottomRight = ints + target . x ( ) + target . width ( ) - cornerWidth + ( target . y ( ) + target . height ( ) - cornerHeight ) * imageWidth ;
2018-04-07 08:47:08 +00:00
auto maskCorner = [ & ] ( uint32 * imageInts , const QImage & mask ) {
2017-07-13 14:42:46 +00:00
auto maskWidth = mask . width ( ) ;
auto maskHeight = mask . height ( ) ;
auto maskBytesPerPixel = ( mask . depth ( ) > > 3 ) ;
auto maskBytesPerLine = mask . bytesPerLine ( ) ;
2016-11-28 15:45:07 +00:00
auto maskBytesAdded = maskBytesPerLine - maskWidth * maskBytesPerPixel ;
2017-07-13 14:42:46 +00:00
auto maskBytes = mask . constBits ( ) ;
2017-08-17 09:06:26 +00:00
Assert ( maskBytesAdded > = 0 ) ;
Assert ( mask . depth ( ) = = ( maskBytesPerPixel < < 3 ) ) ;
2016-11-28 15:45:07 +00:00
auto imageIntsAdded = imageIntsPerLine - maskWidth * imageIntsPerPixel ;
2017-08-17 09:06:26 +00:00
Assert ( imageIntsAdded > = 0 ) ;
2016-11-28 15:45:07 +00:00
for ( auto y = 0 ; y ! = maskHeight ; + + y ) {
for ( auto x = 0 ; x ! = maskWidth ; + + x ) {
auto opacity = static_cast < anim : : ShiftedMultiplier > ( * maskBytes ) + 1 ;
* imageInts = anim : : unshifted ( anim : : shifted ( * imageInts ) * opacity ) ;
maskBytes + = maskBytesPerPixel ;
imageInts + = imageIntsPerPixel ;
}
maskBytes + = maskBytesAdded ;
imageInts + = imageIntsAdded ;
}
} ;
2017-12-18 17:50:25 +00:00
if ( corners & RectPart : : TopLeft ) maskCorner ( intsTopLeft , cornerMasks [ 0 ] ) ;
if ( corners & RectPart : : TopRight ) maskCorner ( intsTopRight , cornerMasks [ 1 ] ) ;
if ( corners & RectPart : : BottomLeft ) maskCorner ( intsBottomLeft , cornerMasks [ 2 ] ) ;
if ( corners & RectPart : : BottomRight ) maskCorner ( intsBottomRight , cornerMasks [ 3 ] ) ;
2016-11-28 15:45:07 +00:00
}
2017-12-25 19:26:08 +00:00
void prepareRound (
QImage & image ,
ImageRoundRadius radius ,
RectParts corners ,
QRect target ) {
if ( ! static_cast < int > ( corners ) ) {
return ;
} else if ( radius = = ImageRoundRadius : : Ellipse ) {
Assert ( ( corners & RectPart : : AllCorners ) = = RectPart : : AllCorners ) ;
Assert ( target . isNull ( ) ) ;
prepareCircle ( image ) ;
}
Assert ( ! image . isNull ( ) ) ;
image . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
image = std : : move ( image ) . convertToFormat ( QImage : : Format_ARGB32_Premultiplied ) ;
Assert ( ! image . isNull ( ) ) ;
auto masks = App : : cornersMask ( radius ) ;
prepareRound ( image , masks , corners , target ) ;
}
2016-12-23 13:21:01 +00:00
QImage prepareColored ( style : : color add , QImage image ) {
2016-11-28 15:45:07 +00:00
auto format = image . format ( ) ;
if ( format ! = QImage : : Format_RGB32 & & format ! = QImage : : Format_ARGB32_Premultiplied ) {
2017-02-21 13:45:56 +00:00
image = std : : move ( image ) . convertToFormat ( QImage : : Format_ARGB32_Premultiplied ) ;
2016-11-28 15:45:07 +00:00
}
if ( auto pix = image . bits ( ) ) {
int ca = int ( add - > c . alphaF ( ) * 0xFF ) , cr = int ( add - > c . redF ( ) * 0xFF ) , cg = int ( add - > c . greenF ( ) * 0xFF ) , cb = int ( add - > c . blueF ( ) * 0xFF ) ;
const int w = image . width ( ) , h = image . height ( ) , size = w * h * 4 ;
for ( int32 i = 0 ; i < size ; i + = 4 ) {
int b = pix [ i ] , g = pix [ i + 1 ] , r = pix [ i + 2 ] , a = pix [ i + 3 ] , aca = a * ca ;
pix [ i + 0 ] = uchar ( b + ( ( aca * ( cb - b ) ) > > 16 ) ) ;
pix [ i + 1 ] = uchar ( g + ( ( aca * ( cg - g ) ) > > 16 ) ) ;
pix [ i + 2 ] = uchar ( r + ( ( aca * ( cr - r ) ) > > 16 ) ) ;
pix [ i + 3 ] = uchar ( a + ( ( aca * ( 0xFF - a ) ) > > 16 ) ) ;
}
}
2017-02-21 14:37:53 +00:00
return image ;
2016-11-28 15:45:07 +00:00
}
QImage prepareOpaque ( QImage image ) {
if ( image . hasAlphaChannel ( ) ) {
2017-02-21 13:45:56 +00:00
image = std : : move ( image ) . convertToFormat ( QImage : : Format_ARGB32_Premultiplied ) ;
2016-11-28 15:45:07 +00:00
auto ints = reinterpret_cast < uint32 * > ( image . bits ( ) ) ;
auto bg = anim : : shifted ( st : : imageBgTransparent - > c ) ;
auto width = image . width ( ) ;
auto height = image . height ( ) ;
auto addPerLine = ( image . bytesPerLine ( ) / sizeof ( uint32 ) ) - width ;
for ( auto y = 0 ; y ! = height ; + + y ) {
for ( auto x = 0 ; x ! = width ; + + x ) {
auto components = anim : : shifted ( * ints ) ;
2016-12-13 17:07:56 +00:00
* ints + + = anim : : unshifted ( components * 256 + bg * ( 256 - anim : : getAlpha ( components ) ) ) ;
2016-11-28 15:45:07 +00:00
}
2016-12-13 17:07:56 +00:00
ints + = addPerLine ;
2016-11-28 15:45:07 +00:00
}
}
2017-02-21 14:37:53 +00:00
return image ;
2016-11-28 15:45:07 +00:00
}
2017-06-06 09:15:13 +00:00
QImage prepare ( QImage img , int w , int h , Images : : Options options , int outerw , int outerh , const style : : color * colored ) {
2017-08-17 09:06:26 +00:00
Assert ( ! img . isNull ( ) ) ;
2017-08-31 16:28:58 +00:00
if ( options & Images : : Option : : Blurred ) {
2017-05-24 14:36:58 +00:00
img = prepareBlur ( std : : move ( img ) ) ;
2017-08-17 09:06:26 +00:00
Assert ( ! img . isNull ( ) ) ;
2016-11-28 15:45:07 +00:00
}
if ( w < = 0 | | ( w = = img . width ( ) & & ( h < = 0 | | h = = img . height ( ) ) ) ) {
} else if ( h < = 0 ) {
2017-08-31 16:28:58 +00:00
img = img . scaledToWidth ( w , ( options & Images : : Option : : Smooth ) ? Qt : : SmoothTransformation : Qt : : FastTransformation ) ;
2017-08-17 09:06:26 +00:00
Assert ( ! img . isNull ( ) ) ;
2016-11-28 15:45:07 +00:00
} else {
2017-08-31 16:28:58 +00:00
img = img . scaled ( w , h , Qt : : IgnoreAspectRatio , ( options & Images : : Option : : Smooth ) ? Qt : : SmoothTransformation : Qt : : FastTransformation ) ;
2017-08-17 09:06:26 +00:00
Assert ( ! img . isNull ( ) ) ;
2016-11-28 15:45:07 +00:00
}
if ( outerw > 0 & & outerh > 0 ) {
outerw * = cIntRetinaFactor ( ) ;
outerh * = cIntRetinaFactor ( ) ;
if ( outerw ! = w | | outerh ! = h ) {
img . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
2017-06-06 09:16:56 +00:00
auto result = QImage ( outerw , outerh , QImage : : Format_ARGB32_Premultiplied ) ;
2016-11-28 15:45:07 +00:00
result . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
2017-06-06 09:16:56 +00:00
if ( options & Images : : Option : : TransparentBackground ) {
result . fill ( Qt : : transparent ) ;
}
2016-11-28 15:45:07 +00:00
{
QPainter p ( & result ) ;
if ( w < outerw | | h < outerh ) {
p . fillRect ( 0 , 0 , result . width ( ) , result . height ( ) , st : : imageBg ) ;
}
p . drawImage ( ( result . width ( ) - img . width ( ) ) / ( 2 * cIntRetinaFactor ( ) ) , ( result . height ( ) - img . height ( ) ) / ( 2 * cIntRetinaFactor ( ) ) , img ) ;
}
img = result ;
2017-08-17 09:06:26 +00:00
Assert ( ! img . isNull ( ) ) ;
2016-11-28 15:45:07 +00:00
}
}
auto corners = [ ] ( Images : : Options options ) {
2017-12-18 17:50:25 +00:00
return ( ( options & Images : : Option : : RoundedTopLeft ) ? RectPart : : TopLeft : RectPart : : None )
| ( ( options & Images : : Option : : RoundedTopRight ) ? RectPart : : TopRight : RectPart : : None )
| ( ( options & Images : : Option : : RoundedBottomLeft ) ? RectPart : : BottomLeft : RectPart : : None )
| ( ( options & Images : : Option : : RoundedBottomRight ) ? RectPart : : BottomRight : RectPart : : None ) ;
2016-11-28 15:45:07 +00:00
} ;
2017-08-31 16:28:58 +00:00
if ( options & Images : : Option : : Circled ) {
2016-11-28 15:45:07 +00:00
prepareCircle ( img ) ;
2017-08-17 09:06:26 +00:00
Assert ( ! img . isNull ( ) ) ;
2017-08-31 16:28:58 +00:00
} else if ( options & Images : : Option : : RoundedLarge ) {
2016-11-28 15:45:07 +00:00
prepareRound ( img , ImageRoundRadius : : Large , corners ( options ) ) ;
2017-08-17 09:06:26 +00:00
Assert ( ! img . isNull ( ) ) ;
2017-08-31 16:28:58 +00:00
} else if ( options & Images : : Option : : RoundedSmall ) {
2016-11-28 15:45:07 +00:00
prepareRound ( img , ImageRoundRadius : : Small , corners ( options ) ) ;
2017-08-17 09:06:26 +00:00
Assert ( ! img . isNull ( ) ) ;
2016-11-28 15:45:07 +00:00
}
2017-08-31 16:28:58 +00:00
if ( options & Images : : Option : : Colored ) {
2017-08-17 09:06:26 +00:00
Assert ( colored ! = nullptr ) ;
2017-06-06 09:15:13 +00:00
img = prepareColored ( * colored , std : : move ( img ) ) ;
}
2016-11-28 15:45:07 +00:00
img . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
2017-02-21 14:37:53 +00:00
return img ;
2016-11-28 15:45:07 +00:00
}
} // namespace Images
namespace {
using LocalImages = QMap < QString , Image * > ;
LocalImages localImages ;
using WebImages = QMap < QString , WebImage * > ;
WebImages webImages ;
Image * generateBlankImage ( ) {
auto data = QImage ( cIntRetinaFactor ( ) , cIntRetinaFactor ( ) , QImage : : Format_ARGB32_Premultiplied ) ;
data . fill ( Qt : : transparent ) ;
data . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
2017-02-21 13:45:56 +00:00
return internal : : getImage ( App : : pixmapFromImageInPlace ( std : : move ( data ) ) , " GIF " ) ;
2016-11-28 15:45:07 +00:00
}
Image * blank ( ) {
static auto blankImage = generateBlankImage ( ) ;
return blankImage ;
}
using StorageImages = QMap < StorageKey , StorageImage * > ;
StorageImages storageImages ;
2017-03-05 17:33:32 +00:00
using WebFileImages = QMap < StorageKey , WebFileImage * > ;
WebFileImages webFileImages ;
2016-11-28 15:45:07 +00:00
int64 globalAcquiredSize = 0 ;
uint64 PixKey ( int width , int height , Images : : Options options ) {
return static_cast < uint64 > ( width ) | ( static_cast < uint64 > ( height ) < < 24 ) | ( static_cast < uint64 > ( options ) < < 48 ) ;
}
uint64 SinglePixKey ( Images : : Options options ) {
return PixKey ( 0 , 0 , options ) ;
}
} // namespace
StorageImageLocation StorageImageLocation : : Null ;
2018-03-04 20:04:13 +00:00
WebFileLocation WebFileLocation : : Null ;
2016-11-28 15:45:07 +00:00
2018-07-13 16:49:46 +00:00
StorageImageLocation : : StorageImageLocation (
int32 width ,
int32 height ,
int32 dc ,
const uint64 & volume ,
int32 local ,
const uint64 & secret ,
const QByteArray & fileReference )
: _widthheight ( packIntInt ( width , height ) )
, _dclocal ( packIntInt ( dc , local ) )
, _volume ( volume )
, _secret ( secret )
, _fileReference ( fileReference ) {
}
StorageImageLocation : : StorageImageLocation (
int32 width ,
int32 height ,
const MTPDfileLocation & location )
: StorageImageLocation (
width ,
height ,
location . vdc_id . v ,
location . vvolume_id . v ,
location . vlocal_id . v ,
location . vsecret . v ,
location . vfile_reference . v ) {
}
2016-11-28 15:45:07 +00:00
bool Image : : isNull ( ) const {
return ( this = = blank ( ) ) ;
}
ImagePtr : : ImagePtr ( ) : Parent ( blank ( ) ) {
}
ImagePtr : : ImagePtr ( int32 width , int32 height , const MTPFileLocation & location , ImagePtr def ) :
Parent ( ( location . type ( ) = = mtpc_fileLocation ) ? ( Image * ) ( internal : : getImage ( StorageImageLocation ( width , height , location . c_fileLocation ( ) ) ) ) : def . v ( ) ) {
}
Image : : Image ( const QString & file , QByteArray fmt ) : _forgot ( false ) {
_data = App : : pixmapFromImageInPlace ( App : : readImage ( file , & fmt , false , 0 , & _saved ) ) ;
_format = fmt ;
if ( ! _data . isNull ( ) ) {
globalAcquiredSize + = int64 ( _data . width ( ) ) * _data . height ( ) * 4 ;
}
}
Image : : Image ( const QByteArray & filecontent , QByteArray fmt ) : _forgot ( false ) {
_data = App : : pixmapFromImageInPlace ( App : : readImage ( filecontent , & fmt , false ) ) ;
_format = fmt ;
_saved = filecontent ;
if ( ! _data . isNull ( ) ) {
globalAcquiredSize + = int64 ( _data . width ( ) ) * _data . height ( ) * 4 ;
}
}
Image : : Image ( const QPixmap & pixmap , QByteArray format ) : _format ( format ) , _forgot ( false ) , _data ( pixmap ) {
if ( ! _data . isNull ( ) ) {
globalAcquiredSize + = int64 ( _data . width ( ) ) * _data . height ( ) * 4 ;
}
}
Image : : Image ( const QByteArray & filecontent , QByteArray fmt , const QPixmap & pixmap ) : _saved ( filecontent ) , _format ( fmt ) , _forgot ( false ) , _data ( pixmap ) {
_data = pixmap ;
_format = fmt ;
_saved = filecontent ;
if ( ! _data . isNull ( ) ) {
globalAcquiredSize + = int64 ( _data . width ( ) ) * _data . height ( ) * 4 ;
}
}
2018-07-13 21:25:47 +00:00
const QPixmap & Image : : pix (
Data : : FileOrigin origin ,
int32 w ,
int32 h ) const {
2016-11-28 15:45:07 +00:00
checkload ( ) ;
if ( w < = 0 | | ! width ( ) | | ! height ( ) ) {
w = width ( ) ;
} else if ( cRetina ( ) ) {
w * = cIntRetinaFactor ( ) ;
h * = cIntRetinaFactor ( ) ;
}
auto options = Images : : Option : : Smooth | Images : : Option : : None ;
auto k = PixKey ( w , h , options ) ;
auto i = _sizesCache . constFind ( k ) ;
if ( i = = _sizesCache . cend ( ) ) {
2018-07-13 21:25:47 +00:00
auto p = pixNoCache ( origin , w , h , options ) ;
2016-11-28 15:45:07 +00:00
if ( cRetina ( ) ) p . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
i = _sizesCache . insert ( k , p ) ;
if ( ! p . isNull ( ) ) {
globalAcquiredSize + = int64 ( p . width ( ) ) * p . height ( ) * 4 ;
}
}
return i . value ( ) ;
}
2018-07-13 21:25:47 +00:00
const QPixmap & Image : : pixRounded (
Data : : FileOrigin origin ,
int32 w ,
int32 h ,
ImageRoundRadius radius ,
RectParts corners ) const {
2016-11-28 15:45:07 +00:00
checkload ( ) ;
if ( w < = 0 | | ! width ( ) | | ! height ( ) ) {
w = width ( ) ;
} else if ( cRetina ( ) ) {
w * = cIntRetinaFactor ( ) ;
h * = cIntRetinaFactor ( ) ;
}
auto options = Images : : Option : : Smooth | Images : : Option : : None ;
2017-12-18 17:50:25 +00:00
auto cornerOptions = [ ] ( RectParts corners ) {
return ( corners & RectPart : : TopLeft ? Images : : Option : : RoundedTopLeft : Images : : Option : : None )
| ( corners & RectPart : : TopRight ? Images : : Option : : RoundedTopRight : Images : : Option : : None )
| ( corners & RectPart : : BottomLeft ? Images : : Option : : RoundedBottomLeft : Images : : Option : : None )
| ( corners & RectPart : : BottomRight ? Images : : Option : : RoundedBottomRight : Images : : Option : : None ) ;
2016-11-28 15:45:07 +00:00
} ;
if ( radius = = ImageRoundRadius : : Large ) {
options | = Images : : Option : : RoundedLarge | cornerOptions ( corners ) ;
} else if ( radius = = ImageRoundRadius : : Small ) {
options | = Images : : Option : : RoundedSmall | cornerOptions ( corners ) ;
2017-04-02 11:30:03 +00:00
} else if ( radius = = ImageRoundRadius : : Ellipse ) {
options | = Images : : Option : : Circled | cornerOptions ( corners ) ;
2016-11-28 15:45:07 +00:00
}
auto k = PixKey ( w , h , options ) ;
auto i = _sizesCache . constFind ( k ) ;
if ( i = = _sizesCache . cend ( ) ) {
2018-07-13 21:25:47 +00:00
auto p = pixNoCache ( origin , w , h , options ) ;
2016-11-28 15:45:07 +00:00
if ( cRetina ( ) ) p . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
i = _sizesCache . insert ( k , p ) ;
if ( ! p . isNull ( ) ) {
globalAcquiredSize + = int64 ( p . width ( ) ) * p . height ( ) * 4 ;
}
}
return i . value ( ) ;
}
2018-07-13 21:25:47 +00:00
const QPixmap & Image : : pixCircled (
Data : : FileOrigin origin ,
int32 w ,
int32 h ) const {
2016-11-28 15:45:07 +00:00
checkload ( ) ;
2016-01-09 07:11:23 +00:00
2016-11-28 15:45:07 +00:00
if ( w < = 0 | | ! width ( ) | | ! height ( ) ) {
w = width ( ) ;
} else if ( cRetina ( ) ) {
w * = cIntRetinaFactor ( ) ;
h * = cIntRetinaFactor ( ) ;
}
auto options = Images : : Option : : Smooth | Images : : Option : : Circled ;
auto k = PixKey ( w , h , options ) ;
auto i = _sizesCache . constFind ( k ) ;
if ( i = = _sizesCache . cend ( ) ) {
2018-07-13 21:25:47 +00:00
auto p = pixNoCache ( origin , w , h , options ) ;
2016-11-28 15:45:07 +00:00
if ( cRetina ( ) ) p . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
i = _sizesCache . insert ( k , p ) ;
if ( ! p . isNull ( ) ) {
globalAcquiredSize + = int64 ( p . width ( ) ) * p . height ( ) * 4 ;
2014-08-11 09:03:45 +00:00
}
}
2016-11-28 15:45:07 +00:00
return i . value ( ) ;
2014-09-22 03:52:37 +00:00
}
2018-07-13 21:25:47 +00:00
const QPixmap & Image : : pixBlurredCircled (
Data : : FileOrigin origin ,
int32 w ,
int32 h ) const {
2016-12-03 12:10:35 +00:00
checkload ( ) ;
if ( w < = 0 | | ! width ( ) | | ! height ( ) ) {
w = width ( ) ;
} else if ( cRetina ( ) ) {
w * = cIntRetinaFactor ( ) ;
h * = cIntRetinaFactor ( ) ;
}
auto options = Images : : Option : : Smooth | Images : : Option : : Circled | Images : : Option : : Blurred ;
auto k = PixKey ( w , h , options ) ;
auto i = _sizesCache . constFind ( k ) ;
if ( i = = _sizesCache . cend ( ) ) {
2018-07-13 21:25:47 +00:00
auto p = pixNoCache ( origin , w , h , options ) ;
2016-12-03 12:10:35 +00:00
if ( cRetina ( ) ) p . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
i = _sizesCache . insert ( k , p ) ;
if ( ! p . isNull ( ) ) {
globalAcquiredSize + = int64 ( p . width ( ) ) * p . height ( ) * 4 ;
}
}
return i . value ( ) ;
}
2018-07-13 21:25:47 +00:00
const QPixmap & Image : : pixBlurred (
Data : : FileOrigin origin ,
int32 w ,
int32 h ) const {
2016-11-28 15:45:07 +00:00
checkload ( ) ;
2016-03-18 10:18:30 +00:00
2016-11-28 15:45:07 +00:00
if ( w < = 0 | | ! width ( ) | | ! height ( ) ) {
w = width ( ) * cIntRetinaFactor ( ) ;
} else if ( cRetina ( ) ) {
w * = cIntRetinaFactor ( ) ;
h * = cIntRetinaFactor ( ) ;
}
auto options = Images : : Option : : Smooth | Images : : Option : : Blurred ;
auto k = PixKey ( w , h , options ) ;
auto i = _sizesCache . constFind ( k ) ;
if ( i = = _sizesCache . cend ( ) ) {
2018-07-13 21:25:47 +00:00
auto p = pixNoCache ( origin , w , h , options ) ;
2016-11-28 15:45:07 +00:00
if ( cRetina ( ) ) p . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
i = _sizesCache . insert ( k , p ) ;
if ( ! p . isNull ( ) ) {
globalAcquiredSize + = int64 ( p . width ( ) ) * p . height ( ) * 4 ;
2016-03-18 10:18:30 +00:00
}
}
return i . value ( ) ;
}
2018-07-13 21:25:47 +00:00
const QPixmap & Image : : pixColored (
Data : : FileOrigin origin ,
style : : color add ,
int32 w ,
int32 h ) const {
2016-11-28 15:45:07 +00:00
checkload ( ) ;
2016-03-18 10:18:30 +00:00
2016-11-28 15:45:07 +00:00
if ( w < = 0 | | ! width ( ) | | ! height ( ) ) {
w = width ( ) * cIntRetinaFactor ( ) ;
} else if ( cRetina ( ) ) {
w * = cIntRetinaFactor ( ) ;
h * = cIntRetinaFactor ( ) ;
}
auto options = Images : : Option : : Smooth | Images : : Option : : Colored ;
auto k = PixKey ( w , h , options ) ;
auto i = _sizesCache . constFind ( k ) ;
if ( i = = _sizesCache . cend ( ) ) {
2018-07-13 21:25:47 +00:00
auto p = pixColoredNoCache ( origin , add , w , h , true ) ;
2016-11-28 15:45:07 +00:00
if ( cRetina ( ) ) p . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
i = _sizesCache . insert ( k , p ) ;
if ( ! p . isNull ( ) ) {
globalAcquiredSize + = int64 ( p . width ( ) ) * p . height ( ) * 4 ;
}
}
return i . value ( ) ;
2016-03-18 10:18:30 +00:00
}
2018-07-13 21:25:47 +00:00
const QPixmap & Image : : pixBlurredColored (
Data : : FileOrigin origin ,
style : : color add ,
int32 w ,
int32 h ) const {
2016-11-28 15:45:07 +00:00
checkload ( ) ;
if ( w < = 0 | | ! width ( ) | | ! height ( ) ) {
w = width ( ) * cIntRetinaFactor ( ) ;
} else if ( cRetina ( ) ) {
w * = cIntRetinaFactor ( ) ;
h * = cIntRetinaFactor ( ) ;
2016-11-21 20:26:54 +00:00
}
2016-11-28 15:45:07 +00:00
auto options = Images : : Option : : Blurred | Images : : Option : : Smooth | Images : : Option : : Colored ;
auto k = PixKey ( w , h , options ) ;
auto i = _sizesCache . constFind ( k ) ;
if ( i = = _sizesCache . cend ( ) ) {
2018-07-13 21:25:47 +00:00
auto p = pixBlurredColoredNoCache ( origin , add , w , h ) ;
2016-11-28 15:45:07 +00:00
if ( cRetina ( ) ) p . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
i = _sizesCache . insert ( k , p ) ;
if ( ! p . isNull ( ) ) {
globalAcquiredSize + = int64 ( p . width ( ) ) * p . height ( ) * 4 ;
}
}
return i . value ( ) ;
}
2016-02-28 13:23:03 +00:00
2018-07-13 21:25:47 +00:00
const QPixmap & Image : : pixSingle (
Data : : FileOrigin origin ,
int32 w ,
int32 h ,
int32 outerw ,
int32 outerh ,
ImageRoundRadius radius ,
RectParts corners ,
const style : : color * colored ) const {
2016-11-28 15:45:07 +00:00
checkload ( ) ;
2015-05-20 19:28:24 +00:00
2016-11-28 15:45:07 +00:00
if ( w < = 0 | | ! width ( ) | | ! height ( ) ) {
w = width ( ) * cIntRetinaFactor ( ) ;
} else if ( cRetina ( ) ) {
w * = cIntRetinaFactor ( ) ;
h * = cIntRetinaFactor ( ) ;
2016-02-28 13:23:03 +00:00
}
2016-11-21 20:26:54 +00:00
2016-11-28 15:45:07 +00:00
auto options = Images : : Option : : Smooth | Images : : Option : : None ;
2017-12-18 17:50:25 +00:00
auto cornerOptions = [ ] ( RectParts corners ) {
return ( corners & RectPart : : TopLeft ? Images : : Option : : RoundedTopLeft : Images : : Option : : None )
| ( corners & RectPart : : TopRight ? Images : : Option : : RoundedTopRight : Images : : Option : : None )
| ( corners & RectPart : : BottomLeft ? Images : : Option : : RoundedBottomLeft : Images : : Option : : None )
| ( corners & RectPart : : BottomRight ? Images : : Option : : RoundedBottomRight : Images : : Option : : None ) ;
2016-11-21 20:26:54 +00:00
} ;
2016-11-28 15:45:07 +00:00
if ( radius = = ImageRoundRadius : : Large ) {
options | = Images : : Option : : RoundedLarge | cornerOptions ( corners ) ;
} else if ( radius = = ImageRoundRadius : : Small ) {
options | = Images : : Option : : RoundedSmall | cornerOptions ( corners ) ;
2017-04-02 11:30:03 +00:00
} else if ( radius = = ImageRoundRadius : : Ellipse ) {
options | = Images : : Option : : Circled | cornerOptions ( corners ) ;
2015-01-05 20:17:33 +00:00
}
2017-06-06 09:15:13 +00:00
if ( colored ) {
options | = Images : : Option : : Colored ;
}
2015-01-05 20:17:33 +00:00
2016-11-28 15:45:07 +00:00
auto k = SinglePixKey ( options ) ;
auto i = _sizesCache . constFind ( k ) ;
if ( i = = _sizesCache . cend ( ) | | i - > width ( ) ! = ( outerw * cIntRetinaFactor ( ) ) | | i - > height ( ) ! = ( outerh * cIntRetinaFactor ( ) ) ) {
if ( i ! = _sizesCache . cend ( ) ) {
globalAcquiredSize - = int64 ( i - > width ( ) ) * i - > height ( ) * 4 ;
}
2018-07-13 21:25:47 +00:00
auto p = pixNoCache ( origin , w , h , options , outerw , outerh , colored ) ;
2016-11-28 15:45:07 +00:00
if ( cRetina ( ) ) p . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
i = _sizesCache . insert ( k , p ) ;
if ( ! p . isNull ( ) ) {
globalAcquiredSize + = int64 ( p . width ( ) ) * p . height ( ) * 4 ;
2015-01-05 20:17:33 +00:00
}
}
2016-11-28 15:45:07 +00:00
return i . value ( ) ;
2015-01-05 20:17:33 +00:00
}
2018-07-13 21:25:47 +00:00
const QPixmap & Image : : pixBlurredSingle (
Data : : FileOrigin origin ,
int w ,
int h ,
int32 outerw ,
int32 outerh ,
ImageRoundRadius radius ,
RectParts corners ) const {
2016-11-28 15:45:07 +00:00
checkload ( ) ;
if ( w < = 0 | | ! width ( ) | | ! height ( ) ) {
w = width ( ) * cIntRetinaFactor ( ) ;
} else if ( cRetina ( ) ) {
w * = cIntRetinaFactor ( ) ;
h * = cIntRetinaFactor ( ) ;
2016-02-28 13:23:03 +00:00
}
2016-11-28 15:45:07 +00:00
auto options = Images : : Option : : Smooth | Images : : Option : : Blurred ;
2017-12-18 17:50:25 +00:00
auto cornerOptions = [ ] ( RectParts corners ) {
return ( corners & RectPart : : TopLeft ? Images : : Option : : RoundedTopLeft : Images : : Option : : None )
| ( corners & RectPart : : TopRight ? Images : : Option : : RoundedTopRight : Images : : Option : : None )
| ( corners & RectPart : : BottomLeft ? Images : : Option : : RoundedBottomLeft : Images : : Option : : None )
| ( corners & RectPart : : BottomRight ? Images : : Option : : RoundedBottomRight : Images : : Option : : None ) ;
2016-11-28 15:45:07 +00:00
} ;
if ( radius = = ImageRoundRadius : : Large ) {
options | = Images : : Option : : RoundedLarge | cornerOptions ( corners ) ;
} else if ( radius = = ImageRoundRadius : : Small ) {
options | = Images : : Option : : RoundedSmall | cornerOptions ( corners ) ;
2017-04-02 11:30:03 +00:00
} else if ( radius = = ImageRoundRadius : : Ellipse ) {
options | = Images : : Option : : Circled | cornerOptions ( corners ) ;
2014-09-20 21:35:46 +00:00
}
2016-11-28 15:45:07 +00:00
auto k = SinglePixKey ( options ) ;
auto i = _sizesCache . constFind ( k ) ;
if ( i = = _sizesCache . cend ( ) | | i - > width ( ) ! = ( outerw * cIntRetinaFactor ( ) ) | | i - > height ( ) ! = ( outerh * cIntRetinaFactor ( ) ) ) {
if ( i ! = _sizesCache . cend ( ) ) {
globalAcquiredSize - = int64 ( i - > width ( ) ) * i - > height ( ) * 4 ;
}
2018-07-13 21:25:47 +00:00
auto p = pixNoCache ( origin , w , h , options , outerw , outerh ) ;
2016-11-28 15:45:07 +00:00
if ( cRetina ( ) ) p . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
i = _sizesCache . insert ( k , p ) ;
if ( ! p . isNull ( ) ) {
globalAcquiredSize + = int64 ( p . width ( ) ) * p . height ( ) * 4 ;
2015-05-20 19:28:24 +00:00
}
}
2016-11-28 15:45:07 +00:00
return i . value ( ) ;
2014-08-11 09:03:45 +00:00
}
2018-07-13 21:25:47 +00:00
QPixmap Image : : pixNoCache (
Data : : FileOrigin origin ,
int w ,
int h ,
Images : : Options options ,
int outerw ,
int outerh ,
const style : : color * colored ) const {
if ( ! loading ( ) ) const_cast < Image * > ( this ) - > load ( origin ) ;
2015-12-19 14:37:28 +00:00
restore ( ) ;
2016-02-28 13:23:03 +00:00
2016-01-09 07:11:23 +00:00
if ( _data . isNull ( ) ) {
if ( h < = 0 & & height ( ) > 0 ) {
h = qRound ( width ( ) * w / float64 ( height ( ) ) ) ;
}
2018-07-13 21:25:47 +00:00
return blank ( ) - > pixNoCache ( origin , w , h , options , outerw , outerh ) ;
2016-01-09 07:11:23 +00:00
}
2015-12-19 14:37:28 +00:00
if ( isNull ( ) & & outerw > 0 & & outerh > 0 ) {
outerw * = cIntRetinaFactor ( ) ;
outerh * = cIntRetinaFactor ( ) ;
QImage result ( outerw , outerh , QImage : : Format_ARGB32_Premultiplied ) ;
result . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
{
QPainter p ( & result ) ;
2016-01-09 07:11:23 +00:00
if ( w < outerw ) {
2016-10-31 12:29:26 +00:00
p . fillRect ( 0 , 0 , ( outerw - w ) / 2 , result . height ( ) , st : : imageBg ) ;
p . fillRect ( ( ( outerw - w ) / 2 ) + w , 0 , result . width ( ) - ( ( ( outerw - w ) / 2 ) + w ) , result . height ( ) , st : : imageBg ) ;
2016-01-09 07:11:23 +00:00
}
if ( h < outerh ) {
2016-10-31 12:29:26 +00:00
p . fillRect ( qMax ( 0 , ( outerw - w ) / 2 ) , 0 , qMin ( result . width ( ) , w ) , ( outerh - h ) / 2 , st : : imageBg ) ;
p . fillRect ( qMax ( 0 , ( outerw - w ) / 2 ) , ( ( outerh - h ) / 2 ) + h , qMin ( result . width ( ) , w ) , result . height ( ) - ( ( ( outerh - h ) / 2 ) + h ) , st : : imageBg ) ;
2016-01-09 07:11:23 +00:00
}
2016-10-31 12:29:26 +00:00
p . fillRect ( qMax ( 0 , ( outerw - w ) / 2 ) , qMax ( 0 , ( outerh - h ) / 2 ) , qMin ( result . width ( ) , w ) , qMin ( result . height ( ) , h ) , st : : imageBgTransparent ) ;
2015-12-19 14:37:28 +00:00
}
2016-11-28 15:45:07 +00:00
auto corners = [ ] ( Images : : Options options ) {
2017-12-18 17:50:25 +00:00
return ( ( options & Images : : Option : : RoundedTopLeft ) ? RectPart : : TopLeft : RectPart : : None )
| ( ( options & Images : : Option : : RoundedTopRight ) ? RectPart : : TopRight : RectPart : : None )
| ( ( options & Images : : Option : : RoundedBottomLeft ) ? RectPart : : BottomLeft : RectPart : : None )
| ( ( options & Images : : Option : : RoundedBottomRight ) ? RectPart : : BottomRight : RectPart : : None ) ;
2016-11-21 20:26:54 +00:00
} ;
2017-08-31 16:28:58 +00:00
if ( options & Images : : Option : : Circled ) {
2016-11-28 15:45:07 +00:00
Images : : prepareCircle ( result ) ;
2017-08-31 16:28:58 +00:00
} else if ( options & Images : : Option : : RoundedLarge ) {
2016-11-28 15:45:07 +00:00
Images : : prepareRound ( result , ImageRoundRadius : : Large , corners ( options ) ) ;
2017-08-31 16:28:58 +00:00
} else if ( options & Images : : Option : : RoundedSmall ) {
2016-11-28 15:45:07 +00:00
Images : : prepareRound ( result , ImageRoundRadius : : Small , corners ( options ) ) ;
2016-03-18 10:18:30 +00:00
}
2017-08-31 16:28:58 +00:00
if ( options & Images : : Option : : Colored ) {
2017-08-17 09:06:26 +00:00
Assert ( colored ! = nullptr ) ;
2017-06-06 09:15:13 +00:00
result = Images : : prepareColored ( * colored , std : : move ( result ) ) ;
}
2017-02-21 13:45:56 +00:00
return App : : pixmapFromImageInPlace ( std : : move ( result ) ) ;
2015-12-19 14:37:28 +00:00
}
2016-02-28 13:23:03 +00:00
2017-06-06 09:15:13 +00:00
return Images : : pixmap ( _data . toImage ( ) , w , h , options , outerw , outerh , colored ) ;
2015-12-19 14:37:28 +00:00
}
2018-07-13 21:25:47 +00:00
QPixmap Image : : pixColoredNoCache (
Data : : FileOrigin origin ,
style : : color add ,
int32 w ,
int32 h ,
bool smooth ) const {
const_cast < Image * > ( this ) - > load ( origin ) ;
2014-05-30 08:53:19 +00:00
restore ( ) ;
2018-07-13 21:25:47 +00:00
if ( _data . isNull ( ) ) return blank ( ) - > pix ( origin ) ;
2014-05-30 08:53:19 +00:00
2017-06-06 09:15:13 +00:00
auto img = _data . toImage ( ) ;
if ( w < = 0 | | ! width ( ) | | ! height ( ) | | ( w = = width ( ) & & ( h < = 0 | | h = = height ( ) ) ) ) {
return App : : pixmapFromImageInPlace ( Images : : prepareColored ( add , std : : move ( img ) ) ) ;
}
2014-05-30 08:53:19 +00:00
if ( h < = 0 ) {
2016-11-28 15:45:07 +00:00
return App : : pixmapFromImageInPlace ( Images : : prepareColored ( add , img . scaledToWidth ( w , smooth ? Qt : : SmoothTransformation : Qt : : FastTransformation ) ) ) ;
2014-05-30 08:53:19 +00:00
}
2016-11-28 15:45:07 +00:00
return App : : pixmapFromImageInPlace ( Images : : prepareColored ( add , img . scaled ( w , h , Qt : : IgnoreAspectRatio , smooth ? Qt : : SmoothTransformation : Qt : : FastTransformation ) ) ) ;
2015-01-05 20:17:33 +00:00
}
2018-07-13 21:25:47 +00:00
QPixmap Image : : pixBlurredColoredNoCache (
Data : : FileOrigin origin ,
style : : color add ,
int32 w ,
int32 h ) const {
const_cast < Image * > ( this ) - > load ( origin ) ;
2015-01-05 20:17:33 +00:00
restore ( ) ;
2018-07-13 21:25:47 +00:00
if ( _data . isNull ( ) ) return blank ( ) - > pix ( origin ) ;
2015-01-05 20:17:33 +00:00
2017-05-24 14:36:58 +00:00
auto img = Images : : prepareBlur ( _data . toImage ( ) ) ;
2015-01-05 20:17:33 +00:00
if ( h < = 0 ) {
img = img . scaledToWidth ( w , Qt : : SmoothTransformation ) ;
} else {
img = img . scaled ( w , h , Qt : : IgnoreAspectRatio , Qt : : SmoothTransformation ) ;
}
2016-11-28 15:45:07 +00:00
return App : : pixmapFromImageInPlace ( Images : : prepareColored ( add , img ) ) ;
2014-05-30 08:53:19 +00:00
}
void Image : : forget ( ) const {
2015-12-25 13:09:14 +00:00
if ( _forgot ) return ;
2014-05-30 08:53:19 +00:00
2015-12-25 13:09:14 +00:00
if ( _data . isNull ( ) ) return ;
2014-05-30 08:53:19 +00:00
invalidateSizeCache ( ) ;
2018-04-07 07:01:32 +00:00
/*if (hasLocalCopy()) {
_saved . clear ( ) ;
} else */ if ( _saved . isEmpty ( ) ) {
2015-12-25 13:09:14 +00:00
QBuffer buffer ( & _saved ) ;
if ( ! _data . save ( & buffer , _format ) ) {
if ( _data . save ( & buffer , " PNG " ) ) {
_format = " PNG " ;
2014-12-22 23:11:37 +00:00
} else {
return ;
}
}
2014-05-30 08:53:19 +00:00
}
2015-12-30 06:47:39 +00:00
globalAcquiredSize - = int64 ( _data . width ( ) ) * _data . height ( ) * 4 ;
2015-12-25 13:09:14 +00:00
_data = QPixmap ( ) ;
_forgot = true ;
2014-05-30 08:53:19 +00:00
}
void Image : : restore ( ) const {
2015-12-25 13:09:14 +00:00
if ( ! _forgot ) return ;
QBuffer buffer ( & _saved ) ;
QImageReader reader ( & buffer , _format ) ;
2016-08-30 05:24:16 +00:00
# ifndef OS_MAC_OLD
2015-12-25 13:09:14 +00:00
reader . setAutoTransform ( true ) ;
2016-08-30 05:24:16 +00:00
# endif // OS_MAC_OLD
2015-12-25 13:09:14 +00:00
_data = QPixmap : : fromImageReader ( & reader , Qt : : ColorOnly ) ;
if ( ! _data . isNull ( ) ) {
2015-12-30 06:47:39 +00:00
globalAcquiredSize + = int64 ( _data . width ( ) ) * _data . height ( ) * 4 ;
2014-05-30 08:53:19 +00:00
}
2015-12-25 13:09:14 +00:00
_forgot = false ;
2014-05-30 08:53:19 +00:00
}
2018-09-21 16:28:46 +00:00
std : : optional < Storage : : Cache : : Key > Image : : cacheKey ( ) const {
return std : : nullopt ;
2018-08-27 11:35:58 +00:00
}
2014-05-30 08:53:19 +00:00
void Image : : invalidateSizeCache ( ) const {
2016-11-22 08:36:02 +00:00
for ( auto & pix : _sizesCache ) {
if ( ! pix . isNull ( ) ) {
globalAcquiredSize - = int64 ( pix . width ( ) ) * pix . height ( ) * 4 ;
2014-05-30 08:53:19 +00:00
}
}
_sizesCache . clear ( ) ;
}
2015-12-25 13:09:14 +00:00
Image : : ~ Image ( ) {
invalidateSizeCache ( ) ;
if ( ! _data . isNull ( ) ) {
2015-12-30 06:47:39 +00:00
globalAcquiredSize - = int64 ( _data . width ( ) ) * _data . height ( ) * 4 ;
2014-12-22 23:11:37 +00:00
}
}
2014-05-30 08:53:19 +00:00
void clearStorageImages ( ) {
2016-11-21 20:26:54 +00:00
for ( auto image : base : : take ( storageImages ) ) {
delete image ;
2014-05-30 08:53:19 +00:00
}
2016-11-21 20:26:54 +00:00
for ( auto image : base : : take ( webImages ) ) {
delete image ;
2015-12-30 19:09:20 +00:00
}
2017-03-05 17:33:32 +00:00
for ( auto image : base : : take ( webFileImages ) ) {
delete image ;
}
2014-05-30 08:53:19 +00:00
}
void clearAllImages ( ) {
2016-11-21 20:26:54 +00:00
for ( auto image : base : : take ( localImages ) ) {
delete image ;
2014-05-30 08:53:19 +00:00
}
clearStorageImages ( ) ;
}
int64 imageCacheSize ( ) {
2015-12-30 06:47:39 +00:00
return globalAcquiredSize ;
2014-05-30 08:53:19 +00:00
}
2015-12-30 19:09:20 +00:00
void RemoteImage : : doCheckload ( ) const {
2017-03-04 11:28:21 +00:00
if ( ! amLoading ( ) | | ! _loader - > finished ( ) ) return ;
2014-05-30 08:53:19 +00:00
2016-04-10 14:53:01 +00:00
QPixmap data = _loader - > imagePixmap ( shrinkBox ( ) ) ;
2015-12-24 19:26:28 +00:00
if ( data . isNull ( ) ) {
2017-02-25 16:44:02 +00:00
destroyLoaderDelayed ( CancelledFileLoader ) ;
2015-12-24 19:26:28 +00:00
return ;
}
2014-05-30 08:53:19 +00:00
2015-12-24 19:26:28 +00:00
if ( ! _data . isNull ( ) ) {
2015-12-30 06:47:39 +00:00
globalAcquiredSize - = int64 ( _data . width ( ) ) * _data . height ( ) * 4 ;
2014-05-30 08:53:19 +00:00
}
2015-12-24 19:26:28 +00:00
2016-04-10 14:53:01 +00:00
_format = _loader - > imageFormat ( shrinkBox ( ) ) ;
2015-12-24 19:26:28 +00:00
_data = data ;
2015-12-25 13:09:14 +00:00
_saved = _loader - > bytes ( ) ;
2015-12-30 19:09:20 +00:00
const_cast < RemoteImage * > ( this ) - > setInformation ( _saved . size ( ) , _data . width ( ) , _data . height ( ) ) ;
2015-12-30 06:47:39 +00:00
globalAcquiredSize + = int64 ( _data . width ( ) ) * _data . height ( ) * 4 ;
2015-12-24 19:26:28 +00:00
invalidateSizeCache ( ) ;
2017-02-25 16:44:02 +00:00
destroyLoaderDelayed ( ) ;
2015-12-24 19:26:28 +00:00
2015-12-25 13:09:14 +00:00
_forgot = false ;
2014-05-30 08:53:19 +00:00
}
2017-02-25 16:44:02 +00:00
void RemoteImage : : destroyLoaderDelayed ( FileLoader * newValue ) const {
_loader - > stop ( ) ;
auto loader = std : : unique_ptr < FileLoader > ( std : : exchange ( _loader , newValue ) ) ;
2017-08-04 14:54:32 +00:00
Auth ( ) . downloader ( ) . delayedDestroyLoader ( std : : move ( loader ) ) ;
2017-02-25 16:44:02 +00:00
}
2015-12-31 15:27:21 +00:00
void RemoteImage : : loadLocal ( ) {
if ( loaded ( ) | | amLoading ( ) ) return ;
2018-09-21 16:28:46 +00:00
_loader = createLoader ( std : : nullopt , LoadFromLocalOnly , true ) ;
2015-12-31 15:27:21 +00:00
if ( _loader ) _loader - > start ( ) ;
}
2018-08-27 11:35:58 +00:00
void RemoteImage : : setImageBytes (
const QByteArray & bytes ,
const QByteArray & bytesFormat ) {
2015-12-24 19:26:28 +00:00
if ( ! _data . isNull ( ) ) {
2015-12-30 06:47:39 +00:00
globalAcquiredSize - = int64 ( _data . width ( ) ) * _data . height ( ) * 4 ;
2014-05-30 08:53:19 +00:00
}
2015-12-24 19:26:28 +00:00
QByteArray fmt ( bytesFormat ) ;
2016-07-13 17:34:57 +00:00
_data = App : : pixmapFromImageInPlace ( App : : readImage ( bytes , & fmt , false ) ) ;
2015-12-24 19:26:28 +00:00
if ( ! _data . isNull ( ) ) {
2015-12-30 06:47:39 +00:00
globalAcquiredSize + = int64 ( _data . width ( ) ) * _data . height ( ) * 4 ;
2015-12-30 19:09:20 +00:00
setInformation ( bytes . size ( ) , _data . width ( ) , _data . height ( ) ) ;
2014-05-30 08:53:19 +00:00
}
invalidateSizeCache ( ) ;
2015-12-24 19:26:28 +00:00
if ( amLoading ( ) ) {
2017-02-25 16:44:02 +00:00
destroyLoaderDelayed ( ) ;
2014-05-30 08:53:19 +00:00
}
2015-12-25 13:09:14 +00:00
_saved = bytes ;
_format = fmt ;
_forgot = false ;
2018-08-27 11:35:58 +00:00
const auto location = this - > location ( ) ;
2018-09-04 19:33:57 +00:00
if ( ! location . isNull ( )
& & ! bytes . isEmpty ( )
& & bytes . size ( ) < = Storage : : kMaxFileInMemory ) {
2018-08-28 20:49:16 +00:00
Auth ( ) . data ( ) . cache ( ) . putIfEmpty (
Data : : StorageCacheKey ( location ) ,
2018-08-28 21:09:55 +00:00
Storage : : Cache : : Database : : TaggedValue (
base : : duplicate ( bytes ) ,
Data : : kImageCacheTag ) ) ;
2018-08-27 11:35:58 +00:00
}
2014-05-30 08:53:19 +00:00
}
2017-03-04 19:36:59 +00:00
bool RemoteImage : : amLoading ( ) const {
return _loader & & _loader ! = CancelledFileLoader ;
}
2018-07-13 21:25:47 +00:00
void RemoteImage : : automaticLoad (
Data : : FileOrigin origin ,
const HistoryItem * item ) {
2015-12-24 19:26:28 +00:00
if ( loaded ( ) ) return ;
if ( _loader ! = CancelledFileLoader & & item ) {
bool loadFromCloud = false ;
if ( item - > history ( ) - > peer - > isUser ( ) ) {
loadFromCloud = ! ( cAutoDownloadPhoto ( ) & dbiadNoPrivate ) ;
} else {
loadFromCloud = ! ( cAutoDownloadPhoto ( ) & dbiadNoGroups ) ;
}
if ( _loader ) {
if ( loadFromCloud ) _loader - > permitLoadFromCloud ( ) ;
2015-12-30 19:09:20 +00:00
} else {
2018-07-13 21:25:47 +00:00
_loader = createLoader (
origin ,
loadFromCloud ? LoadFromCloudOrLocal : LoadFromLocalOnly ,
true ) ;
2015-12-30 19:09:20 +00:00
if ( _loader ) _loader - > start ( ) ;
2015-12-24 19:26:28 +00:00
}
}
}
2015-12-30 19:09:20 +00:00
void RemoteImage : : automaticLoadSettingsChanged ( ) {
2015-12-27 21:37:48 +00:00
if ( loaded ( ) | | _loader ! = CancelledFileLoader ) return ;
_loader = 0 ;
}
2018-07-13 21:25:47 +00:00
void RemoteImage : : load (
Data : : FileOrigin origin ,
bool loadFirst ,
bool prior ) {
2015-12-24 19:26:28 +00:00
if ( loaded ( ) ) return ;
2015-12-30 19:09:20 +00:00
if ( ! _loader ) {
2018-07-13 21:25:47 +00:00
_loader = createLoader ( origin , LoadFromCloudOrLocal , false ) ;
2015-12-24 19:26:28 +00:00
}
if ( amLoading ( ) ) {
_loader - > start ( loadFirst , prior ) ;
}
}
2018-07-13 21:25:47 +00:00
void RemoteImage : : loadEvenCancelled (
Data : : FileOrigin origin ,
bool loadFirst ,
bool prior ) {
if ( _loader = = CancelledFileLoader ) {
_loader = nullptr ;
}
return load ( origin , loadFirst , prior ) ;
2015-12-24 19:26:28 +00:00
}
2015-12-30 19:09:20 +00:00
RemoteImage : : ~ RemoteImage ( ) {
2015-12-24 19:26:28 +00:00
if ( ! _data . isNull ( ) ) {
2015-12-30 06:47:39 +00:00
globalAcquiredSize - = int64 ( _data . width ( ) ) * _data . height ( ) * 4 ;
2014-05-30 08:53:19 +00:00
}
2015-12-24 19:26:28 +00:00
if ( amLoading ( ) ) {
2017-02-25 16:44:02 +00:00
destroyLoaderDelayed ( ) ;
2014-05-30 08:53:19 +00:00
}
}
2015-12-30 19:09:20 +00:00
bool RemoteImage : : loaded ( ) const {
2015-12-25 13:09:14 +00:00
doCheckload ( ) ;
return ( ! _data . isNull ( ) | | ! _saved . isNull ( ) ) ;
2015-12-24 19:26:28 +00:00
}
2015-12-30 19:09:20 +00:00
bool RemoteImage : : displayLoading ( ) const {
2015-12-24 19:26:28 +00:00
return amLoading ( ) & & ( ! _loader - > loadingLocal ( ) | | ! _loader - > autoLoading ( ) ) ;
}
2015-12-30 19:09:20 +00:00
void RemoteImage : : cancel ( ) {
2015-12-24 19:26:28 +00:00
if ( ! amLoading ( ) ) return ;
2017-02-25 16:44:02 +00:00
auto loader = std : : exchange ( _loader , CancelledFileLoader ) ;
loader - > cancel ( ) ;
loader - > stop ( ) ;
2017-08-04 14:54:32 +00:00
Auth ( ) . downloader ( ) . delayedDestroyLoader ( std : : unique_ptr < FileLoader > ( loader ) ) ;
2015-12-24 19:26:28 +00:00
}
2015-12-30 19:09:20 +00:00
float64 RemoteImage : : progress ( ) const {
2015-12-24 19:26:28 +00:00
return amLoading ( ) ? _loader - > currentProgress ( ) : ( loaded ( ) ? 1 : 0 ) ;
}
2015-12-30 19:09:20 +00:00
int32 RemoteImage : : loadOffset ( ) const {
2015-12-24 19:26:28 +00:00
return amLoading ( ) ? _loader - > currentOffset ( ) : 0 ;
2014-05-30 08:53:19 +00:00
}
2015-12-30 19:09:20 +00:00
StorageImage : : StorageImage ( const StorageImageLocation & location , int32 size )
2016-04-10 14:53:01 +00:00
: _location ( location )
, _size ( size ) {
2015-12-30 19:09:20 +00:00
}
2018-08-27 11:35:58 +00:00
StorageImage : : StorageImage (
const StorageImageLocation & location ,
const QByteArray & bytes )
2016-04-10 14:53:01 +00:00
: _location ( location )
, _size ( bytes . size ( ) ) {
2018-08-27 11:35:58 +00:00
setImageBytes ( bytes ) ;
}
2018-09-21 16:28:46 +00:00
std : : optional < Storage : : Cache : : Key > StorageImage : : cacheKey ( ) const {
2018-08-27 11:35:58 +00:00
return _location . isNull ( )
2018-09-21 16:28:46 +00:00
? std : : nullopt
2018-08-27 11:35:58 +00:00
: base : : make_optional ( Data : : StorageCacheKey ( _location ) ) ;
2015-12-30 19:09:20 +00:00
}
2016-01-30 16:31:10 +00:00
int32 StorageImage : : countWidth ( ) const {
2015-12-30 19:09:20 +00:00
return _location . width ( ) ;
}
2016-01-30 16:31:10 +00:00
int32 StorageImage : : countHeight ( ) const {
2015-12-30 19:09:20 +00:00
return _location . height ( ) ;
}
void StorageImage : : setInformation ( int32 size , int32 width , int32 height ) {
_size = size ;
_location . setSize ( width , height ) ;
}
2018-07-13 21:25:47 +00:00
FileLoader * StorageImage : : createLoader (
Data : : FileOrigin origin ,
LoadFromCloudSetting fromCloud ,
bool autoLoading ) {
2018-07-15 16:36:19 +00:00
if ( _location . isNull ( ) ) {
return nullptr ;
}
2018-07-13 21:25:47 +00:00
return new mtpFileLoader (
& _location ,
origin ,
_size ,
fromCloud ,
2018-08-28 21:09:55 +00:00
autoLoading ,
Data : : kImageCacheTag ) ;
2015-12-30 19:09:20 +00:00
}
2018-03-04 20:04:13 +00:00
WebFileImage : : WebFileImage (
const WebFileLocation & location ,
QSize box ,
int size )
2017-03-05 17:33:32 +00:00
: _location ( location )
2018-03-04 20:04:13 +00:00
, _box ( box )
, _width ( 0 )
, _height ( 0 )
2017-03-05 17:33:32 +00:00
, _size ( size ) {
}
2018-03-04 20:04:13 +00:00
WebFileImage : : WebFileImage (
const WebFileLocation & location ,
int width ,
int height ,
int size )
: _location ( location )
, _width ( width )
, _height ( height )
, _size ( size ) {
2017-03-05 17:33:32 +00:00
}
2018-09-21 16:28:46 +00:00
std : : optional < Storage : : Cache : : Key > WebFileImage : : cacheKey ( ) const {
2018-08-27 11:35:58 +00:00
return _location . isNull ( )
2018-09-21 16:28:46 +00:00
? std : : nullopt
2018-08-27 11:35:58 +00:00
: base : : make_optional ( Data : : WebDocumentCacheKey ( _location ) ) ;
}
2018-03-04 20:04:13 +00:00
int WebFileImage : : countWidth ( ) const {
return _width ;
2017-03-05 17:33:32 +00:00
}
2018-03-04 20:04:13 +00:00
int WebFileImage : : countHeight ( ) const {
return _height ;
}
void WebFileImage : : setInformation ( int size , int width , int height ) {
2017-03-05 17:33:32 +00:00
_size = size ;
2018-03-04 20:04:13 +00:00
_width = width ;
_height = height ;
2017-03-05 17:33:32 +00:00
}
2018-03-04 20:04:13 +00:00
FileLoader * WebFileImage : : createLoader (
2018-07-13 21:25:47 +00:00
Data : : FileOrigin origin ,
2018-03-04 20:04:13 +00:00
LoadFromCloudSetting fromCloud ,
bool autoLoading ) {
2018-07-13 21:25:47 +00:00
return _location . isNull ( )
? nullptr
: new mtpFileLoader (
& _location ,
_size ,
fromCloud ,
2018-08-28 21:09:55 +00:00
autoLoading ,
Data : : kImageCacheTag ) ;
2017-03-05 17:33:32 +00:00
}
2015-12-31 15:27:21 +00:00
DelayedStorageImage : : DelayedStorageImage ( ) : StorageImage ( StorageImageLocation ( ) )
, _loadRequested ( false )
, _loadCancelled ( false )
, _loadFromCloud ( false ) {
}
2018-07-13 16:49:46 +00:00
DelayedStorageImage : : DelayedStorageImage ( int32 w , int32 h )
: StorageImage ( StorageImageLocation ( w , h , 0 , 0 , 0 , 0 , { } ) )
2015-12-31 15:27:21 +00:00
, _loadRequested ( false )
, _loadCancelled ( false )
, _loadFromCloud ( false ) {
}
2018-08-27 11:35:58 +00:00
//
//DelayedStorageImage::DelayedStorageImage(QByteArray &bytes)
//: StorageImage(StorageImageLocation(), bytes)
//, _loadRequested(false)
//, _loadCancelled(false)
//, _loadFromCloud(false) {
//}
2015-12-31 15:27:21 +00:00
2018-07-13 16:49:46 +00:00
void DelayedStorageImage : : setStorageLocation (
2018-07-13 21:25:47 +00:00
Data : : FileOrigin origin ,
2018-07-13 16:49:46 +00:00
const StorageImageLocation location ) {
2015-12-31 15:27:21 +00:00
_location = location ;
if ( _loadRequested ) {
if ( ! _loadCancelled ) {
if ( _loadFromCloud ) {
2018-07-13 21:25:47 +00:00
load ( origin ) ;
2015-12-31 15:27:21 +00:00
} else {
loadLocal ( ) ;
}
}
_loadRequested = false ;
}
}
2018-07-13 21:25:47 +00:00
void DelayedStorageImage : : automaticLoad (
Data : : FileOrigin origin ,
const HistoryItem * item ) {
2015-12-31 15:27:21 +00:00
if ( _location . isNull ( ) ) {
if ( ! _loadCancelled & & item ) {
bool loadFromCloud = false ;
if ( item - > history ( ) - > peer - > isUser ( ) ) {
loadFromCloud = ! ( cAutoDownloadPhoto ( ) & dbiadNoPrivate ) ;
} else {
loadFromCloud = ! ( cAutoDownloadPhoto ( ) & dbiadNoGroups ) ;
}
if ( _loadRequested ) {
if ( loadFromCloud ) _loadFromCloud = loadFromCloud ;
} else {
_loadFromCloud = loadFromCloud ;
_loadRequested = true ;
}
}
} else {
2018-07-13 21:25:47 +00:00
StorageImage : : automaticLoad ( origin , item ) ;
2015-12-31 15:27:21 +00:00
}
}
void DelayedStorageImage : : automaticLoadSettingsChanged ( ) {
if ( _loadCancelled ) _loadCancelled = false ;
StorageImage : : automaticLoadSettingsChanged ( ) ;
}
2018-07-13 21:25:47 +00:00
void DelayedStorageImage : : load (
Data : : FileOrigin origin ,
bool loadFirst ,
bool prior ) {
2015-12-31 15:27:21 +00:00
if ( _location . isNull ( ) ) {
_loadRequested = _loadFromCloud = true ;
} else {
2018-07-13 21:25:47 +00:00
StorageImage : : load ( origin , loadFirst , prior ) ;
2015-12-31 15:27:21 +00:00
}
}
2018-07-13 21:25:47 +00:00
void DelayedStorageImage : : loadEvenCancelled (
Data : : FileOrigin origin ,
bool loadFirst ,
bool prior ) {
2015-12-31 15:27:21 +00:00
_loadCancelled = false ;
2018-07-13 21:25:47 +00:00
StorageImage : : loadEvenCancelled ( origin , loadFirst , prior ) ;
2015-12-31 15:27:21 +00:00
}
bool DelayedStorageImage : : displayLoading ( ) const {
return _location . isNull ( ) ? true : StorageImage : : displayLoading ( ) ;
}
void DelayedStorageImage : : cancel ( ) {
if ( _loadRequested ) {
_loadRequested = false ;
}
StorageImage : : cancel ( ) ;
}
2018-03-04 20:04:13 +00:00
WebImage : : WebImage ( const QString & url , QSize box )
: _url ( url )
, _box ( box )
, _size ( 0 )
, _width ( 0 )
, _height ( 0 ) {
2016-04-10 11:13:37 +00:00
}
2018-03-04 20:04:13 +00:00
WebImage : : WebImage ( const QString & url , int width , int height )
: _url ( url )
, _size ( 0 )
, _width ( width )
, _height ( height ) {
2016-04-10 18:18:26 +00:00
}
2018-09-21 16:28:46 +00:00
std : : optional < Storage : : Cache : : Key > WebImage : : cacheKey ( ) const {
2018-08-27 11:35:58 +00:00
return Data : : UrlCacheKey ( _url ) ;
}
2016-04-10 18:18:26 +00:00
void WebImage : : setSize ( int width , int height ) {
_width = width ;
_height = height ;
}
2016-04-10 11:13:37 +00:00
int32 WebImage : : countWidth ( ) const {
return _width ;
}
int32 WebImage : : countHeight ( ) const {
return _height ;
}
void WebImage : : setInformation ( int32 size , int32 width , int32 height ) {
_size = size ;
2016-04-10 18:18:26 +00:00
setSize ( width , height ) ;
2016-04-10 11:13:37 +00:00
}
2018-07-13 21:25:47 +00:00
FileLoader * WebImage : : createLoader (
Data : : FileOrigin origin ,
LoadFromCloudSetting fromCloud ,
bool autoLoading ) {
2018-08-28 21:09:55 +00:00
return new webFileLoader (
_url ,
QString ( ) ,
fromCloud ,
autoLoading ,
Data : : kImageCacheTag ) ;
2016-04-10 11:13:37 +00:00
}
namespace internal {
Image * getImage ( const QString & file , QByteArray format ) {
if ( file . startsWith ( qstr ( " http:// " ) , Qt : : CaseInsensitive ) | | file . startsWith ( qstr ( " https:// " ) , Qt : : CaseInsensitive ) ) {
QString key = file ;
WebImages : : const_iterator i = webImages . constFind ( key ) ;
if ( i = = webImages . cend ( ) ) {
i = webImages . insert ( key , new WebImage ( file ) ) ;
}
return i . value ( ) ;
} else {
QFileInfo f ( file ) ;
QString key = qsl ( " //:%1//:%2//: " ) . arg ( f . size ( ) ) . arg ( f . lastModified ( ) . toTime_t ( ) ) + file ;
LocalImages : : const_iterator i = localImages . constFind ( key ) ;
if ( i = = localImages . cend ( ) ) {
i = localImages . insert ( key , new Image ( file , format ) ) ;
}
return i . value ( ) ;
}
}
Image * getImage ( const QString & url , QSize box ) {
QString key = qsl ( " //:%1//:%2//: " ) . arg ( box . width ( ) ) . arg ( box . height ( ) ) + url ;
auto i = webImages . constFind ( key ) ;
if ( i = = webImages . cend ( ) ) {
i = webImages . insert ( key , new WebImage ( url , box ) ) ;
}
return i . value ( ) ;
}
2016-04-10 18:18:26 +00:00
Image * getImage ( const QString & url , int width , int height ) {
QString key = url ;
auto i = webImages . constFind ( key ) ;
if ( i = = webImages . cend ( ) ) {
i = webImages . insert ( key , new WebImage ( url , width , height ) ) ;
} else {
i . value ( ) - > setSize ( width , height ) ;
}
return i . value ( ) ;
}
2016-04-10 11:13:37 +00:00
Image * getImage ( const QByteArray & filecontent , QByteArray format ) {
return new Image ( filecontent , format ) ;
}
Image * getImage ( const QPixmap & pixmap , QByteArray format ) {
return new Image ( pixmap , format ) ;
}
Image * getImage ( const QByteArray & filecontent , QByteArray format , const QPixmap & pixmap ) {
return new Image ( filecontent , format , pixmap ) ;
}
Image * getImage ( int32 width , int32 height ) {
return new DelayedStorageImage ( width , height ) ;
}
2015-05-19 15:46:45 +00:00
StorageImage * getImage ( const StorageImageLocation & location , int32 size ) {
2018-08-27 11:35:58 +00:00
const auto key = storageKey ( location ) ;
auto i = storageImages . constFind ( key ) ;
2014-05-30 08:53:19 +00:00
if ( i = = storageImages . cend ( ) ) {
2015-05-19 15:46:45 +00:00
i = storageImages . insert ( key , new StorageImage ( location , size ) ) ;
2018-08-28 11:32:27 +00:00
} else {
i . value ( ) - > refreshFileReference ( location . fileReference ( ) ) ;
2014-05-30 08:53:19 +00:00
}
return i . value ( ) ;
}
2018-08-27 11:35:58 +00:00
StorageImage * getImage (
const StorageImageLocation & location ,
const QByteArray & bytes ) {
const auto key = storageKey ( location ) ;
auto i = storageImages . constFind ( key ) ;
2016-04-10 11:13:37 +00:00
if ( i = = storageImages . cend ( ) ) {
2018-08-27 11:35:58 +00:00
i = storageImages . insert ( key , new StorageImage ( location , bytes ) ) ;
2018-08-28 11:32:27 +00:00
} else {
i . value ( ) - > refreshFileReference ( location . fileReference ( ) ) ;
if ( ! i . value ( ) - > loaded ( ) ) {
2018-08-27 11:35:58 +00:00
i . value ( ) - > setImageBytes ( bytes ) ;
2015-05-19 15:46:45 +00:00
}
2014-05-30 08:53:19 +00:00
}
return i . value ( ) ;
}
2015-11-26 17:34:52 +00:00
2018-03-04 20:04:13 +00:00
QSize getImageSize ( const QVector < MTPDocumentAttribute > & attributes ) {
for ( const auto & attribute : attributes ) {
if ( attribute . type ( ) = = mtpc_documentAttributeImageSize ) {
auto & size = attribute . c_documentAttributeImageSize ( ) ;
return QSize ( size . vw . v , size . vh . v ) ;
}
}
return QSize ( ) ;
}
Image * getImage ( const MTPDwebDocument & document ) {
const auto size = getImageSize ( document . vattributes . v ) ;
if ( size . isEmpty ( ) ) {
return blank ( ) ;
}
// We don't use size from WebDocument, because it is not reliable.
// It can be > 0 and different from the real size that we get in upload.WebFile result.
auto filesize = 0 ; // document.vsize.v;
return getImage (
WebFileLocation (
2018-06-26 13:58:29 +00:00
Global : : WebFileDcId ( ) ,
2018-03-04 20:04:13 +00:00
document . vurl . v ,
document . vaccess_hash . v ) ,
size . width ( ) ,
size . height ( ) ,
filesize ) ;
}
Image * getImage ( const MTPDwebDocumentNoProxy & document ) {
const auto size = getImageSize ( document . vattributes . v ) ;
if ( size . isEmpty ( ) ) {
return blank ( ) ;
}
return getImage ( qs ( document . vurl ) , size . width ( ) , size . height ( ) ) ;
}
Image * getImage ( const MTPDwebDocument & document , QSize box ) {
2018-03-13 10:29:42 +00:00
//const auto size = getImageSize(document.vattributes.v);
//if (size.isEmpty()) {
// return blank();
//}
2018-03-04 20:04:13 +00:00
// We don't use size from WebDocument, because it is not reliable.
// It can be > 0 and different from the real size that we get in upload.WebFile result.
auto filesize = 0 ; // document.vsize.v;
return getImage (
WebFileLocation (
2018-06-26 13:58:29 +00:00
Global : : WebFileDcId ( ) ,
2018-03-04 20:04:13 +00:00
document . vurl . v ,
document . vaccess_hash . v ) ,
box ,
filesize ) ;
}
Image * getImage ( const MTPDwebDocumentNoProxy & document , QSize box ) {
2018-03-13 10:29:42 +00:00
//const auto size = getImageSize(document.vattributes.v);
//if (size.isEmpty()) {
// return blank();
//}
2018-03-04 20:04:13 +00:00
return getImage ( qs ( document . vurl ) , box ) ;
}
Image * getImage ( const MTPWebDocument & document ) {
switch ( document . type ( ) ) {
case mtpc_webDocument :
return getImage ( document . c_webDocument ( ) ) ;
case mtpc_webDocumentNoProxy :
return getImage ( document . c_webDocumentNoProxy ( ) ) ;
}
Unexpected ( " Type in getImage(MTPWebDocument). " ) ;
}
Image * getImage ( const MTPWebDocument & document , QSize box ) {
switch ( document . type ( ) ) {
case mtpc_webDocument :
return getImage ( document . c_webDocument ( ) , box ) ;
case mtpc_webDocumentNoProxy :
return getImage ( document . c_webDocumentNoProxy ( ) , box ) ;
}
Unexpected ( " Type in getImage(MTPWebDocument). " ) ;
}
WebFileImage * getImage (
const WebFileLocation & location ,
QSize box ,
int size ) {
auto key = storageKey ( location ) ;
auto i = webFileImages . constFind ( key ) ;
if ( i = = webFileImages . cend ( ) ) {
i = webFileImages . insert (
key ,
new WebFileImage ( location , box , size ) ) ;
}
return i . value ( ) ;
}
WebFileImage * getImage (
const WebFileLocation & location ,
int width ,
int height ,
int size ) {
2017-03-05 17:33:32 +00:00
auto key = storageKey ( location ) ;
auto i = webFileImages . constFind ( key ) ;
if ( i = = webFileImages . cend ( ) ) {
2018-03-04 20:04:13 +00:00
i = webFileImages . insert (
key ,
new WebFileImage ( location , width , height , size ) ) ;
2017-03-05 17:33:32 +00:00
}
return i . value ( ) ;
}
2016-04-10 11:13:37 +00:00
} // namespace internal
2015-12-30 19:09:20 +00:00
2017-12-18 09:07:18 +00:00
ReadAccessEnabler : : ReadAccessEnabler ( const PsFileBookmark * bookmark )
: _bookmark ( bookmark )
, _failed ( _bookmark ? ! _bookmark - > enable ( ) : false ) {
2015-11-26 17:34:52 +00:00
}
2017-12-18 09:07:18 +00:00
ReadAccessEnabler : : ReadAccessEnabler (
const std : : shared_ptr < PsFileBookmark > & bookmark )
: _bookmark ( bookmark . get ( ) )
, _failed ( _bookmark ? ! _bookmark - > enable ( ) : false ) {
2015-11-26 17:34:52 +00:00
}
ReadAccessEnabler : : ~ ReadAccessEnabler ( ) {
if ( _bookmark & & ! _failed ) _bookmark - > disable ( ) ;
}
2017-03-04 11:28:21 +00:00
FileLocation : : FileLocation ( const QString & name ) : fname ( name ) {
2015-11-26 17:34:52 +00:00
if ( fname . isEmpty ( ) ) {
size = 0 ;
} else {
setBookmark ( psPathBookmark ( name ) ) ;
QFileInfo f ( name ) ;
if ( f . exists ( ) ) {
qint64 s = f . size ( ) ;
if ( s > INT_MAX ) {
fname = QString ( ) ;
2017-12-18 09:07:18 +00:00
_bookmark = nullptr ;
2015-11-26 17:34:52 +00:00
size = 0 ;
} else {
modified = f . lastModified ( ) ;
size = qint32 ( s ) ;
}
} else {
fname = QString ( ) ;
2017-12-18 09:07:18 +00:00
_bookmark = nullptr ;
2015-11-26 17:34:52 +00:00
size = 0 ;
}
}
}
bool FileLocation : : check ( ) const {
if ( fname . isEmpty ( ) ) return false ;
ReadAccessEnabler enabler ( _bookmark ) ;
if ( enabler . failed ( ) ) {
2017-12-18 09:07:18 +00:00
const_cast < FileLocation * > ( this ) - > _bookmark = nullptr ;
2015-11-26 17:34:52 +00:00
}
QFileInfo f ( name ( ) ) ;
2015-11-27 17:58:56 +00:00
if ( ! f . isReadable ( ) ) return false ;
2015-11-26 17:34:52 +00:00
quint64 s = f . size ( ) ;
2017-02-09 13:51:49 +00:00
if ( s > INT_MAX ) {
DEBUG_LOG ( ( " File location check: Wrong size %1 " ) . arg ( s ) ) ;
return false ;
}
2015-11-26 17:34:52 +00:00
2017-02-09 13:51:49 +00:00
if ( qint32 ( s ) ! = size ) {
DEBUG_LOG ( ( " File location check: Wrong size %1 when should be %2 " ) . arg ( s ) . arg ( size ) ) ;
return false ;
}
auto realModified = f . lastModified ( ) ;
if ( realModified ! = modified ) {
DEBUG_LOG ( ( " File location check: Wrong last modified time %1 when should be %2 " ) . arg ( realModified . toMSecsSinceEpoch ( ) ) . arg ( modified . toMSecsSinceEpoch ( ) ) ) ;
return false ;
}
return true ;
2015-11-26 17:34:52 +00:00
}
const QString & FileLocation : : name ( ) const {
return _bookmark ? _bookmark - > name ( fname ) : fname ;
}
QByteArray FileLocation : : bookmark ( ) const {
return _bookmark ? _bookmark - > bookmark ( ) : QByteArray ( ) ;
}
void FileLocation : : setBookmark ( const QByteArray & bm ) {
2016-03-29 17:17:00 +00:00
_bookmark . reset ( bm . isEmpty ( ) ? nullptr : new PsFileBookmark ( bm ) ) ;
2015-11-26 17:34:52 +00:00
}
bool FileLocation : : accessEnable ( ) const {
return isEmpty ( ) ? false : ( _bookmark ? _bookmark - > enable ( ) : true ) ;
}
void FileLocation : : accessDisable ( ) const {
return _bookmark ? _bookmark - > disable ( ) : ( void ) 0 ;
}