1 package nom.tam.image.tile.operation.buffer;
2
3 /*
4 * #%L
5 * nom.tam FITS library
6 * %%
7 * Copyright (C) 1996 - 2024 nom-tam-fits
8 * %%
9 * This is free and unencumbered software released into the public domain.
10 *
11 * Anyone is free to copy, modify, publish, use, compile, sell, or
12 * distribute this software, either in source code form or as a compiled
13 * binary, for any purpose, commercial or non-commercial, and by any
14 * means.
15 *
16 * In jurisdictions that recognize copyright laws, the author or authors
17 * of this software dedicate any and all copyright interest in the
18 * software to the public domain. We make this dedication for the benefit
19 * of the public at large and to the detriment of our heirs and
20 * successors. We intend this dedication to be an overt act of
21 * relinquishment in perpetuity of all present and future rights to this
22 * software under copyright law.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
28 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
29 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
30 * OTHER DEALINGS IN THE SOFTWARE.
31 * #L%
32 */
33
34 import java.nio.Buffer;
35
36 import nom.tam.util.type.ElementType;
37
38 /**
39 * <p>
40 * (<i>for internal use</i>) Tiling implementation, for when the tile width is less than the width of the image. For
41 * example, for covering a 300 by 250 image with tiles of 40 by 40 pixels.
42 * </p>
43 * <p>
44 * This subclass of the row based view, will abstract the problems that occur when the tile does not spread over a whole
45 * row. in that case the buffer describing the image does not match the buffer describing the tile. That is why a
46 * temporary buffer is needed to make the buffer continuous.
47 * </p>
48 *
49 * @see TileBufferRowBased
50 */
51 class TileBufferColumnBased extends TileBuffer {
52
53 /**
54 * the buffer representing the tile data gap less. this will exist only between the first getBuffer() and the
55 * finish(). This way the memory used for the data copy is allocates as early as needed and freed as soon as
56 * possible.
57 */
58 private Buffer packed;
59
60 /**
61 * the width of the image in pixels, that differs from the width of the tile.
62 */
63 private final int imageWidth;
64
65 TileBufferColumnBased(ElementType<Buffer> baseType, int dataOffset, int imageWidth, int width, int height) {
66 super(baseType, dataOffset, width, height);
67 this.imageWidth = imageWidth;
68 }
69
70 @Override
71 public void finish() {
72 desolveGapLessBuffer();
73 }
74
75 @Override
76 public Buffer getBuffer() {
77 if (packed == null) {
78 createPackedBuffer();
79 }
80 return packed;
81 }
82
83 /**
84 * create the temporary buffer that contains no data gaps.
85 */
86 private void createPackedBuffer() {
87 final int gap = imageWidth - getWidth();
88
89 Buffer raw = getImageBuffer();
90 final int imLength = Math.min(raw.capacity(), getPixelSizeInData());
91
92 raw.position(0);
93
94 ElementType<Buffer> type = elementType();
95 packed = type.newBuffer(getPixelSize());
96
97 for (int i = 0; i < getHeight(); i++) {
98 raw.limit(raw.position() + getWidth());
99 type.appendBuffer(packed, raw);
100 raw.limit(Math.min(raw.position() + gap, imLength));
101 raw.position(raw.limit());
102 }
103 packed.rewind();
104 raw.limit(imLength);
105 }
106
107 /**
108 * resolve the temporary buffer that contains no data gaps, and put the data back into the image buffer.
109 */
110 private void desolveGapLessBuffer() {
111 final int gap = imageWidth - getWidth();
112 Buffer raw = getImageBuffer();
113 raw.position(0);
114 raw.limit(getPixelSizeInData());
115 packed.rewind();
116
117 ElementType<Buffer> type = elementType();
118
119 for (int i = 0; i < getHeight(); i++) {
120 packed.limit(packed.position() + getWidth());
121 type.appendBuffer(raw, packed);
122 raw.position(Math.min(raw.position() + gap, raw.limit()));
123 }
124 packed = null;
125 }
126
127 /**
128 * @return size of the tile data inside the image data. normally tile-height*image-width but then the data block of
129 * the last tile would go over the image data limit.
130 */
131 private int getPixelSizeInData() {
132 return (getHeight() - 1) * imageWidth + getWidth();
133 }
134
135 private ElementType<Buffer> elementType() {
136 return ElementType.forBuffer(getImageBuffer());
137 }
138
139 }