1 : /******************************************************************************
2 : *
3 : * Purpose: Implementation of the CPCIDSKChannel Abstract class.
4 : *
5 : ******************************************************************************
6 : * Copyright (c) 2009
7 : * PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, Canada
8 : *
9 : * Permission is hereby granted, free of charge, to any person obtaining a
10 : * copy of this software and associated documentation files (the "Software"),
11 : * to deal in the Software without restriction, including without limitation
12 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 : * and/or sell copies of the Software, and to permit persons to whom the
14 : * Software is furnished to do so, subject to the following conditions:
15 : *
16 : * The above copyright notice and this permission notice shall be included
17 : * in all copies or substantial portions of the Software.
18 : *
19 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 : * DEALINGS IN THE SOFTWARE.
26 : ****************************************************************************/
27 :
28 : #include "pcidsk_config.h"
29 : #include "pcidsk_types.h"
30 : #include "pcidsk_exception.h"
31 : #include "pcidsk_channel.h"
32 : #include "core/cpcidskfile.h"
33 : #include "channel/cpcidskchannel.h"
34 : #include "channel/ctiledchannel.h"
35 : #include <cassert>
36 : #include <cstdlib>
37 : #include <cstring>
38 : #include <cstdio>
39 :
40 : using namespace PCIDSK;
41 :
42 : /************************************************************************/
43 : /* CPCIDSKChannel() */
44 : /************************************************************************/
45 :
46 127 : CPCIDSKChannel::CPCIDSKChannel( PCIDSKBuffer &image_header,
47 : CPCIDSKFile *file,
48 : eChanType pixel_type,
49 127 : int channel_number )
50 :
51 : {
52 127 : this->pixel_type = pixel_type;
53 127 : this->file = file;
54 127 : this->channel_number = channel_number;
55 :
56 127 : width = file->GetWidth();
57 127 : height = file->GetHeight();
58 :
59 127 : block_width = width;
60 127 : block_height = 1;
61 :
62 : /* -------------------------------------------------------------------- */
63 : /* Establish if we need to byte swap the data on load/store. */
64 : /* -------------------------------------------------------------------- */
65 127 : if( channel_number != -1 )
66 : {
67 124 : unsigned short test_value = 1;
68 :
69 124 : byte_order = image_header.buffer[201];
70 124 : if( ((uint8 *) &test_value)[0] == 1 )
71 124 : needs_swap = (byte_order != 'S');
72 : else
73 0 : needs_swap = (byte_order == 'S');
74 :
75 124 : if( pixel_type == CHN_8U )
76 100 : needs_swap = 0;
77 :
78 : /* -------------------------------------------------------------------- */
79 : /* Initialize the metadata object, but do not try to load till */
80 : /* needed. We avoid doing this for unassociated channels such */
81 : /* as overviews. */
82 : /* -------------------------------------------------------------------- */
83 124 : metadata.Initialize( file, "IMG", channel_number );
84 : }
85 :
86 : /* -------------------------------------------------------------------- */
87 : /* No overviews for unassociated files, so just mark them as */
88 : /* initialized. */
89 : /* -------------------------------------------------------------------- */
90 127 : overviews_initialized = channel_number == -1;
91 127 : }
92 :
93 : /************************************************************************/
94 : /* ~CPCIDSKChannel() */
95 : /************************************************************************/
96 :
97 127 : CPCIDSKChannel::~CPCIDSKChannel()
98 :
99 : {
100 127 : InvalidateOverviewInfo();
101 127 : }
102 :
103 : /************************************************************************/
104 : /* InvalidateOverviewInfo() */
105 : /* */
106 : /* This is called when CreateOverviews() creates overviews - we */
107 : /* invalidate our loaded info and re-establish on a next request. */
108 : /************************************************************************/
109 :
110 127 : void CPCIDSKChannel::InvalidateOverviewInfo()
111 :
112 : {
113 130 : for( size_t io=0; io < overview_bands.size(); io++ )
114 : {
115 3 : if( overview_bands[io] != NULL )
116 : {
117 3 : delete overview_bands[io];
118 3 : overview_bands[io] = NULL;
119 : }
120 : }
121 :
122 127 : overview_infos.clear();
123 127 : overview_bands.clear();
124 :
125 127 : overviews_initialized = false;
126 127 : }
127 :
128 : /************************************************************************/
129 : /* EstablishOverviewInfo() */
130 : /************************************************************************/
131 :
132 75 : void CPCIDSKChannel::EstablishOverviewInfo()
133 :
134 : {
135 75 : if( overviews_initialized )
136 6 : return;
137 :
138 69 : overviews_initialized = true;
139 :
140 69 : std::vector<std::string> keys = GetMetadataKeys();
141 : size_t i;
142 :
143 72 : for( i = 0; i < keys.size(); i++ )
144 : {
145 10 : if( strncmp(keys[i].c_str(),"_Overview_",10) != 0 )
146 7 : continue;
147 :
148 3 : std::string value = GetMetadataValue( keys[i] );
149 :
150 3 : overview_infos.push_back( value );
151 3 : overview_bands.push_back( NULL );
152 69 : }
153 : }
154 :
155 : /************************************************************************/
156 : /* GetBlockCount() */
157 : /************************************************************************/
158 :
159 0 : int CPCIDSKChannel::GetBlockCount()
160 :
161 : {
162 : // We deliberately call GetBlockWidth() and GetWidth() to trigger
163 : // computation of the values for tiled layers. At some point it would
164 : // be good to cache the block count as this computation is a bit expensive
165 :
166 0 : int x_block_count = (GetWidth() + GetBlockWidth() - 1) / GetBlockWidth();
167 0 : int y_block_count = (GetHeight() + GetBlockHeight() - 1) / GetBlockHeight();
168 :
169 0 : return x_block_count * y_block_count;
170 : }
171 :
172 : /************************************************************************/
173 : /* GetOverviewCount() */
174 : /************************************************************************/
175 :
176 72 : int CPCIDSKChannel::GetOverviewCount()
177 :
178 : {
179 72 : EstablishOverviewInfo();
180 :
181 72 : return overview_infos.size();
182 : }
183 :
184 : /************************************************************************/
185 : /* GetOverview() */
186 : /************************************************************************/
187 :
188 3 : PCIDSKChannel *CPCIDSKChannel::GetOverview( int overview_index )
189 :
190 : {
191 3 : EstablishOverviewInfo();
192 :
193 3 : if( overview_bands[overview_index] == NULL )
194 : {
195 3 : PCIDSKBuffer image_header(1024), file_header(1024);
196 : char pseudo_filename[65];
197 :
198 : sprintf( pseudo_filename, "/SIS=%d",
199 3 : atoi(overview_infos[overview_index].c_str()) );
200 :
201 3 : image_header.Put( pseudo_filename, 64, 64 );
202 :
203 : overview_bands[overview_index] =
204 : new CTiledChannel( image_header, file_header, -1, file,
205 3 : CHN_UNKNOWN );
206 : }
207 :
208 3 : return overview_bands[overview_index];
209 : }
210 :
|