@@ -323,6 +323,11 @@ func new() *cog {
323323}
324324
325325func (cog * cog ) writeHeader (w io.Writer ) error {
326+ glen := uint64 (len (ghost ))
327+ if len (cog .ifd .masks ) > 0 {
328+ glen = uint64 (len (ghostmask ))
329+ }
330+ var err error
326331 if cog .bigtiff {
327332 buf := [16 ]byte {}
328333 if cog .enc == binary .LittleEndian {
@@ -333,9 +338,8 @@ func (cog *cog) writeHeader(w io.Writer) error {
333338 cog .enc .PutUint16 (buf [2 :], 43 )
334339 cog .enc .PutUint16 (buf [4 :], 8 )
335340 cog .enc .PutUint16 (buf [6 :], 0 )
336- cog .enc .PutUint64 (buf [8 :], 16 )
337- _ , err := w .Write (buf [:])
338- return err
341+ cog .enc .PutUint64 (buf [8 :], 16 + glen )
342+ _ , err = w .Write (buf [:])
339343 } else {
340344 buf := [8 ]byte {}
341345 if cog .enc == binary .LittleEndian {
@@ -344,10 +348,18 @@ func (cog *cog) writeHeader(w io.Writer) error {
344348 copy (buf [0 :], []byte ("MM" ))
345349 }
346350 cog .enc .PutUint16 (buf [2 :], 42 )
347- cog .enc .PutUint32 (buf [4 :], 8 )
348- _ , err := w .Write (buf [:])
351+ cog .enc .PutUint32 (buf [4 :], 8 + uint32 (glen ))
352+ _ , err = w .Write (buf [:])
353+ }
354+ if err != nil {
349355 return err
350356 }
357+ if len (cog .ifd .masks ) > 0 {
358+ _ , err = w .Write ([]byte (ghostmask ))
359+ } else {
360+ _ , err = w .Write ([]byte (ghost ))
361+ }
362+ return err
351363}
352364
353365const (
@@ -388,6 +400,23 @@ func (cog *cog) computeStructure() {
388400 }
389401}
390402
403+ const ghost = `GDAL_STRUCTURAL_METADATA_SIZE=000140 bytes
404+ LAYOUT=IFDS_BEFORE_DATA
405+ BLOCK_ORDER=ROW_MAJOR
406+ BLOCK_LEADER=SIZE_AS_UINT4
407+ BLOCK_TRAILER=LAST_4_BYTES_REPEATED
408+ KNOWN_INCOMPATIBLE_EDITION=NO
409+ ` //2 spaces: 1 for the gdal spec, and one to ensure the actual start offset is on a word boundary
410+
411+ const ghostmask = `GDAL_STRUCTURAL_METADATA_SIZE=000174 bytes
412+ LAYOUT=IFDS_BEFORE_DATA
413+ BLOCK_ORDER=ROW_MAJOR
414+ BLOCK_LEADER=SIZE_AS_UINT4
415+ BLOCK_TRAILER=LAST_4_BYTES_REPEATED
416+ KNOWN_INCOMPATIBLE_EDITION=NO
417+ MASK_INTERLEAVED_WITH_IMAGERY=YES
418+ `
419+
391420func (cog * cog ) computeImageryOffsets () error {
392421 ifd := cog .ifd
393422 for ifd != nil {
@@ -418,6 +447,11 @@ func (cog *cog) computeImageryOffsets() error {
418447 if ! cog .bigtiff {
419448 dataOffset = 8
420449 }
450+ if len (cog .ifd .masks ) > 0 {
451+ dataOffset += uint64 (len (ghostmask )) + 4
452+ } else {
453+ dataOffset += uint64 (len (ghost )) + 4
454+ }
421455
422456 ifd = cog .ifd
423457 for ifd != nil {
@@ -444,7 +478,7 @@ func (cog *cog) computeImageryOffsets() error {
444478 }
445479 tile .ifd .NewTileOffsets32 [tileidx ] = uint32 (dataOffset )
446480 }
447- dataOffset += uint64 (tile .ifd .TileByteCounts [tileidx ])
481+ dataOffset += uint64 (tile .ifd .TileByteCounts [tileidx ]) + 8
448482 } else {
449483 if cog .bigtiff {
450484 tile .ifd .NewTileOffsets64 [tileidx ] = 0
@@ -470,6 +504,11 @@ func (cog *cog) write(out io.Writer) error {
470504 if ! cog .bigtiff {
471505 strileData .Offset = 8
472506 }
507+ if len (cog .ifd .masks ) > 0 {
508+ strileData .Offset += uint64 (len (ghostmask ))
509+ } else {
510+ strileData .Offset += uint64 (len (ghost ))
511+ }
473512
474513 ifd := cog .ifd
475514 for ifd != nil {
@@ -480,12 +519,16 @@ func (cog *cog) write(out io.Writer) error {
480519 ifd = ifd .overview
481520 }
482521
522+ glen := uint64 (len (ghost ))
523+ if len (cog .ifd .masks ) > 0 {
524+ glen = uint64 (len (ghostmask ))
525+ }
483526 cog .writeHeader (out )
484527
485528 ifd = cog .ifd
486- off := uint64 (16 )
529+ off := uint64 (16 + glen )
487530 if ! cog .bigtiff {
488- off = 8
531+ off = 8 + glen
489532 }
490533 for ifd != nil {
491534 nmasks := len (ifd .masks )
@@ -511,19 +554,28 @@ func (cog *cog) write(out io.Writer) error {
511554
512555 datas := cog .dataInterlacing ()
513556 tiles := datas .tiles ()
514- buf := & bytes. Buffer {}
557+ data := [] byte {}
515558 for tile := range tiles {
516- buf .Reset ()
517559 idx := (tile .x + tile .y * tile .ifd .ntilesx )* tile .ifd .nplanes + tile .plane
518- if tile .ifd .TileByteCounts [idx ] > 0 {
560+ bc := tile .ifd .TileByteCounts [idx ]
561+ if bc > 0 {
519562 _ , err := tile .ifd .r .Seek (int64 (tile .ifd .OriginalTileOffsets [idx ]), io .SeekStart )
520563 if err != nil {
521564 return fmt .Errorf ("seek to %d: %w" , tile .ifd .OriginalTileOffsets [idx ], err )
522565 }
523- _ , err = io .CopyN (out , tile .ifd .r , int64 (tile .ifd .TileByteCounts [idx ]))
566+ if uint32 (len (data )) < bc + 8 {
567+ data = make ([]byte , (bc + 8 )* 2 )
568+ }
569+ binary .LittleEndian .PutUint32 (data , bc ) //header ghost: tile size
570+ _ , err = tile .ifd .r .Read (data [4 : 4 + bc ])
571+ if err != nil {
572+ return fmt .Errorf ("read %d from %d: %w" ,
573+ bc , tile .ifd .OriginalTileOffsets [idx ], err )
574+ }
575+ copy (data [4 + bc :8 + bc ], data [bc :4 + bc ]) //trailer ghost: repeat last 4 bytes
576+ _ , err = out .Write (data [0 : bc + 8 ])
524577 if err != nil {
525- return fmt .Errorf ("copy %d from %d: %w" ,
526- tile .ifd .TileByteCounts [idx ], tile .ifd .OriginalTileOffsets [idx ], err )
578+ return fmt .Errorf ("write %d: %w" , bc , err )
527579 }
528580 }
529581 }
@@ -812,9 +864,7 @@ func (cog *cog) dataInterlacing() datas {
812864 ifdo = cog .ifd
813865 for idx := count - 1 ; idx >= 0 ; idx -- {
814866 ret [idx ] = append (ret [idx ], ifdo )
815- for _ , mi := range ifdo .masks {
816- ret [idx ] = append (ret [idx ], mi )
817- }
867+ ret [idx ] = append (ret [idx ], ifdo .masks ... )
818868 ifdo = ifdo .overview
819869 }
820870 return ret
0 commit comments