Skip to content

Commit

Permalink
jpeg: a0: use different frequency models for components and DC and AC…
Browse files Browse the repository at this point in the history
… coefficients
  • Loading branch information
Artem Golovko committed Dec 25, 2020
1 parent 85e20b1 commit 685ae71
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 75 deletions.
102 changes: 51 additions & 51 deletions src/main/kotlin/jpeg/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,43 +121,43 @@ Compile with maven ``mvn clean package`` or download from [github](https://githu

| File name | Raw size(bytes) | Compressed size(bytes) | Ratio (%) |
| ----------- | ----------- | ----------- | ----------- |
| airplane30.jpg | 19207 | 18976 | 1.203 |
| tulips30.jpg | 37972 | 38132 | -0.421 |
| serrano30.jpg | 58288 | 58156 | 0.226 |
| girl30.jpg | 24310 | 23525 | 3.229 |
| lena30.jpg | 17578 | 17468 | 0.626 |
| baboon30.jpg | 36113 | 35783 | 0.914 |
| cat30.jpg | 35902 | 36357 | -1.267 |
| sails30.jpg | 45512 | 45230 | 0.620 |
| monarch30.jpg | 28501 | 28510 | -0.032 |
| arctichare30.jpg | 12080 | 11776 | 2.517 |
| fruits30.jpg | 17646 | 17270 | 2.131 |
| frymire30.jpg | 200860 | 200773 | 0.043 |
| watch30.jpg | 46741 | 45664 | 2.304 |
| peppers30.jpg | 18746 | 18618 | 0.683 |
| pool30.jpg | 7467 | 7010 | 6.120 |
| total | 606923 | 603248 | 0.606 |
| airplane30.jpg | 19207 | 18986 | 1.151 |
| tulips30.jpg | 37972 | 37556 | 1.096 |
| serrano30.jpg | 58288 | 57163 | 1.930 |
| girl30.jpg | 24310 | 23228 | 4.451 |
| lena30.jpg | 17578 | 17440 | 0.785 |
| baboon30.jpg | 36113 | 35368 | 2.063 |
| cat30.jpg | 35902 | 35526 | 1.047 |
| sails30.jpg | 45512 | 44459 | 2.314 |
| monarch30.jpg | 28501 | 28447 | 0.189 |
| arctichare30.jpg | 12080 | 11943 | 1.134 |
| fruits30.jpg | 17646 | 17375 | 1.536 |
| frymire30.jpg | 200860 | 197375 | 1.735 |
| watch30.jpg | 46741 | 44309 | 5.203 |
| peppers30.jpg | 18746 | 18649 | 0.517 |
| pool30.jpg | 7467 | 7588 | -1.620 |
| total | 606923 | 595412 | 1.897 |

### Quality 80

| File name | Raw size(bytes) | Compressed size(bytes) | Ratio (%) |
| ----------- | ----------- | ----------- | ----------- |
| cat80.jpg | 81974 | 82911 | -1.143 |
| monarch80.jpg | 64055 | 64775 | -1.124 |
| tulips80.jpg | 85764 | 86734 | -1.131 |
| lena80.jpg | 43872 | 44590 | -1.637 |
| peppers80.jpg | 47929 | 48357 | -0.893 |
| serrano80.jpg | 138167 | 137628 | 0.390 |
| sails80.jpg | 105830 | 107118 | -1.217 |
| airplane80.jpg | 44079 | 44691 | -1.388 |
| baboon80.jpg | 88465 | 89248 | -0.885 |
| watch80.jpg | 101074 | 102433 | -1.345 |
| arctichare80.jpg | 26569 | 27238 | -2.518 |
| girl80.jpg | 59979 | 60479 | -0.834 |
| pool80.jpg | 14492 | 14802 | -2.139 |
| frymire80.jpg | 440857 | 437707 | 0.715 |
| fruits80.jpg | 45303 | 45961 | -1.452 |
| total | 1388409 | 1394672 | -0.451 |
| cat80.jpg | 81974 | 81420 | 0.676 |
| monarch80.jpg | 64055 | 64211 | -0.244 |
| tulips80.jpg | 85764 | 85440 | 0.378 |
| lena80.jpg | 43872 | 44019 | -0.335 |
| peppers80.jpg | 47929 | 47827 | 0.213 |
| serrano80.jpg | 138167 | 135521 | 1.915 |
| sails80.jpg | 105830 | 105759 | 0.067 |
| airplane80.jpg | 44079 | 44457 | -0.858 |
| baboon80.jpg | 88465 | 88303 | 0.183 |
| watch80.jpg | 101074 | 100678 | 0.392 |
| arctichare80.jpg | 26569 | 27264 | -2.616 |
| girl80.jpg | 59979 | 59858 | 0.202 |
| pool80.jpg | 14492 | 14937 | -3.071 |
| frymire80.jpg | 440857 | 431110 | 2.211 |
| fruits80.jpg | 45303 | 45610 | -0.678 |
| total | 1388409 | 1376414 | 0.864 |

## Сжатие квантованных DCT коэффициентов
Был рассмотрен вариант, при котором мы декодируем до квантованных DCT коэффициентов(тем самым увеличиваем данные больше чем в два раза по сравнению с закодированным rle и дельтой коэффициентами).
Expand All @@ -176,39 +176,39 @@ Compile with maven ``mvn clean package`` or download from [github](https://githu
| File name | Raw size(bytes) | Compressed size(bytes) | Ratio (%) |
| ----------- | ----------- | ----------- | ----------- |
| airplane30.jpg | 19207 | 18849 | 1.864 |
| tulips30.jpg | 37972 | 37861 | 0.292 |
| serrano30.jpg | 58288 | 57442 | 1.451 |
| girl30.jpg | 24310 | 23526 | 3.225 |
| lena30.jpg | 17578 | 17469 | 0.620 |
| baboon30.jpg | 36113 | 35784 | 0.911 |
| cat30.jpg | 35902 | 35855 | 0.131 |
| sails30.jpg | 45512 | 45227 | 0.626 |
| tulips30.jpg | 37972 | 37557 | 1.093 |
| serrano30.jpg | 58288 | 57164 | 1.928 |
| girl30.jpg | 24310 | 23229 | 4.447 |
| lena30.jpg | 17578 | 17441 | 0.779 |
| baboon30.jpg | 36113 | 35369 | 2.060 |
| cat30.jpg | 35902 | 35527 | 1.045 |
| sails30.jpg | 45512 | 44460 | 2.311 |
| monarch30.jpg | 28501 | 28228 | 0.958 |
| arctichare30.jpg | 12080 | 11444 | 5.265 |
| fruits30.jpg | 17646 | 17271 | 2.125 |
| fruits30.jpg | 17646 | 17376 | 1.530 |
| frymire30.jpg | 200860 | 194598 | 3.118 |
| watch30.jpg | 46741 | 44445 | 4.912 |
| peppers30.jpg | 18746 | 18619 | 0.677 |
| watch30.jpg | 46741 | 44310 | 5.201 |
| peppers30.jpg | 18746 | 18650 | 0.512 |
| pool30.jpg | 7467 | 6196 | 17.022 |
| total | 606923 | 592814 | 2.325 |
| total | 606923 | 590398 | 2.723 |

### Quality 80

| File name | Raw size(bytes) | Compressed size(bytes) | Ratio (%) |
| ----------- | ----------- | ----------- | ----------- |
| cat80.jpg | 81974 | 81975 | -0.001 |
| cat80.jpg | 81974 | 81421 | 0.675 |
| monarch80.jpg | 64055 | 64056 | -0.002 |
| tulips80.jpg | 85764 | 85765 | -0.001 |
| tulips80.jpg | 85764 | 85441 | 0.377 |
| lena80.jpg | 43872 | 43861 | 0.025 |
| peppers80.jpg | 47929 | 47894 | 0.073 |
| serrano80.jpg | 138167 | 136962 | 0.872 |
| sails80.jpg | 105830 | 105831 | -0.001 |
| peppers80.jpg | 47929 | 47828 | 0.211 |
| serrano80.jpg | 138167 | 135522 | 1.914 |
| sails80.jpg | 105830 | 105760 | 0.066 |
| airplane80.jpg | 44079 | 44076 | 0.007 |
| baboon80.jpg | 88465 | 88466 | -0.001 |
| baboon80.jpg | 88465 | 88304 | 0.182 |
| watch80.jpg | 101074 | 99902 | 1.160 |
| arctichare80.jpg | 26569 | 26271 | 1.122 |
| girl80.jpg | 59979 | 59644 | 0.559 |
| pool80.jpg | 14492 | 13804 | 4.747 |
| frymire80.jpg | 440857 | 435318 | 1.256 |
| frymire80.jpg | 440857 | 431111 | 2.211 |
| fruits80.jpg | 45303 | 45304 | -0.002 |
| total | 1388409 | 1379129 | 0.668 |
| total | 1388409 | 1372305 | 1.160 |
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.davidjohnburrowes.format.jpeg.JpegData
import com.davidjohnburrowes.format.jpeg.data.EntropyData
import commons.*
import jpeg.transcoder.entropy.coding.JpegEntropyCoder
import jpeg.transcoder.entropy.coding.huffman.HuffmanJpegMeta
import java.io.ByteArrayOutputStream
import java.io.InputStream
import java.io.OutputStream
Expand All @@ -22,37 +23,68 @@ private class A0JpegEntropyCoderWriter(

private val jpegData = JpegData().apply { read(input) }

private val encodedSymbols = ByteArrayOutputStream()

private val coefData = ByteArrayOutputStream()
private val jpegMeta = HuffmanJpegMeta.fromJpeg(jpegData)

private val entropyData = jpegData.filterIsInstance<EntropyData>().first()

private val bitInputStream = BitInputStream(entropyData.data.inputStream())

private val componentSymbolsData =
mutableMapOf<Int, Pair<ByteArrayOutputStream, ByteArrayOutputStream>>()

private val coefData = ByteArrayOutputStream()

private val coefDataBitOutputStream = BitOutputStream(coefData, 1)

override fun writeEncoded() {
while (true) {
val symbolBits = (1..8).map { bitInputStream.read() }
if (symbolBits.contains(-1)) {
break
}
(1..jpegMeta.mcuHeight).forEach { hMcu ->
(1..jpegMeta.mcuWidth).forEach { vMcu ->
jpegMeta.components.forEach { component ->
val componentId = component.frameInfo.componentId
val componentSymbolData = componentSymbolsData
.getOrPut(componentId) { ByteArrayOutputStream() to ByteArrayOutputStream() }
(1..component.frameInfo.verticalScaling).forEach { vScale ->
(1..component.frameInfo.horizontalScaling).forEach { hScale ->
var coef = 0
while (coef < 64) {
val coefByteArray = if (coef == 0) {
componentSymbolData.first
} else componentSymbolData.second
val symbolBits = (1..8).map { bitInputStream.read() }
val symbol = symbolBits.bitsToInt()
val zerosSize = symbol shr 4
val coefBitsSize = symbol and 15

val symbol = symbolBits.bitsToInt()
val coefBitsSize = symbol and 15
encodedSymbols.write(symbol)
coefByteArray.write(symbol)

repeat(coefBitsSize) { coefDataBitOutputStream.write(bitInputStream.read()) }
if (coef != 0 && symbol == 0) {
coef = 64
break
}

coef += zerosSize + 1
repeat(coefBitsSize) { coefDataBitOutputStream.write(bitInputStream.read()) }
}
}
}
}
}
}
close()
}

override fun close() {
bitInputStream.close()
coefDataBitOutputStream.close()
val symbolsEncoded = A0Compressor.encode(encodedSymbols.toByteArray())
entropyData.data = symbolsEncoded.size.toBytes() + symbolsEncoded + coefData.toByteArray()

val coefsByComponentsAndTable = componentSymbolsData.map {
val dcData = A0Compressor.encode(it.value.first.toByteArray())
val acData = A0Compressor.encode(it.value.second.toByteArray())
dcData.size.toBytes() + dcData + acData.size.toBytes() + acData
}.reduce { acc, bytes -> acc + bytes }

entropyData.data = coefsByComponentsAndTable + coefData.toByteArray()

jpegData.write(output)
input.close()
output.close()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.davidjohnburrowes.format.jpeg.JpegData
import com.davidjohnburrowes.format.jpeg.data.EntropyData
import commons.*
import jpeg.transcoder.entropy.coding.JpegEntropyDecoder
import jpeg.transcoder.entropy.coding.huffman.HuffmanJpegMeta
import java.io.ByteArrayOutputStream
import java.io.InputStream
import java.io.OutputStream
Expand All @@ -22,27 +23,69 @@ private class A0JpegEntropyDecoderWriter(

private val jpegData = JpegData().apply { read(input) }

private val jpegMeta = HuffmanJpegMeta.fromJpeg(jpegData)

private val entropyData = jpegData.filterIsInstance<EntropyData>().first()

private val decoded = ByteArrayOutputStream()

private val bitOutputStream = BitOutputStream(decoded, 1)

override fun writeDecoded() {
val symbolsSize = entropyData.data.copyOfRange(0, 4).toInt()
val encodedSymbols = entropyData.data.inputStream(4, symbolsSize)
val coefData = entropyData.data.inputStream(4 + symbolsSize, entropyData.data.size - 4 - symbolsSize)
var currentStreamPos = 0
val componentSymbolsData = jpegMeta.components.associate {
val componentId = it.frameInfo.componentId
val dcSize = entropyData.data.copyOfRange(currentStreamPos, currentStreamPos + 4).toInt()
currentStreamPos += 4
val dcSymbolsDataStream = entropyData.data.inputStream(currentStreamPos, dcSize)
val dcSymbolsData = A0Compressor.decode(dcSymbolsDataStream)
currentStreamPos += dcSize

val acSize = entropyData.data.copyOfRange(currentStreamPos, currentStreamPos + 4).toInt()
currentStreamPos += 4
val acSymbolsDataStream = entropyData.data.inputStream(currentStreamPos, acSize)
val acSymbolsData = A0Compressor.decode(acSymbolsDataStream)
currentStreamPos += acSize

componentId to (dcSymbolsData.inputStream() to acSymbolsData.inputStream())
}
val coefData = entropyData.data
.inputStream(currentStreamPos, entropyData.data.size - currentStreamPos)
val coefDataBitInputStream = BitInputStream(coefData)

val decodedSymbols = A0Compressor.decode(encodedSymbols)
decodedSymbols.forEach { symbol ->
val symbolInt = symbol.toInt() and 0xFF
val coefBitsSize = symbolInt and 15
val symbolBits = symbolInt.asBitsString(8).asBits()
(1..jpegMeta.mcuHeight).forEach { hMcu ->
(1..jpegMeta.mcuWidth).forEach { vMcu ->
jpegMeta.components.forEach { component ->
val componentId = component.frameInfo.componentId
val componentSymbolData = componentSymbolsData.getValue(componentId)
(1..component.frameInfo.verticalScaling).forEach { vScale ->
(1..component.frameInfo.horizontalScaling).forEach { hScale ->
var coef = 0
while (coef < 64) {
val coefByteArray = if (coef == 0) {
componentSymbolData.first
} else componentSymbolData.second
val symbol = coefByteArray.read()
val zerosSize = symbol shr 4
val coefBitsSize = symbol and 15

symbolBits.forEach { bitOutputStream.write(it) }
(1..coefBitsSize).forEach { bitOutputStream.write(coefDataBitInputStream.read()) }
val symbolBits = symbol.asBitsString(8).asBits()
symbolBits.forEach { bitOutputStream.write(it) }

if (coef != 0 && symbol == 0) {
coef = 64
break
}

coef += zerosSize + 1
repeat(coefBitsSize) { bitOutputStream.write(coefDataBitInputStream.read()) }
}
}
}
}
}
}

close()
}

Expand Down

0 comments on commit 685ae71

Please sign in to comment.