Line data Source code
1 : /*
2 : Copyright 2021 Esri
3 : Licensed under the Apache License, Version 2.0 (the "License");
4 : you may not use this file except in compliance with the License.
5 : You may obtain a copy of the License at
6 : http://www.apache.org/licenses/LICENSE-2.0
7 : Unless required by applicable law or agreed to in writing, software
8 : distributed under the License is distributed on an "AS IS" BASIS,
9 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 : See the License for the specific language governing permissions and
11 : limitations under the License.
12 :
13 : QB3 band implementation
14 : QB3 page compression and decompression functions
15 :
16 : Authors: Lucian Plesea
17 : */
18 : #include "marfa.h"
19 : #include <QB3.h>
20 :
21 : NAMESPACE_MRF_START
22 12 : CPLErr QB3_Band::Compress(buf_mgr &dst, buf_mgr &src)
23 : {
24 12 : auto bands = static_cast<size_t>(img.pagesize.c);
25 12 : encsp pQB3 = nullptr;
26 : #define CREATE_QB3(T) \
27 : qb3_create_encoder(img.pagesize.x, img.pagesize.y, bands, qb3_dtype::T)
28 :
29 12 : switch (img.dt)
30 : {
31 8 : case (GDT_Byte):
32 8 : pQB3 = CREATE_QB3(QB3_U8);
33 8 : break;
34 1 : case (GDT_Int16):
35 1 : pQB3 = CREATE_QB3(QB3_I16);
36 1 : break;
37 1 : case (GDT_UInt16):
38 1 : pQB3 = CREATE_QB3(QB3_U16);
39 1 : break;
40 1 : case (GDT_Int32):
41 1 : pQB3 = CREATE_QB3(QB3_I32);
42 1 : break;
43 1 : case (GDT_UInt32):
44 1 : pQB3 = CREATE_QB3(QB3_U32);
45 1 : break;
46 0 : default:
47 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
48 : "MRF:QB3 Data type not supported");
49 0 : return CE_Failure;
50 : }
51 : #undef CREATE_QB3
52 :
53 12 : if (nullptr == pQB3)
54 : {
55 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
56 : "MRF:QB3 Cannot create encoder");
57 0 : return CE_Failure;
58 : }
59 :
60 12 : CPLErr status = CE_None;
61 : try
62 : {
63 12 : if (dst.size < qb3_max_encoded_size(pQB3))
64 : {
65 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
66 : "MRF:QB3 encoded buffer size too small");
67 0 : throw CE_Failure;
68 : }
69 :
70 : // Use independent band compression when by default band 1 is core band
71 13 : if ((3 == bands || 4 == bands) &&
72 1 : EQUAL(poMRFDS->GetPhotometricInterpretation(), "MULTISPECTRAL"))
73 : {
74 0 : size_t corebands[] = {0, 1, 2, 3}; // Identity, no core bands
75 0 : qb3_set_encoder_coreband(pQB3, bands, corebands);
76 : }
77 :
78 : // Quality of 90 and above trigger the better encoding
79 12 : qb3_set_encoder_mode(pQB3, (img.quality > 90) ? QB3M_BEST : QB3M_BASE);
80 :
81 12 : dst.size = qb3_encode(pQB3, src.buffer, dst.buffer);
82 12 : if (0 == dst.size)
83 : {
84 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
85 : "MRF:QB3 encoding failed");
86 0 : throw CE_Failure;
87 : }
88 :
89 : // Never happens if qb3_max_encoded doesn't lie
90 12 : if (dst.size > qb3_max_encoded_size(pQB3))
91 : {
92 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
93 : "MRF:QB3 encoded size exceeds limit, check QB3 library");
94 0 : throw CE_Failure;
95 : }
96 : }
97 0 : catch (CPLErr error)
98 : {
99 0 : status = error;
100 : }
101 12 : qb3_destroy_encoder(pQB3);
102 12 : return status;
103 : }
104 :
105 8 : CPLErr QB3_Band::Decompress(buf_mgr &dst, buf_mgr &src)
106 : {
107 : size_t img_size[3];
108 8 : auto pdQB3 = qb3_read_start(src.buffer, src.size, img_size);
109 8 : if (nullptr == pdQB3)
110 : {
111 0 : CPLError(CE_Failure, CPLE_AppDefined,
112 : "MRF: QB3 can't create decoder, is it a valid QB3 stream?");
113 0 : return CE_Failure;
114 : }
115 :
116 8 : CPLErr status = CE_None;
117 : try
118 : {
119 8 : if (img_size[0] != static_cast<size_t>(img.pagesize.x) ||
120 8 : img_size[1] != static_cast<size_t>(img.pagesize.y) ||
121 8 : img_size[2] != static_cast<size_t>(img.pagesize.c))
122 : {
123 0 : CPLError(CE_Failure, CPLE_AppDefined,
124 : "MRF: QB Page has invalid size");
125 0 : throw CE_Failure;
126 : }
127 :
128 8 : if (!qb3_read_info(pdQB3))
129 : {
130 0 : CPLError(CE_Failure, CPLE_AppDefined,
131 : "MRF: QB3 metadata read failure");
132 0 : throw CE_Failure;
133 : }
134 :
135 8 : if (static_cast<size_t>(img.pageSizeBytes) != qb3_decoded_size(pdQB3))
136 : {
137 0 : CPLError(CE_Failure, CPLE_AppDefined,
138 : "MRF: QB3 incorrect decoded tile size");
139 0 : throw CE_Failure;
140 : }
141 :
142 8 : dst.size = qb3_read_data(pdQB3, dst.buffer);
143 8 : if (static_cast<size_t>(img.pageSizeBytes) != dst.size)
144 : {
145 0 : CPLError(CE_Failure, CPLE_AppDefined, "MRF: QB3 decoding error");
146 0 : throw CE_Failure;
147 : }
148 : }
149 0 : catch (CPLErr error)
150 : {
151 0 : status = error;
152 : }
153 8 : qb3_destroy_decoder(pdQB3);
154 8 : return status;
155 : }
156 :
157 42 : QB3_Band::QB3_Band(MRFDataset *pDS, const ILImage &image, int b, int level)
158 42 : : MRFRasterBand(pDS, image, b, level)
159 : {
160 : static_assert(CPL_IS_LSB,
161 : "QB3 is only implemented for little endian architectures");
162 42 : if (image.pageSizeBytes > INT_MAX / 4)
163 : {
164 0 : CPLError(CE_Failure, CPLE_AppDefined, "QB3 page too large");
165 0 : return;
166 : }
167 :
168 42 : if (0 != nBlockXSize % 4 || 0 != nBlockYSize % 4)
169 : {
170 0 : CPLError(CE_Failure, CPLE_NotSupported,
171 : "QB3 page size has to be a multiple of 4");
172 0 : return;
173 : }
174 :
175 42 : if (image.dt != GDT_Byte && image.dt != GDT_Int16 &&
176 9 : image.dt != GDT_UInt16 && image.dt != GDT_Int32 &&
177 3 : image.dt != GDT_UInt32)
178 : {
179 0 : CPLError(CE_Failure, CPLE_NotSupported,
180 : "Data type not supported by QB3 compression");
181 0 : return;
182 : }
183 :
184 : // Should use qb3_max_encoded_size();
185 :
186 : // Enlarge the page buffer, QB3 may expand data.
187 42 : pDS->SetPBufferSize(2 * image.pageSizeBytes);
188 : }
189 :
190 : NAMESPACE_MRF_END
|