Initial commit
This commit is contained in:
commit
6ac7f0e800
|
@ -0,0 +1,23 @@
|
|||
name: test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: erlef/setup-beam@v1
|
||||
with:
|
||||
otp-version: "26.0.2"
|
||||
gleam-version: "1.2.0"
|
||||
rebar3-version: "3"
|
||||
# elixir-version: "1.15.4"
|
||||
- run: gleam deps download
|
||||
- run: gleam test
|
||||
- run: gleam format --check src test
|
|
@ -0,0 +1,4 @@
|
|||
*.beam
|
||||
*.ez
|
||||
/build
|
||||
erl_crash.dump
|
|
@ -0,0 +1,36 @@
|
|||
# pngleam
|
||||
|
||||
[![Package Version](https://img.shields.io/hexpm/v/pngleam)](https://hex.pm/packages/pngleam)
|
||||
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/pngleam/)
|
||||
|
||||
```sh
|
||||
gleam add pngleam
|
||||
```
|
||||
```gleam
|
||||
import pngleam
|
||||
|
||||
pub fn main() {
|
||||
[
|
||||
<<0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF>>,
|
||||
<<0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF>>,
|
||||
<<0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x80, 0x80, 0x80>>,
|
||||
]
|
||||
|> gleam_png.from_packed(
|
||||
width: 3,
|
||||
height: 3,
|
||||
color_info: pngleam.rgb_8bit,
|
||||
compression_level: pngleam.default_compression,
|
||||
)
|
||||
|> simplifile.write_bits("img.png", _)
|
||||
}
|
||||
```
|
||||
|
||||
Further documentation can be found at <https://hexdocs.pm/pngleam>.
|
||||
|
||||
## Development
|
||||
|
||||
```sh
|
||||
gleam run # Run the project
|
||||
gleam test # Run the tests
|
||||
gleam shell # Run an Erlang shell
|
||||
```
|
|
@ -0,0 +1,16 @@
|
|||
name = "pngleam"
|
||||
version = "1.0.0"
|
||||
|
||||
description = "PNG image library for Gleam"
|
||||
licences = ["AGPL-3.0-only"]
|
||||
repository = { type = "github", user = "LilyRose2798", repo = "pngleam" }
|
||||
links = [
|
||||
{ title = "7Circles Git", href = "https://git.7cs.dev/lily/pngleam" },
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
gleam_stdlib = ">= 0.34.0 and < 2.0.0"
|
||||
gzlib = ">= 1.0.0 and < 2.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
gleeunit = ">= 1.0.0 and < 2.0.0"
|
|
@ -0,0 +1,13 @@
|
|||
# This file was generated by Gleam
|
||||
# You typically do not need to edit this file
|
||||
|
||||
packages = [
|
||||
{ name = "gleam_stdlib", version = "0.38.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "663CF11861179AF415A625307447775C09404E752FF99A24E2057C835319F1BE" },
|
||||
{ name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" },
|
||||
{ name = "gzlib", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gzlib", source = "hex", outer_checksum = "EC6A3FAF20B8A707B5A550E1B622785685759991C9D13CFC4AAE8FE34FDDF3B8" },
|
||||
]
|
||||
|
||||
[requirements]
|
||||
gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" }
|
||||
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
|
||||
gzlib = { version = ">= 1.0.0 and < 2.0.0" }
|
|
@ -0,0 +1,111 @@
|
|||
import gleam/bit_array
|
||||
import gleam/list
|
||||
import gzlib
|
||||
|
||||
pub const no_compression = gzlib.no_compression
|
||||
|
||||
pub const min_compression = gzlib.min_compression
|
||||
|
||||
pub const max_compression = gzlib.max_compression
|
||||
|
||||
pub const default_compression = gzlib.default_compression
|
||||
|
||||
pub const compression_level = gzlib.compression_level
|
||||
|
||||
pub type ColorType {
|
||||
Greyscale
|
||||
Color
|
||||
Indexed
|
||||
GreyscaleWithAlpha
|
||||
ColorWithAlpha
|
||||
}
|
||||
|
||||
fn color_type_to_int(color_type: ColorType) -> Int {
|
||||
case color_type {
|
||||
Greyscale -> 0b000
|
||||
Color -> 0b010
|
||||
Indexed -> 0b011
|
||||
GreyscaleWithAlpha -> 0b100
|
||||
ColorWithAlpha -> 0b110
|
||||
}
|
||||
}
|
||||
|
||||
pub opaque type ColorInfo {
|
||||
ColorInfo(color_type: ColorType, bit_depth: Int)
|
||||
}
|
||||
|
||||
pub const greyscale_8bit = ColorInfo(Greyscale, 8)
|
||||
|
||||
pub const rgb_8bit = ColorInfo(Color, 8)
|
||||
|
||||
pub const rgb_16bit = ColorInfo(Color, 16)
|
||||
|
||||
pub const rgba_8bit = ColorInfo(ColorWithAlpha, 8)
|
||||
|
||||
pub const rgba_16bit = ColorInfo(ColorWithAlpha, 16)
|
||||
|
||||
pub fn color_info(
|
||||
color_type color_type: ColorType,
|
||||
bit_depth bit_depth: Int,
|
||||
) -> Result(ColorInfo, Nil) {
|
||||
let color_info = Ok(ColorInfo(color_type, bit_depth))
|
||||
case color_type, bit_depth {
|
||||
Greyscale, 1 | Greyscale, 2 | Greyscale, 4 | Greyscale, 8 | Greyscale, 16 ->
|
||||
color_info
|
||||
Color, 8 | Color, 16 -> color_info
|
||||
Indexed, 1 | Indexed, 2 | Indexed, 4 | Indexed, 8 -> color_info
|
||||
GreyscaleWithAlpha, 8 | GreyscaleWithAlpha, 16 -> color_info
|
||||
ColorWithAlpha, 8 | ColorWithAlpha, 16 -> color_info
|
||||
_, _ -> Error(Nil)
|
||||
}
|
||||
}
|
||||
|
||||
fn chunk_bit_array(data: BitArray) -> List(BitArray) {
|
||||
do_chunk_bit_array(data, []) |> list.reverse
|
||||
}
|
||||
|
||||
fn do_chunk_bit_array(data: BitArray, chunks: List(BitArray)) -> List(BitArray) {
|
||||
case data {
|
||||
<<chunk:bytes-size(8192), rest:bytes>> ->
|
||||
do_chunk_bit_array(rest, [chunk, ..chunks])
|
||||
chunk -> [chunk, ..chunks]
|
||||
}
|
||||
}
|
||||
|
||||
fn get_chunk(tag: String, data: BitArray) -> BitArray {
|
||||
let data_size = bit_array.byte_size(data)
|
||||
let tag_bits = <<tag:utf8>>
|
||||
let checksum = gzlib.continue_crc32(gzlib.crc32(tag_bits), data)
|
||||
<<data_size:size(32), tag_bits:bits, data:bits, checksum:size(32)>>
|
||||
}
|
||||
|
||||
const signature = <<137, "PNG":utf8, "\r\n":utf8, 26, "\n":utf8>>
|
||||
|
||||
pub fn from_packed(
|
||||
row_data row_data: List(BitArray),
|
||||
width width: Int,
|
||||
height height: Int,
|
||||
color_info color_info: ColorInfo,
|
||||
compression_level compression_level: gzlib.CompressionLevel,
|
||||
) -> BitArray {
|
||||
let ihdr =
|
||||
get_chunk("IHDR", <<
|
||||
width:size(32),
|
||||
height:size(32),
|
||||
color_info.bit_depth:size(8),
|
||||
color_type_to_int(color_info.color_type):size(8),
|
||||
0:size(8),
|
||||
0:size(8),
|
||||
0:size(8),
|
||||
>>)
|
||||
let idats =
|
||||
row_data
|
||||
|> list.map(fn(d) { <<0, d:bits>> })
|
||||
|> bit_array.concat
|
||||
|> gzlib.compress_with_level(compression_level)
|
||||
|> chunk_bit_array
|
||||
|> list.map(get_chunk("IDAT", _))
|
||||
|> bit_array.concat
|
||||
let iend = get_chunk("IEND", <<>>)
|
||||
<<signature:bits, ihdr:bits, idats:bits, iend:bits>>
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import gleeunit
|
||||
|
||||
pub fn main() {
|
||||
gleeunit.main()
|
||||
}
|
Loading…
Reference in New Issue