1 : /******************************************************************************
2 : *
3 : * Purpose: Implementation of the CExternalChannel class.
4 : *
5 : * This class is used to implement band interleaved channels that are
6 : * references to an external image database that is not just a raw file.
7 : * It uses the application supplied EDB interface to access non-PCIDSK files.
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2010
11 : * PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, Canada
12 : *
13 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : ****************************************************************************/
31 :
32 : #include "pcidsk_config.h"
33 : #include "pcidsk_types.h"
34 : #include "pcidsk_channel.h"
35 : #include "pcidsk_buffer.h"
36 : #include "pcidsk_exception.h"
37 : #include "pcidsk_file.h"
38 : #include "core/pcidsk_utils.h"
39 : #include "core/cpcidskfile.h"
40 : #include "channel/cexternalchannel.h"
41 : #include <cassert>
42 : #include <cstring>
43 : #include <cstdio>
44 : #include <cstdlib>
45 :
46 : using namespace PCIDSK;
47 :
48 : /************************************************************************/
49 : /* CExternalChannel() */
50 : /************************************************************************/
51 :
52 : CExternalChannel::CExternalChannel( PCIDSKBuffer &image_header,
53 : uint64 ih_offset,
54 : PCIDSKBuffer &file_header,
55 : int channelnum,
56 : CPCIDSKFile *file,
57 0 : eChanType pixel_type )
58 0 : : CPCIDSKChannel( image_header, ih_offset, file, pixel_type, channelnum)
59 :
60 : {
61 0 : db = NULL;
62 0 : mutex = NULL;
63 :
64 : /* -------------------------------------------------------------------- */
65 : /* Establish the data window. */
66 : /* -------------------------------------------------------------------- */
67 0 : exoff = atoi(image_header.Get( 250, 8 ));
68 0 : eyoff = atoi(image_header.Get( 258, 8 ));
69 0 : exsize = atoi(image_header.Get( 266, 8 ));
70 0 : eysize = atoi(image_header.Get( 274, 8 ));
71 :
72 0 : echannel = atoi(image_header.Get( 282, 8 ));
73 :
74 : /* -------------------------------------------------------------------- */
75 : /* Establish the file we will be accessing. */
76 : /* -------------------------------------------------------------------- */
77 0 : image_header.Get(64,64,filename);
78 0 : }
79 :
80 : /************************************************************************/
81 : /* ~CExternalChannel() */
82 : /************************************************************************/
83 :
84 0 : CExternalChannel::~CExternalChannel()
85 :
86 : {
87 : // no need to deaccess the EDBFile - the file is responsible for that.
88 0 : }
89 :
90 : /************************************************************************/
91 : /* AccessDB() */
92 : /************************************************************************/
93 :
94 0 : void CExternalChannel::AccessDB() const
95 :
96 : {
97 0 : if( db != NULL )
98 0 : return;
99 :
100 : /* -------------------------------------------------------------------- */
101 : /* open, or fetch an already open file handle. */
102 : /* -------------------------------------------------------------------- */
103 0 : writable = file->GetEDBFileDetails( &db, &mutex, filename );
104 :
105 : /* -------------------------------------------------------------------- */
106 : /* Capture the block size. */
107 : /* -------------------------------------------------------------------- */
108 0 : block_width = db->GetBlockWidth( echannel );
109 0 : if( block_width > width )
110 0 : block_width = width;
111 0 : block_height = db->GetBlockHeight( echannel );
112 0 : if( block_height > height )
113 0 : block_height = height;
114 :
115 0 : blocks_per_row = (GetWidth() + block_width - 1) / block_width;
116 : }
117 :
118 : /************************************************************************/
119 : /* GetBlockWidth() */
120 : /************************************************************************/
121 :
122 0 : int CExternalChannel::GetBlockWidth() const
123 :
124 : {
125 0 : AccessDB();
126 :
127 0 : return block_width;
128 : }
129 :
130 : /************************************************************************/
131 : /* GetBlockHeight() */
132 : /************************************************************************/
133 :
134 0 : int CExternalChannel::GetBlockHeight() const
135 :
136 : {
137 0 : AccessDB();
138 :
139 0 : return block_height;
140 : }
141 :
142 : /************************************************************************/
143 : /* ReadBlock() */
144 : /************************************************************************/
145 :
146 : int CExternalChannel::ReadBlock( int block_index, void *buffer,
147 : int xoff, int yoff,
148 0 : int xsize, int ysize )
149 :
150 : {
151 0 : AccessDB();
152 :
153 : /* -------------------------------------------------------------------- */
154 : /* Default window if needed. */
155 : /* -------------------------------------------------------------------- */
156 0 : if( xoff == -1 && yoff == -1 && xsize == -1 && ysize == -1 )
157 : {
158 0 : xoff = 0;
159 0 : yoff = 0;
160 0 : xsize = GetBlockWidth();
161 0 : ysize = GetBlockHeight();
162 : }
163 :
164 : /* -------------------------------------------------------------------- */
165 : /* Validate Window */
166 : /* -------------------------------------------------------------------- */
167 0 : if( xoff < 0 || xoff + xsize > GetBlockWidth()
168 : || yoff < 0 || yoff + ysize > GetBlockHeight() )
169 : {
170 : ThrowPCIDSKException(
171 : "Invalid window in ReadBlock(): xoff=%d,yoff=%d,xsize=%d,ysize=%d",
172 0 : xoff, yoff, xsize, ysize );
173 : }
174 :
175 : /* -------------------------------------------------------------------- */
176 : /* Do a direct call for the simpliest case of 1:1 block mapping. */
177 : /* -------------------------------------------------------------------- */
178 0 : if( exoff == 0 && eyoff == 0
179 : && exsize == db->GetWidth()
180 : && eysize == db->GetHeight() )
181 : {
182 0 : MutexHolder oHolder( mutex );
183 : return db->ReadBlock( echannel, block_index, buffer,
184 0 : xoff, yoff, xsize, ysize );
185 : }
186 :
187 : /* ==================================================================== */
188 : /* Otherwise we need to break this down into potentially up to */
189 : /* four requests against the source file. */
190 : /* ==================================================================== */
191 0 : int src_block_width = db->GetBlockWidth( echannel );
192 0 : int src_block_height = db->GetBlockHeight( echannel );
193 : int src_blocks_per_row = (db->GetWidth() + src_block_width - 1)
194 0 : / src_block_width;
195 0 : int pixel_size = DataTypeSize(GetType());
196 : uint8 *temp_buffer = (uint8 *) calloc(src_block_width*src_block_height,
197 0 : pixel_size);
198 : int txoff, tyoff, txsize, tysize;
199 : int dst_blockx, dst_blocky;
200 :
201 0 : if( temp_buffer == NULL )
202 0 : ThrowPCIDSKException( "Failed to allocate temporary block buffer." );
203 :
204 0 : dst_blockx = block_index % blocks_per_row;
205 0 : dst_blocky = block_index / blocks_per_row;
206 :
207 : // what is the region of our desired data on the destination file?
208 :
209 0 : txoff = dst_blockx * block_width + exoff + xoff;
210 0 : tyoff = dst_blocky * block_height + eyoff + yoff;
211 0 : txsize = xsize;
212 0 : tysize = ysize;
213 :
214 : /* -------------------------------------------------------------------- */
215 : /* read external block for top left corner of target block. */
216 : /* -------------------------------------------------------------------- */
217 : int ablock_x, ablock_y, i_line;
218 : int axoff, ayoff, axsize, aysize;
219 0 : int block1_xsize=0, block1_ysize=0;
220 : int ttxoff, ttyoff, ttxsize, ttysize;
221 :
222 0 : ttxoff = txoff;
223 0 : ttyoff = tyoff;
224 0 : ttxsize = txsize;
225 0 : ttysize = tysize;
226 :
227 0 : ablock_x = ttxoff / src_block_width;
228 0 : ablock_y = ttyoff / src_block_height;
229 :
230 0 : axoff = ttxoff - ablock_x * src_block_width;
231 0 : ayoff = ttyoff - ablock_y * src_block_height;
232 :
233 0 : if( axoff + ttxsize > src_block_width )
234 0 : axsize = src_block_width - axoff;
235 : else
236 0 : axsize = ttxsize;
237 :
238 0 : if( ayoff + ttysize > src_block_height )
239 0 : aysize = src_block_height - ayoff;
240 : else
241 0 : aysize = ttysize;
242 :
243 0 : if( axsize > 0 )
244 0 : block1_xsize = axsize;
245 : else
246 0 : block1_xsize = 0;
247 :
248 0 : if( aysize > 0 )
249 0 : block1_ysize = aysize;
250 : else
251 0 : block1_ysize = 0;
252 :
253 0 : if( axsize > 0 && aysize > 0 )
254 : {
255 0 : MutexHolder oHolder( mutex );
256 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
257 0 : temp_buffer, axoff, ayoff, axsize, aysize );
258 :
259 0 : for( i_line = 0; i_line < aysize; i_line++ )
260 : {
261 : memcpy( ((uint8*) buffer) + i_line * xsize * pixel_size,
262 : temp_buffer + i_line * axsize * pixel_size,
263 0 : axsize * pixel_size );
264 0 : }
265 : }
266 :
267 : /* -------------------------------------------------------------------- */
268 : /* read external block for top right corner of target block. */
269 : /* -------------------------------------------------------------------- */
270 0 : ttxoff = txoff + block1_xsize;
271 0 : ttyoff = tyoff;
272 0 : ttxsize = txsize - block1_xsize;
273 0 : ttysize = tysize;
274 :
275 0 : ablock_x = ttxoff / src_block_width;
276 0 : ablock_y = ttyoff / src_block_height;
277 :
278 0 : axoff = ttxoff - ablock_x * src_block_width;
279 0 : ayoff = ttyoff - ablock_y * src_block_height;
280 :
281 0 : if( axoff + ttxsize > src_block_width )
282 0 : axsize = src_block_width - axoff;
283 : else
284 0 : axsize = ttxsize;
285 :
286 0 : if( ayoff + ttysize > src_block_height )
287 0 : aysize = src_block_height - ayoff;
288 : else
289 0 : aysize = ttysize;
290 :
291 0 : if( axsize > 0 && aysize > 0 )
292 : {
293 0 : MutexHolder oHolder( mutex );
294 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
295 0 : temp_buffer, axoff, ayoff, axsize, aysize );
296 :
297 0 : for( i_line = 0; i_line < aysize; i_line++ )
298 : {
299 : memcpy( ((uint8*) buffer)
300 : + (block1_xsize + i_line * xsize) * pixel_size,
301 : temp_buffer + i_line * axsize * pixel_size,
302 0 : axsize * pixel_size );
303 0 : }
304 : }
305 :
306 : /* -------------------------------------------------------------------- */
307 : /* read external block for bottom left corner of target block. */
308 : /* -------------------------------------------------------------------- */
309 0 : ttxoff = txoff;
310 0 : ttyoff = tyoff + block1_ysize;
311 0 : ttxsize = txsize;
312 0 : ttysize = tysize - block1_ysize;
313 :
314 0 : ablock_x = ttxoff / src_block_width;
315 0 : ablock_y = ttyoff / src_block_height;
316 :
317 0 : axoff = ttxoff - ablock_x * src_block_width;
318 0 : ayoff = ttyoff - ablock_y * src_block_height;
319 :
320 0 : if( axoff + ttxsize > src_block_width )
321 0 : axsize = src_block_width - axoff;
322 : else
323 0 : axsize = ttxsize;
324 :
325 0 : if( ayoff + ttysize > src_block_height )
326 0 : aysize = src_block_height - ayoff;
327 : else
328 0 : aysize = ttysize;
329 :
330 0 : if( axsize > 0 && aysize > 0 )
331 : {
332 0 : MutexHolder oHolder( mutex );
333 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
334 0 : temp_buffer, axoff, ayoff, axsize, aysize );
335 :
336 0 : for( i_line = 0; i_line < aysize; i_line++ )
337 : {
338 : memcpy( ((uint8*) buffer)
339 : + (i_line + block1_ysize) * xsize * pixel_size,
340 : temp_buffer + i_line * axsize * pixel_size,
341 0 : axsize * pixel_size );
342 0 : }
343 : }
344 :
345 : /* -------------------------------------------------------------------- */
346 : /* read external block for bottom left corner of target block. */
347 : /* -------------------------------------------------------------------- */
348 0 : ttxoff = txoff + block1_xsize;
349 0 : ttyoff = tyoff + block1_ysize;
350 0 : ttxsize = txsize - block1_xsize;
351 0 : ttysize = tysize - block1_ysize;
352 :
353 0 : ablock_x = ttxoff / src_block_width;
354 0 : ablock_y = ttyoff / src_block_height;
355 :
356 0 : axoff = ttxoff - ablock_x * src_block_width;
357 0 : ayoff = ttyoff - ablock_y * src_block_height;
358 :
359 0 : if( axoff + ttxsize > src_block_width )
360 0 : axsize = src_block_width - axoff;
361 : else
362 0 : axsize = ttxsize;
363 :
364 0 : if( ayoff + ttysize > src_block_height )
365 0 : aysize = src_block_height - ayoff;
366 : else
367 0 : aysize = ttysize;
368 :
369 0 : if( axsize > 0 && aysize > 0 )
370 : {
371 0 : MutexHolder oHolder( mutex );
372 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
373 0 : temp_buffer, axoff, ayoff, axsize, aysize );
374 :
375 0 : for( i_line = 0; i_line < aysize; i_line++ )
376 : {
377 : memcpy( ((uint8*) buffer)
378 : + (block1_xsize + (i_line + block1_ysize) * xsize) * pixel_size,
379 : temp_buffer + i_line * axsize * pixel_size,
380 0 : axsize * pixel_size );
381 0 : }
382 : }
383 :
384 0 : free( temp_buffer );
385 :
386 0 : return 1;
387 : }
388 :
389 : /************************************************************************/
390 : /* WriteBlock() */
391 : /************************************************************************/
392 :
393 0 : int CExternalChannel::WriteBlock( int block_index, void *buffer )
394 :
395 : {
396 0 : AccessDB();
397 :
398 0 : if( !file->GetUpdatable() || !writable )
399 0 : throw PCIDSKException( "File not open for update in WriteBlock()" );
400 :
401 : /* -------------------------------------------------------------------- */
402 : /* Pass the request on directly in the simple case. */
403 : /* -------------------------------------------------------------------- */
404 0 : if( exoff == 0 && eyoff == 0
405 : && exsize == db->GetWidth()
406 : && eysize == db->GetHeight() )
407 : {
408 0 : MutexHolder oHolder( mutex );
409 0 : return db->WriteBlock( echannel, block_index, buffer );
410 : }
411 :
412 : /* ==================================================================== */
413 : /* Otherwise we need to break this down into potentially up to */
414 : /* four requests against the source file. */
415 : /* ==================================================================== */
416 0 : int src_block_width = db->GetBlockWidth( echannel );
417 0 : int src_block_height = db->GetBlockHeight( echannel );
418 : int src_blocks_per_row = (db->GetWidth() + src_block_width - 1)
419 0 : / src_block_width;
420 0 : int pixel_size = DataTypeSize(GetType());
421 : uint8 *temp_buffer = (uint8 *) calloc(src_block_width*src_block_height,
422 0 : pixel_size);
423 : int txoff, tyoff, txsize, tysize;
424 : int dst_blockx, dst_blocky;
425 :
426 0 : if( temp_buffer == NULL )
427 0 : ThrowPCIDSKException( "Failed to allocate temporary block buffer." );
428 :
429 0 : dst_blockx = block_index % blocks_per_row;
430 0 : dst_blocky = block_index / blocks_per_row;
431 :
432 : // what is the region of our desired data on the destination file?
433 :
434 0 : txoff = dst_blockx * block_width + exoff;
435 0 : tyoff = dst_blocky * block_height + eyoff;
436 0 : txsize = block_width;
437 0 : tysize = block_height;
438 :
439 : /* -------------------------------------------------------------------- */
440 : /* process external block for top left corner of target block. */
441 : /* -------------------------------------------------------------------- */
442 : int ablock_x, ablock_y, i_line;
443 : int axoff, ayoff, axsize, aysize;
444 0 : int block1_xsize=0, block1_ysize=0;
445 : int ttxoff, ttyoff, ttxsize, ttysize;
446 :
447 0 : ttxoff = txoff;
448 0 : ttyoff = tyoff;
449 0 : ttxsize = txsize;
450 0 : ttysize = tysize;
451 :
452 0 : ablock_x = ttxoff / src_block_width;
453 0 : ablock_y = ttyoff / src_block_height;
454 :
455 0 : axoff = ttxoff - ablock_x * src_block_width;
456 0 : ayoff = ttyoff - ablock_y * src_block_height;
457 :
458 0 : if( axoff + ttxsize > src_block_width )
459 0 : axsize = src_block_width - axoff;
460 : else
461 0 : axsize = ttxsize;
462 :
463 0 : if( ayoff + ttysize > src_block_height )
464 0 : aysize = src_block_height - ayoff;
465 : else
466 0 : aysize = ttysize;
467 :
468 0 : if( axsize > 0 )
469 0 : block1_xsize = axsize;
470 : else
471 0 : block1_xsize = 0;
472 :
473 0 : if( aysize > 0 )
474 0 : block1_ysize = aysize;
475 : else
476 0 : block1_ysize = 0;
477 :
478 0 : if( axsize > 0 && aysize > 0 )
479 : {
480 0 : MutexHolder oHolder( mutex );
481 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
482 0 : temp_buffer );
483 :
484 0 : for( i_line = 0; i_line < aysize; i_line++ )
485 : {
486 : memcpy( temp_buffer
487 : + (i_line+ayoff) * src_block_width * pixel_size
488 : + axoff * pixel_size,
489 : ((uint8*) buffer) + i_line * block_width * pixel_size,
490 0 : axsize * pixel_size );
491 : }
492 :
493 : db->WriteBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
494 0 : temp_buffer );
495 : }
496 :
497 : /* -------------------------------------------------------------------- */
498 : /* read external block for top right corner of target block. */
499 : /* -------------------------------------------------------------------- */
500 0 : ttxoff = txoff + block1_xsize;
501 0 : ttyoff = tyoff;
502 0 : ttxsize = txsize - block1_xsize;
503 0 : ttysize = tysize;
504 :
505 0 : ablock_x = ttxoff / src_block_width;
506 0 : ablock_y = ttyoff / src_block_height;
507 :
508 0 : axoff = ttxoff - ablock_x * src_block_width;
509 0 : ayoff = ttyoff - ablock_y * src_block_height;
510 :
511 0 : if( axoff + ttxsize > src_block_width )
512 0 : axsize = src_block_width - axoff;
513 : else
514 0 : axsize = ttxsize;
515 :
516 0 : if( ayoff + ttysize > src_block_height )
517 0 : aysize = src_block_height - ayoff;
518 : else
519 0 : aysize = ttysize;
520 :
521 0 : if( axsize > 0 && aysize > 0 )
522 : {
523 0 : MutexHolder oHolder( mutex );
524 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
525 0 : temp_buffer );
526 :
527 0 : for( i_line = 0; i_line < aysize; i_line++ )
528 : {
529 : memcpy( temp_buffer
530 : + (i_line+ayoff) * src_block_width * pixel_size
531 : + axoff * pixel_size,
532 : ((uint8*) buffer) + i_line * block_width * pixel_size
533 : + block1_xsize * pixel_size,
534 0 : axsize * pixel_size );
535 : }
536 :
537 : db->WriteBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
538 0 : temp_buffer );
539 : }
540 :
541 : /* -------------------------------------------------------------------- */
542 : /* read external block for bottom left corner of target block. */
543 : /* -------------------------------------------------------------------- */
544 0 : ttxoff = txoff;
545 0 : ttyoff = tyoff + block1_ysize;
546 0 : ttxsize = txsize;
547 0 : ttysize = tysize - block1_ysize;
548 :
549 0 : ablock_x = ttxoff / src_block_width;
550 0 : ablock_y = ttyoff / src_block_height;
551 :
552 0 : axoff = ttxoff - ablock_x * src_block_width;
553 0 : ayoff = ttyoff - ablock_y * src_block_height;
554 :
555 0 : if( axoff + ttxsize > src_block_width )
556 0 : axsize = src_block_width - axoff;
557 : else
558 0 : axsize = ttxsize;
559 :
560 0 : if( ayoff + ttysize > src_block_height )
561 0 : aysize = src_block_height - ayoff;
562 : else
563 0 : aysize = ttysize;
564 :
565 0 : if( axsize > 0 && aysize > 0 )
566 : {
567 0 : MutexHolder oHolder( mutex );
568 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
569 0 : temp_buffer );
570 :
571 0 : for( i_line = 0; i_line < aysize; i_line++ )
572 : {
573 : memcpy( temp_buffer
574 : + (i_line+ayoff) * src_block_width * pixel_size
575 : + axoff * pixel_size,
576 : ((uint8*) buffer)
577 : + (i_line+block1_ysize) * block_width * pixel_size,
578 0 : axsize * pixel_size );
579 : }
580 :
581 : db->WriteBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
582 0 : temp_buffer );
583 : }
584 :
585 : /* -------------------------------------------------------------------- */
586 : /* read external block for bottom left corner of target block. */
587 : /* -------------------------------------------------------------------- */
588 0 : ttxoff = txoff + block1_xsize;
589 0 : ttyoff = tyoff + block1_ysize;
590 0 : ttxsize = txsize - block1_xsize;
591 0 : ttysize = tysize - block1_ysize;
592 :
593 0 : ablock_x = ttxoff / src_block_width;
594 0 : ablock_y = ttyoff / src_block_height;
595 :
596 0 : axoff = ttxoff - ablock_x * src_block_width;
597 0 : ayoff = ttyoff - ablock_y * src_block_height;
598 :
599 0 : if( axoff + ttxsize > src_block_width )
600 0 : axsize = src_block_width - axoff;
601 : else
602 0 : axsize = ttxsize;
603 :
604 0 : if( ayoff + ttysize > src_block_height )
605 0 : aysize = src_block_height - ayoff;
606 : else
607 0 : aysize = ttysize;
608 :
609 0 : if( axsize > 0 && aysize > 0 )
610 : {
611 0 : MutexHolder oHolder( mutex );
612 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
613 0 : temp_buffer );
614 :
615 0 : for( i_line = 0; i_line < aysize; i_line++ )
616 : {
617 : memcpy( temp_buffer
618 : + (i_line+ayoff) * src_block_width * pixel_size
619 : + axoff * pixel_size,
620 : ((uint8*) buffer)
621 : + (i_line+block1_ysize) * block_width * pixel_size
622 : + block1_xsize * pixel_size,
623 0 : axsize * pixel_size );
624 : }
625 :
626 : db->WriteBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
627 0 : temp_buffer );
628 : }
629 :
630 0 : free( temp_buffer );
631 :
632 0 : return 1;
633 : }
634 :
|