All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.org.jetbrains.letsPlot.util.pngj.PngHelperInternal.kt Maven / Gradle / Ivy

There is a newer version: 4.8.0
Show newest version
/*
 * Copyright (c) 2023 JetBrains s.r.o.
 * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
 *
 * This file has been modified by JetBrains : Java code has been converted to Kotlin code.
 *
 * THE FOLLOWING IS THE COPYRIGHT OF THE ORIGINAL DOCUMENT:
 *
 * Copyright (c) 2009-2012, Hernán J. González.
 * Licensed under the Apache License, Version 2.0.
 *
 * The original PNGJ library is written in Java and can be found here: [PNGJ](https://github.com/leonbloy/pngj).
 */

@file:Suppress("unused", "UNUSED_PARAMETER", "KDocUnresolvedReference")

package org.jetbrains.letsPlot.util.pngj

import org.jetbrains.letsPlot.commons.logging.Logger
import org.jetbrains.letsPlot.commons.logging.PrintlnLogger
import kotlin.jvm.JvmOverloads


/**
 * Some utility static methods for internal use.
 *
 *
 * Client code should not normally use this class
 *
 *
 */
internal object PngHelperInternal {
    private const val isDebug = false
    private val LOGGER: Logger = PrintlnLogger(PngHelperInternal::class.simpleName ?: "PngHelperInternal")

    /**
     * Default charset, used internally by PNG for several things
     */
    //var charsetLatin1: java.nio.charset.Charset = java.nio.charset.StandardCharsets.ISO_8859_1

    /**
     * UTF-8 is only used for some chunks
     */
    //var charsetUTF8 = UTF_8

    /**
     * PNG magic bytes
     */
    val pngIdSignature: ByteArray
        get() = byteArrayOf(-119, 80, 78, 71, 13, 10, 26, 10)

    fun doubleToInt100000(d: Double): Int {
        return (d * 100000.0 + 0.5).toInt()
    }

    fun intToDouble100000(i: Int): Double {
        return i / 100000.0
    }

    fun readByte(inputStream: InputPngStream): Int {
        return try {
            inputStream.read()
        } catch (e: Throwable) {
            throw PngjInputException("error reading byte", e)
        }
    }

    /**
     * -1 if eof
     *
     * PNG uses "network byte order"
     */
    fun readInt2(inputStream: InputPngStream): Int {
        return try {
            val b1: Int = inputStream.read()
            val b2: Int = inputStream.read()
            if (b1 == -1 || b2 == -1) -1 else b1 shl 8 or b2
        } catch (e: Throwable) {
            throw PngjInputException("error reading Int2", e)
        }
    }

    /**
     * -1 if eof
     *
     * PNG uses "network byte order"
     */
    fun readInt4(inputStream: InputPngStream): Int {
        return try {
            val b1: Int = inputStream.read()
            val b2: Int = inputStream.read()
            val b3: Int = inputStream.read()
            val b4: Int = inputStream.read()
            if (b1 == -1 || b2 == -1 || b3 == -1 || b4 == -1) -1 else b1 shl 24 or (b2 shl 16) or (b3 shl 8) + b4
        } catch (e: Throwable) {
            throw PngjInputException("error reading Int4", e)
        }
    }

    fun readInt1fromByte(b: ByteArray?, offset: Int): Int {
        require(b != null)
        return b[offset].toInt() and 0xff
    }

    fun readInt2fromBytes(b: ByteArray?, offset: Int): Int {
        require(b != null)
        return b[offset].toInt() and 0xff shl 8 or (b[offset + 1].toInt() and 0xff)
    }

    fun readInt4fromBytes(b: ByteArray?, offset: Int): Int {
        require(b != null)
        return (b[offset].toInt() and 0xff shl 24 or (b[offset + 1].toInt() and 0xff shl 16) or (b[offset + 2].toInt() and 0xff shl 8)
                or (b[offset + 3].toInt() and 0xff))
    }

    fun writeByte(os: OutputPngStream, b: Byte) {
        try {
            os.write(b.toInt())
        } catch (e: Throwable) {
            throw PngjOutputException(e)
        }
    }

    fun writeByte(os: OutputPngStream, bs: ByteArray) {
        try {
            os.write(bs)
        } catch (e: Throwable) {
            throw PngjOutputException(e)
        }
    }

    fun writeInt2(os: OutputPngStream, n: Int) {
        val temp = byteArrayOf((n shr 8 and 0xff).toByte(), (n and 0xff).toByte())
        writeBytes(os, temp)
    }

    fun writeInt4(os: OutputPngStream, n: Int) {
        val temp = ByteArray(4)
        writeInt4tobytes(n, temp, 0)
        writeBytes(os, temp)
    }

    fun writeInt2tobytes(n: Int, b: ByteArray?, offset: Int) {
        require(b != null)
        b[offset] = (n shr 8 and 0xff).toByte()
        b[offset + 1] = (n and 0xff).toByte()
    }

    fun writeInt4tobytes(n: Int, b: ByteArray?, offset: Int) {
        require(b != null)
        b[offset] = (n shr 24 and 0xff).toByte()
        b[offset + 1] = (n shr 16 and 0xff).toByte()
        b[offset + 2] = (n shr 8 and 0xff).toByte()
        b[offset + 3] = (n and 0xff).toByte()
    }

    /**
     * guaranteed to read exactly len bytes. throws error if it can't
     */
    fun readBytes(inputStream: InputPngStream, b: ByteArray, offset: Int, len: Int) {
        if (len == 0) return
        try {
            var read = 0
            while (read < len) {
                val n: Int = inputStream.read(b, offset + read, len - read)
                if (n < 1) throw PngjInputException("error reading bytes, $n !=$len")
                read += n
            }
        } catch (e: Throwable) {
            throw PngjInputException("error reading", e)
        }
    }

    fun skipBytes(inputStream: InputPngStream, len: Long) {
        @Suppress("NAME_SHADOWING")
        var len = len
        try {
            while (len > 0) {
                val n1: Long = inputStream.skip(len)
                if (n1 > 0) {
                    len -= n1
                } else if (n1 == 0L) { // should we retry? lets read one byte
                    if (inputStream.read() == -1) // EOF
                        break else len--
                } else throw Throwable("skip() returned a negative value ???")
            }
        } catch (e: Throwable) {
            throw PngjInputException(e)
        }
    }

    fun writeBytes(os: OutputPngStream, b: ByteArray) {
        try {
            os.write(b)
        } catch (e: Throwable) {
            throw PngjOutputException(e)
        }
    }

    fun writeBytes(os: OutputPngStream, b: ByteArray, offset: Int, n: Int) {
        try {
            os.write(b, offset, n)
        } catch (e: Throwable) {
            throw PngjOutputException(e)
        }
    }

    fun logdebug(msg: String) {
        if (isDebug) println("logdebug: $msg")
    }

    // / filters
    fun filterRowNone(r: Int): Int {
        return (r and 0xFF)
    }

    fun filterRowSub(r: Int, left: Int): Int {
        return (r - left) and 0xFF
    }

    fun filterRowUp(r: Int, up: Int): Int {
        return (r - up) and 0xFF
    }

    fun filterRowAverage(r: Int, left: Int, up: Int): Int {
        return r - (left + up) / 2 and 0xFF
    }

    fun filterRowPaeth(r: Int, left: Int, up: Int, upleft: Int): Int { // a = left, b = above, c
        // = upper left
        return r - filterPaethPredictor(left, up, upleft) and 0xFF
    }

    fun filterPaethPredictor(a: Int, b: Int, c: Int): Int { // a = left, b =
        // above, c = upper
        // left
        // from
        // http://www.libpng.org/pub/png/spec/1.2/PNG-Filters.html
        val p = a + b - c // ; initial estimate
        val pa = if (p >= a) p - a else a - p
        val pb = if (p >= b) p - b else b - p
        val pc = if (p >= c) p - c else c - p
        // ; return nearest of a,b,c,
        // ; breaking ties in order a,b,c.
        return if (pa <= pb && pa <= pc) a else if (pb <= pc) b else c
    }

    /**
     * Prits a debug message (prints class name, method and line number)
     *
     * @param obj
     * : Object to print
     */
    fun debug(obj: Any?) {
        debug(obj, 1, true)
    }

    /**
     * Prints a debug message (prints class name, method and line number) to
     * stderr and logFile
     *
     * @param obj
     * : Object to print
     * @param offset
     * : Offset N lines from stacktrace
     * @param newLine
     * : Print a newline char at the end ('\n')
     */
    /**
     * Prits a debug message (prints class name, method and line number)
     *
     * @param obj
     * : Object to print
     * @param offset
     * : Offset N lines from stacktrace
     */
    @JvmOverloads
    fun debug(obj: Any?, offset: Int, newLine: Boolean = true) {
        //val ste: java.lang.StackTraceElement = java.lang.Exception().getStackTrace().get(1 + offset)
        //var steStr: String = ste.getClassName()
        //val ind = steStr.lastIndexOf('.')
        //steStr = steStr.substring(ind + 1)
        //steStr += "." + ste.getMethodName() + "(" + ste.getLineNumber() + "): " + obj?.toString()
        //println(steStr)
    }


    fun getDigest(pngr: PngReader): Long {
        return pngr.simpleDigest
    }

    fun initCrcForTests(pngr: PngReader) {
        pngr.prepareSimpleDigestComputation()
    }

    fun getRawIdatBytes(r: PngReader): Long { // in case of image with frames, returns the current one
        return if (r.isInterlaced) r.chunkseq!!.deinterlacer!!.totalRawBytes else r.curImgInfo.totalRawBytes
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy