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
2018-10-11 15:54:57 +00:00
# include "ui/image.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 ;
2018-10-11 15:54:57 +00:00
for ( auto i = index_type ( ) ; i < size ; i + = 4 ) {
2016-11-28 15:45:07 +00:00
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
2018-10-23 09:08:50 +00:00
ImagePtr : : ImagePtr ( ) : _data ( Image : : Blank ( ) . get ( ) ) {
2015-12-24 19:26:28 +00:00
}
2018-10-23 09:08:50 +00:00
ImagePtr : : ImagePtr ( not_null < Image * > data ) : _data ( data ) {
2018-03-04 20:04:13 +00:00
}
2018-10-11 15:54:57 +00:00
Image * ImagePtr : : operator - > ( ) const {
return _data ;
2018-03-04 20:04:13 +00:00
}
2018-10-11 15:54:57 +00:00
Image * ImagePtr : : get ( ) const {
return _data ;
2018-03-04 20:04:13 +00:00
}
2018-10-11 15:54:57 +00:00
ImagePtr : : operator bool ( ) const {
return ! _data - > isNull ( ) ;
2018-03-04 20:04:13 +00:00
}
2018-10-11 15:54:57 +00:00
StorageImageLocation StorageImageLocation : : Null ;
WebFileLocation WebFileLocation : : Null ;
2018-03-04 20:04:13 +00:00
2018-10-11 15:54:57 +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 ) {
2017-03-05 17:33:32 +00:00
}
2018-10-11 15:54:57 +00:00
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 ) {
2018-10-08 18:14:05 +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 ;
}