001/*- 002 ******************************************************************************* 003 * Copyright (c) 2022 Diamond Light Source Ltd. 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * Peter Chang - initial API and implementation and/or initial documentation 011 *******************************************************************************/ 012 013package org.eclipse.january.dataset; 014 015import java.util.Arrays; 016 017import org.slf4j.Logger; 018import org.slf4j.LoggerFactory; 019 020/** 021 * Class to hold colour datasets as red, green, blue tuples of byte integers. Note that 022 * the values are treated as unsigned integers 023 * @since 2.3 024 */ 025public class RGBByteDataset extends CompoundByteDataset implements Cloneable { 026 // pin UID to base class 027 private static final long serialVersionUID = Dataset.serialVersionUID; 028 029 private static final Logger logger = LoggerFactory.getLogger(RGBByteDataset.class); 030 031 private static final int ISIZE = 3; // number of elements per item 032 033 /** 034 * Create a null dataset 035 */ 036 public RGBByteDataset() { 037 super(ISIZE); 038 } 039 040 /** 041 * @param shape output shape 042 */ 043 public RGBByteDataset(final int... shape) { 044 super(ISIZE, shape); 045 } 046 047 /** 048 * @param data interleaved RGB values 049 * @param shape output shape 050 */ 051 public RGBByteDataset(final byte[] data, final int... shape) { 052 super(ISIZE, data, shape); 053 } 054 055 /** 056 * Copy a dataset 057 * @param dataset to clone 058 */ 059 public RGBByteDataset(final RGBByteDataset dataset) { 060 super(dataset); 061 } 062 063 @Override 064 public RGBByteDataset clone() { 065 return new RGBByteDataset(this); 066 } 067 068 /** 069 * Create a dataset using given data (red, green and blue parts are given separately) 070 * @param redData data for red 071 * @param greenData data for green 072 * @param blueData data for blue 073 * @param shape (can be null to create 1D dataset) 074 */ 075 public RGBByteDataset(final int[] redData, final int[] greenData, final int[] blueData, int... shape) { 076 int dsize = redData.length > greenData.length ? greenData.length : redData.length; 077 dsize = dsize > blueData.length ? blueData.length : dsize; 078 if (shape == null || shape.length == 0) { 079 shape = new int[] {dsize}; 080 } 081 isize = ISIZE; 082 size = ShapeUtils.calcSize(shape); 083 if (size != dsize) { 084 logger.error("Shape is not compatible with size of data array"); 085 throw new IllegalArgumentException("Shape is not compatible with size of data array"); 086 } 087 this.shape = shape.clone(); 088 089 try { 090 odata = data = createArray(size); 091 } catch (Throwable t) { 092 logger.error("Could not create a dataset of shape {}", Arrays.toString(shape), t); 093 throw new IllegalArgumentException(t); 094 } 095 096 for (int i = 0, n = 0; i < size; i++) { 097 data[n++] = (byte) redData[i]; 098 data[n++] = (byte) greenData[i]; 099 data[n++] = (byte) blueData[i]; 100 } 101 } 102 103 /** 104 * Create a dataset using given data (red, green and blue parts are given separately) 105 * @param redData data for red 106 * @param greenData data for green 107 * @param blueData data for blue 108 * @param shape (can be null to create 1D dataset) 109 */ 110 public RGBByteDataset(final short[] redData, final short[] greenData, final short[] blueData, int... shape) { 111 int dsize = redData.length > greenData.length ? greenData.length : redData.length; 112 dsize = dsize > blueData.length ? blueData.length : dsize; 113 if (shape == null || shape.length == 0) { 114 shape = new int[] {dsize}; 115 } 116 isize = ISIZE; 117 size = ShapeUtils.calcSize(shape); 118 if (size != dsize) { 119 logger.error("Shape is not compatible with size of data array"); 120 throw new IllegalArgumentException("Shape is not compatible with size of data array"); 121 } 122 this.shape = shape.clone(); 123 124 try { 125 odata = data = createArray(size); 126 } catch (Throwable t) { 127 logger.error("Could not create a dataset of shape {}", Arrays.toString(shape), t); 128 throw new IllegalArgumentException(t); 129 } 130 131 for (int i = 0, n = 0; i < size; i++) { 132 data[n++] = (byte) redData[i]; 133 data[n++] = (byte) greenData[i]; 134 data[n++] = (byte) blueData[i]; 135 } 136 } 137 138 /** 139 * Create a dataset using given data (red, green and blue parts are given separately) 140 * @param redData data for red 141 * @param greenData data for green 142 * @param blueData data for blue 143 * @param shape (can be null to create 1D dataset) 144 */ 145 public RGBByteDataset(final byte[] redData, final byte[] greenData, final byte[] blueData, int... shape) { 146 int dsize = redData.length > greenData.length ? greenData.length : redData.length; 147 dsize = dsize > blueData.length ? blueData.length : dsize; 148 if (shape == null || shape.length == 0) { 149 shape = new int[] {dsize}; 150 } 151 isize = ISIZE; 152 size = ShapeUtils.calcSize(shape); 153 if (size != dsize) { 154 logger.error("Shape is not compatible with size of data array"); 155 throw new IllegalArgumentException("Shape is not compatible with size of data array"); 156 } 157 this.shape = shape.clone(); 158 159 try { 160 odata = data = createArray(size); 161 } catch (Throwable t) { 162 logger.error("Could not create a dataset of shape {}", Arrays.toString(shape), t); 163 throw new IllegalArgumentException(t); 164 } 165 166 for (int i = 0, n = 0; i < size; i++) { 167 data[n++] = redData[i]; 168 data[n++] = greenData[i]; 169 data[n++] = blueData[i]; 170 } 171 } 172 173 private final static int MIN_VALUE = 0; 174 private final static int MAX_VALUE = 255; 175 176 /** 177 * Create a dataset using given colour data (colour components are given separately) 178 * @param red dataset 179 * @param green dataset 180 * @param blue dataset 181 */ 182 public RGBByteDataset(final Dataset red, final Dataset green, final Dataset blue) { 183 super(ISIZE, red.getShapeRef()); 184 red.checkCompatibility(green); 185 red.checkCompatibility(blue); 186 187 if (red.max().doubleValue() > MAX_VALUE || red.min().doubleValue() < MIN_VALUE || 188 green.max().doubleValue() > MAX_VALUE || green.min().doubleValue() < MIN_VALUE || 189 blue.max().doubleValue() > MAX_VALUE || blue.min().doubleValue() < MIN_VALUE) { 190 logger.warn("Some values are out of range and will be truncated"); 191 } 192 193 IndexIterator riter = red.getIterator(); 194 IndexIterator giter = green.getIterator(); 195 IndexIterator biter = blue.getIterator(); 196 197 for (int i = 0; riter.hasNext() && giter.hasNext() && biter.hasNext();) { 198 data[i++] = (byte) red.getElementLongAbs(riter.index); 199 data[i++] = (byte) green.getElementLongAbs(giter.index); 200 data[i++] = (byte) blue.getElementLongAbs(biter.index); 201 } 202 } 203 204 /** 205 * Create a dataset using given grey data 206 * @param grey dataset 207 */ 208 public RGBByteDataset(final Dataset grey) { 209 super(ISIZE, grey.getShapeRef()); 210 211 IndexIterator giter = grey.getIterator(); 212 213 for (int i = 0; giter.hasNext();) { 214 final byte g = (byte) grey.getElementLongAbs(giter.index); 215 data[i++] = g; 216 data[i++] = g; 217 data[i++] = g; 218 } 219 } 220 221 /** 222 * Create a dataset using given compound data 223 * @param colour dataset with colour data 224 */ 225 public RGBByteDataset(final CompoundDataset colour) { 226 super(ISIZE, colour.getShapeRef()); 227 228 if (colour.getElementsPerItem() != 3) { 229 throw new IllegalArgumentException("Compound dataset must have three elements per item"); 230 } 231 232 final IndexIterator it = colour.getIterator(); 233 for (int i = 0; it.hasNext();) { 234 data[i++] = (byte) colour.getElementLongAbs(it.index); 235 data[i++] = (byte) colour.getElementLongAbs(it.index + 1); 236 data[i++] = (byte) colour.getElementLongAbs(it.index + 2); 237 } 238 } 239 240 /** 241 * Create a RGB dataset from an object which could be a Java list, array (of arrays...) or Number. Ragged 242 * sequences or arrays are padded with zeros. The item size is the last dimension of the corresponding 243 * elemental dataset 244 * 245 * @param obj object 246 * @return dataset with contents given by input 247 */ 248 public static RGBByteDataset createFromObject(final Object obj) { 249 CompoundByteDataset result = (CompoundByteDataset) DatasetUtils.createCompoundDataset(ByteDataset.createFromObject(obj), ISIZE); 250 return new RGBByteDataset(result.data, result.shape); 251 } 252 253 /** 254 * Create a RGB dataset from a compound dataset (no normalisation performed) 255 * @param a dataset 256 * @return RGB dataset (grey if input dataset has less than 3 elements per item) 257 */ 258 public static RGBByteDataset createFromCompoundDataset(final CompoundDataset a) { 259 if (a instanceof RGBByteDataset) 260 return (RGBByteDataset) a; 261 final int is = a.getElementsPerItem(); 262 if (is < 3) { 263 return new RGBByteDataset((Dataset) a); 264 } 265 266 if (a instanceof CompoundByteDataset && is == 3) { 267 return new RGBByteDataset((byte[]) a.getBuffer(), a.getShapeRef()); 268 } 269 270 final RGBByteDataset rgb = new RGBByteDataset(a.getShapeRef()); 271 final IndexIterator it = a.getIterator(); 272 273 int n = 0; 274 while (it.hasNext()) { 275 rgb.data[n++] = (byte) a.getElementLongAbs(it.index); 276 rgb.data[n++] = (byte) a.getElementLongAbs(it.index + 1); 277 rgb.data[n++] = (byte) a.getElementLongAbs(it.index + 2); 278 } 279 280 return rgb; 281 } 282 283 /** 284 * Create a RGB dataset from hue, saturation and value dataset 285 * @param hue (in degrees from -360 to 360) 286 * @param saturation (from 0 to 1), can be null to denote 1 287 * @param value (from 0 to 1) 288 * @return RGB dataset 289 */ 290 public static RGBByteDataset createFromHSV(final Dataset hue, final Dataset saturation, final Dataset value) { 291 if ((saturation != null && !hue.isCompatibleWith(saturation)) || !hue.isCompatibleWith(value)) { 292 throw new IllegalArgumentException("Hue, saturation and value datasets must have the same shape"); 293 } 294 295 RGBByteDataset result = new RGBByteDataset(hue.getShapeRef()); 296 IndexIterator it = result.getIterator(true); 297 int[] pos = it.getPos(); 298 byte[] rgb = new byte[3]; 299 300 if (saturation == null) { 301 while (it.hasNext()) { 302 convertHSVToRGB(hue.getDouble(pos), 1, value.getDouble(pos), rgb); 303 result.setAbs(it.index, rgb); 304 } 305 } else { 306 while (it.hasNext()) { 307 convertHSVToRGB(hue.getDouble(pos), saturation.getDouble(pos), value.getDouble(pos), rgb); 308 result.setAbs(it.index, rgb); 309 } 310 } 311 312 return result; 313 } 314 315 /** 316 * Create a RGB dataset from hue, saturation and lightness dataset 317 * @param hue (in degrees from -360 to 360) 318 * @param saturation (from 0 to 1), can be null to denote 1 319 * @param lightness (from 0 to 1) 320 * @return RGB dataset 321 */ 322 public static RGBByteDataset createFromHSL(final Dataset hue, final Dataset saturation, final Dataset lightness) { 323 if ((saturation != null && !hue.isCompatibleWith(saturation)) || !hue.isCompatibleWith(lightness)) { 324 throw new IllegalArgumentException("Hue, saturation and lightness datasets must have the same shape"); 325 } 326 327 RGBByteDataset result = new RGBByteDataset(hue.getShapeRef()); 328 IndexIterator it = result.getIterator(true); 329 int[] pos = it.getPos(); 330 byte[] rgb = new byte[3]; 331 332 if (saturation == null) { 333 while (it.hasNext()) { 334 convertHSLToRGB(hue.getDouble(pos), 1, lightness.getDouble(pos), rgb); 335 result.setAbs(it.index, rgb); 336 } 337 } else { 338 while (it.hasNext()) { 339 convertHSLToRGB(hue.getDouble(pos), saturation.getDouble(pos), lightness.getDouble(pos), rgb); 340 result.setAbs(it.index, rgb); 341 } 342 } 343 344 return result; 345 } 346 347 private static void convertHSVToRGB(double h, double s, double v, byte[] rgb) { 348 double m = 255 * v; 349 double chroma = s * m; 350 m -= chroma; 351 double hprime = h / 60.; 352 if (hprime < 0) { 353 hprime += 6; 354 } 355 byte sx = (byte) (chroma * (1 - Math.abs((hprime % 2) - 1)) + m); 356 byte sc = (byte) (chroma + m); 357 byte sm = (byte) m; 358 359 if (hprime < 1) { 360 rgb[0] = sc; 361 rgb[1] = sx; 362 rgb[2] = sm; 363 } else if (hprime < 2) { 364 rgb[0] = sx; 365 rgb[1] = sc; 366 rgb[2] = sm; 367 } else if (hprime < 3) { 368 rgb[0] = sm; 369 rgb[1] = sc; 370 rgb[2] = sx; 371 } else if (hprime < 4) { 372 rgb[0] = sm; 373 rgb[1] = sx; 374 rgb[2] = sc; 375 } else if (hprime < 5) { 376 rgb[0] = sx; 377 rgb[1] = sm; 378 rgb[2] = sc; 379 } else if (hprime < 6) { 380 rgb[0] = sc; 381 rgb[1] = sm; 382 rgb[2] = sx; 383 } else { // if hue is outside domain 384 rgb[0] = sm; 385 rgb[1] = sm; 386 rgb[2] = sm; 387 } 388 } 389 390 private static void convertHSLToRGB(double h, double s, double l, byte[] rgb) { 391 double m = l; 392 double chroma = s * (1 - Math.abs(2 * m - 1)); 393 m -= chroma * 0.5; 394 m *= 255; 395 chroma *= 255; 396 double hprime = h / 60.; 397 if (hprime < 0) { 398 hprime += 6; 399 } 400 byte sx = (byte) (chroma * (1 - Math.abs((hprime % 2) - 1)) + m); 401 byte sc = (byte) (chroma + m); 402 byte sm = (byte) m; 403 404 if (hprime < 1) { 405 rgb[0] = sc; 406 rgb[1] = sx; 407 rgb[2] = sm; 408 } else if (hprime < 2) { 409 rgb[0] = sx; 410 rgb[1] = sc; 411 rgb[2] = sm; 412 } else if (hprime < 3) { 413 rgb[0] = sm; 414 rgb[1] = sc; 415 rgb[2] = sx; 416 } else if (hprime < 4) { 417 rgb[0] = sm; 418 rgb[1] = sx; 419 rgb[2] = sc; 420 } else if (hprime < 5) { 421 rgb[0] = sx; 422 rgb[1] = sm; 423 rgb[2] = sc; 424 } else if (hprime < 6) { 425 rgb[0] = sc; 426 rgb[1] = sm; 427 rgb[2] = sx; 428 } else { // if hue is outside domain 429 rgb[0] = sm; 430 rgb[1] = sm; 431 rgb[2] = sm; 432 } 433 } 434 435 @Override 436 public RGBByteDataset getSlice(SliceIterator siter) { 437 CompoundByteDataset base = super.getSlice(siter); 438 439 RGBByteDataset slice = new RGBByteDataset(); 440 copyToView(base, slice, false, false); 441 slice.setData(); 442 return slice; 443 } 444 445 @Override 446 public RGBByteDataset getView(boolean deepCopyMetadata) { 447 RGBByteDataset view = new RGBByteDataset(); 448 copyToView(this, view, true, deepCopyMetadata); 449 view.setData(); 450 return view; 451 } 452 453 /** 454 * @return red value in the first position 455 */ 456 public byte getRed() { 457 return data[getFirst1DIndex()]; 458 } 459 460 /** 461 * @param i position in first dimension 462 * @return red value in given position 463 */ 464 public byte getRed(final int i) { 465 return data[get1DIndex(i)]; 466 } 467 468 /** 469 * @param i position in first dimension 470 * @param j position in second dimension 471 * @return red value in given position 472 */ 473 public byte getRed(final int i, final int j) { 474 return data[get1DIndex(i, j)]; 475 } 476 477 /** 478 * @param pos position 479 * @return red value in given position 480 */ 481 public byte getRed(final int... pos) { 482 return data[get1DIndex(pos)]; 483 } 484 485 /** 486 * @return green value in the first position 487 */ 488 public byte getGreen() { 489 return data[getFirst1DIndex() + 1]; 490 } 491 492 /** 493 * @param i position in first dimension 494 * @return green value in given position 495 */ 496 public byte getGreen(final int i) { 497 return data[get1DIndex(i) + 1]; 498 } 499 500 /** 501 * @param i position in first dimension 502 * @param j position in second dimension 503 * @return green value in given position 504 */ 505 public byte getGreen(final int i, final int j) { 506 return data[get1DIndex(i, j) + 1]; 507 } 508 509 /** 510 * @param pos position 511 * @return green value in given position 512 */ 513 public byte getGreen(final int... pos) { 514 return data[get1DIndex(pos) + 1]; 515 } 516 517 /** 518 * @return blue value in the first position 519 */ 520 public byte getBlue() { 521 return data[getFirst1DIndex() + 2]; 522 } 523 524 /** 525 * @param i position in first dimension 526 * @return blue value in given position 527 */ 528 public byte getBlue(final int i) { 529 return data[get1DIndex(i) + 2]; 530 } 531 532 /** 533 * @param i position in first dimension 534 * @param j position in second dimension 535 * @return blue value in given position 536 */ 537 public byte getBlue(final int i, final int j) { 538 return data[get1DIndex(i, j) + 2]; 539 } 540 541 /** 542 * @param pos position 543 * @return blue value in given position 544 */ 545 public byte getBlue(final int... pos) { 546 return data[get1DIndex(pos) + 2]; 547 } 548 549 /** 550 * Get a red value from given absolute index as a byte - note this index does not 551 * take in account the item size so be careful when using with multi-element items 552 * 553 * @param n absolute index 554 * @return red value 555 */ 556 public byte getRedAbs(int n) { 557 return data[n*isize]; 558 } 559 560 /** 561 * Get a green value from given absolute index as a byte - note this index does not 562 * take in account the item size so be careful when using with multi-element items 563 * 564 * @param n absolute index 565 * @return green value 566 */ 567 public byte getGreenAbs(int n) { 568 return data[n*isize + 1]; 569 } 570 571 /** 572 * Get a blue value from given absolute index as a byte - note this index does not 573 * take in account the item size so be careful when using with multi-element items 574 * 575 * @param n absolute index 576 * @return blue value 577 */ 578 public byte getBlueAbs(int n) { 579 return data[n*isize + 2]; 580 } 581 582 583 // weights from NTSC formula aka ITU-R BT.601 for mapping RGB to luma 584 private static final double Wr = 0.299, Wg = 0.587, Wb = 0.114; 585 586 /** 587 * Convert colour dataset to a grey-scale one using the NTSC formula, aka ITU-R BT.601, for RGB to luma mapping 588 * @param <T> dataset sub-interface 589 * @param clazz dataset sub-interface 590 * @return a grey-scale dataset of given type 591 */ 592 public <T extends Dataset> T createGreyDataset(final Class<T> clazz) { 593 return createGreyDataset(clazz, Wr, Wg, Wb); 594 } 595 596 /** 597 * Convert colour dataset to a grey-scale one using given RGB to luma mapping 598 * @param <T> dataset sub-interface 599 * @param clazz dataset sub-interface 600 * @param red weight 601 * @param green weight 602 * @param blue weight 603 * @return a grey-scale dataset of given class 604 */ 605 public <T extends Dataset> T createGreyDataset(final Class<T> clazz, final double red, final double green, final double blue) { 606 final T grey = DatasetFactory.zeros(clazz, shape); 607 final IndexIterator it = getIterator(); 608 609 int i = 0; 610 while (it.hasNext()) { 611 grey.setObjectAbs(i++, red*Byte.toUnsignedInt(data[it.index]) + green*Byte.toUnsignedInt(data[it.index + 1]) + blue*Byte.toUnsignedInt(data[it.index + 2])); 612 } 613 return grey; 614 } 615 616 /** 617 * Convert colour dataset to a grey-scale one using the NTSC formula, aka ITU-R BT.601, for RGB to luma mapping 618 * @param dtype dataset type 619 * @return a grey-scale dataset of given class 620 * @deprecated Use {@link RGBByteDataset#createGreyDataset(Class)} 621 */ 622 @Deprecated 623 public Dataset createGreyDataset(final int dtype) { 624 return createGreyDataset(Wr, Wg, Wb, dtype); 625 } 626 627 /** 628 * Convert colour dataset to a grey-scale one using given RGB to luma mapping 629 * @param red weight 630 * @param green weight 631 * @param blue weight 632 * @param dtype dataset type 633 * @return a grey-scale dataset of given type 634 * @deprecated Use {@link RGBByteDataset#createGreyDataset(Class, double, double, double)} 635 */ 636 @Deprecated 637 public Dataset createGreyDataset(final double red, final double green, final double blue, final int dtype) { 638 return createGreyDataset(DTypeUtils.getInterface(dtype), red, green, blue); 639 } 640 641 /** 642 * Extract red colour channel 643 * @param <T> dataset sub-interface 644 * @param clazz dataset sub-interface 645 * @return a dataset of given class 646 */ 647 public <T extends Dataset> T createRedDataset(final Class<T> clazz) { 648 return createColourChannelDataset(0, clazz, "red"); 649 } 650 651 /** 652 * Extract green colour channel 653 * @param <T> dataset sub-interface 654 * @param clazz dataset sub-interface 655 * @return a dataset of given class 656 */ 657 public <T extends Dataset> T createGreenDataset(final Class<T> clazz) { 658 return createColourChannelDataset(1, clazz, "green"); 659 } 660 661 /** 662 * Extract blue colour channel 663 * @param <T> dataset sub-interface 664 * @param clazz dataset sub-interface 665 * @return a dataset of given class 666 */ 667 public <T extends Dataset> T createBlueDataset(final Class<T> clazz) { 668 return createColourChannelDataset(2, clazz, "blue"); 669 } 670 671 /** 672 * Extract red colour channel 673 * @param dtype dataset type 674 * @return a dataset of given type 675 * @deprecated Use {@link #createRedDataset} 676 */ 677 @Deprecated 678 public Dataset createRedDataset(final int dtype) { 679 return createColourChannelDataset(0, DTypeUtils.getInterface(dtype), "red"); 680 } 681 682 /** 683 * Extract green colour channel 684 * @param dtype dataset type 685 * @return a dataset of given type 686 * @deprecated Use {@link #createGreenDataset} 687 */ 688 @Deprecated 689 public Dataset createGreenDataset(final int dtype) { 690 return createColourChannelDataset(1, DTypeUtils.getInterface(dtype), "green"); 691 } 692 693 /** 694 * Extract blue colour channel 695 * @param dtype dataset type 696 * @return a dataset of given type 697 * @deprecated Use {@link #createBlueDataset} 698 */ 699 @Deprecated 700 public Dataset createBlueDataset(final int dtype) { 701 return createColourChannelDataset(2, DTypeUtils.getInterface(dtype), "blue"); 702 } 703 704 private <T extends Dataset> T createColourChannelDataset(int channelOffset, Class<T> clazz, String cName) { 705 final T channel = DatasetFactory.zeros(clazz, shape); 706 707 final StringBuilder cname = name == null ? new StringBuilder() : new StringBuilder(name); 708 if (cname.length() > 0) { 709 cname.append('.'); 710 } 711 cname.append(cName); 712 channel.setName(cname.toString()); 713 714 final IndexIterator it = getIterator(); 715 716 int i = 0; 717 while (it.hasNext()) { 718 channel.setObjectAbs(i++, Byte.toUnsignedInt(data[it.index + channelOffset])); 719 } 720 721 return channel; 722 } 723 724 725 /** 726 * @return red view 727 */ 728 public ByteDataset getRedView() { 729 return getColourChannelView(0, "red"); 730 } 731 732 /** 733 * @return green view 734 */ 735 public ByteDataset getGreenView() { 736 return getColourChannelView(1, "green"); 737 } 738 739 /** 740 * @return blue view 741 */ 742 public ByteDataset getBlueView() { 743 return getColourChannelView(2, "blue"); 744 } 745 746 private ByteDataset getColourChannelView(final int channelOffset, final String cName) { 747 ByteDataset view = getElements(channelOffset); 748 view.setName(cName); 749 return view; 750 } 751 752 @Override 753 public double getElementDoubleAbs(final int index) { 754 return Byte.toUnsignedInt(data[index]); 755 } 756 757 @Override 758 public long getElementLongAbs(final int index) { 759 return Byte.toUnsignedInt(data[index]); 760 } 761 762 @Override 763 public Number max(boolean... ignored) { 764 int max = 0; 765 final IndexIterator it = getIterator(); 766 767 while (it.hasNext()) { 768 for (int i = 0; i < ISIZE; i++) { 769 int value = Byte.toUnsignedInt(data[it.index + i]); 770 if (value > max) 771 max = value; 772 } 773 } 774 return max; 775 } 776 777 @Override 778 public Number min(boolean... ignored) { 779 int min = MAX_VALUE; 780 final IndexIterator it = getIterator(); 781 782 while (it.hasNext()) { 783 for (int i = 0; i < ISIZE; i++) { 784 int value = Byte.toUnsignedInt(data[it.index + i]); 785 if (value < min) 786 min = value; 787 } 788 } 789 return min; 790 } 791}