1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.imaging.formats.icns; 18 19 import org.apache.commons.imaging.common.Allocator; 20 21 final class Rle24Compression { 22 public static byte[] decompress(final int width, final int height, final byte[] data) { 23 final int pixelCount = width * height; 24 final byte[] result = Allocator.byteArray(4 * pixelCount); 25 26 // Several ICNS parsers advance by 4 bytes here: 27 // https://code.google.com/archive/p/icns2png/ - when the width is >= 128 28 // https://icns.sourceforge.io/ - when those 4 bytes are all zero 29 // 30 // A scan of all .icns files on MacOS shows that 31 // all 128x128 images indeed start with 4 zeroes, 32 // while all smaller images don't. 33 // However it is dangerous to assume 34 // that 4 initial zeroes always need to be skipped, 35 // because they could encode valid pixels on smaller images. 36 // So always skip on 128x128, and never skip on anything else. 37 int dataPos = 0; 38 if (width >= 128 && height >= 128) { 39 dataPos = 4; 40 } 41 42 // argb, band by band in 3 passes, with no alpha 43 for (int band = 1; band <= 3; band++) { 44 int remaining = pixelCount; 45 int resultPos = 0; 46 while (remaining > 0) { 47 if ((data[dataPos] & 0x80) != 0) { 48 final int count = (0xff & data[dataPos]) - 125; 49 for (int i = 0; i < count; i++) { 50 result[band + 4 * resultPos++] = data[dataPos + 1]; 51 } 52 dataPos += 2; 53 remaining -= count; 54 } else { 55 final int count = (0xff & data[dataPos]) + 1; 56 dataPos++; 57 for (int i = 0; i < count; i++) { 58 result[band + 4 * resultPos++] = data[dataPos++]; 59 } 60 remaining -= count; 61 } 62 } 63 } 64 return result; 65 } 66 67 private Rle24Compression() { 68 } 69 }