1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
// WebP read support
// © 2024 Alexander Hajnal
// Based loosely on jp2.cpp
//
// If implementing write support it's suggested to use lossless mode with exact
// mode enabled when the quality setting is 100 and for other qualities to use
// lossy mode with the default settings.
//
// This library is distributed under the conditions of the GNU LGPL.
#include "config.h"
#include <tdetempfile.h>
#include <tqfile.h>
#include <tqimage.h>
#include <webp/decode.h>
#include <cstdlib>
#ifdef __cplusplus
extern "C" {
#endif
TDE_EXPORT void kimgio_webp_read( TQImageIO* io )
{
int width, height;
FILE* in;
// === Read the source file ===
// Based on code in jp2.cpp
// for QIODevice's other than TQFile, a temp. file is used.
KTempFile* tempf = 0;
TQFile* qf = 0;
if( ( qf = dynamic_cast<TQFile*>( io->ioDevice() ) ) ) {
// great, it's a TQFile. Let's just take the filename.
in = fopen( TQFile::encodeName( qf->name() ), "rb" );
} else {
// not a TQFile. Copy the whole data to a temp. file.
tempf = new KTempFile();
if( tempf->status() != 0 ) {
delete tempf;
return;
} // if
tempf->setAutoDelete( true );
TQFile* out = tempf->file();
// 4096 (=4k) is a common page size.
TQByteArray b( 4096 );
TQ_LONG size;
// 0 or -1 is EOF / error
while( ( size = io->ioDevice()->readBlock( b.data(), 4096 ) ) > 0 ) {
// in case of a write error, still give the decoder a try
if( ( out->writeBlock( b.data(), size ) ) == -1 ) break;
} // while
// flush everything out to disk
out->flush();
in = fopen( TQFile::encodeName( tempf->name() ), "rb" );
} // else
if( ! in ) {
delete tempf;
return;
} // if
// File is now open
// === Load compressed data ===
// Find file's size
fseek(in, 0L, SEEK_END); // Seek to end of file
long size = ftell(in); // Get position (i.e. the file size)
fseek(in, 0L, SEEK_SET); // Seek back to start of file
// Sanity check
if ( size > SIZE_MAX ) {
// File size is larger than a size_t can hold
fclose( in );
delete tempf;
return;
}
// Allocate a buffer for the compressed data
uint8_t* compressed_image = (uint8_t*)malloc(size);
if( ! compressed_image ) {
// malloc failed
fclose( in );
delete tempf;
return;
} // if
// Read compressed image into buffer
size_t bytes_read = fread( compressed_image, sizeof(uint8_t), size, in );
// Close the compressed image file
fclose( in );
delete tempf;
if ( bytes_read < size ) {
// Read failed
free( compressed_image );
return;
}
// === Decompress image ===
// Get image dimensions
if ( ! WebPGetInfo( compressed_image, size, &width, &height ) ) {
// Error
free( compressed_image );
return;
}
// Create an appropriately sized image
TQImage image;
if( ! image.create( width, height, 32 ) ) {
// Error
free( compressed_image );
return;
}
// Enable alpha channel
image.setAlphaBuffer(true);
// Get the image buffer
uint32_t* data = (uint32_t*)image.bits();
// Decompress the image
#ifdef WORDS_BIGENDIAN
if ( ! WebPDecodeARGBInto( compressed_image, size, (uint8_t*)data, width*height*4, width*4) ) {
#else
if ( ! WebPDecodeBGRAInto( compressed_image, size, (uint8_t*)data, width*height*4, width*4) ) {
#endif
// Error
free( compressed_image );
return;
}
// Free the compressed image buffer
free( compressed_image );
// Finalize load
io->setImage( image );
io->setStatus( 0 );
} // kimgio_webp_read
#ifdef __cplusplus
}
#endif
|