cpdf-source/cpdfpng.ml

75 lines
2.5 KiB
OCaml
Raw Normal View History

2022-12-23 15:29:47 +01:00
(* Read a non-interlaced, non-transparent 24 bit PNG for inclusion in a PDF file *)
2022-12-23 16:24:59 +01:00
open Pdfutil
open Pdfio
2022-12-23 15:29:47 +01:00
type t =
{width : int;
height : int;
2022-12-23 16:24:59 +01:00
idat : bytes}
2022-12-23 15:29:47 +01:00
2022-12-23 16:24:59 +01:00
let string_of_tag t =
Printf.sprintf "%c%c%c%c"
(char_of_int (i32toi (Int32.shift_right t 24)))
(char_of_int (i32toi (Int32.logand 0x000000FFl (Int32.shift_right t 16))))
(char_of_int (i32toi (Int32.logand 0x000000FFl (Int32.shift_right t 8))))
(char_of_int (i32toi (Int32.logand 0x000000FFl t)))
2022-12-23 17:19:40 +01:00
let read_unsigned_4byte i =
let a = i32ofi (i.input_byte ()) in
let b = i32ofi (i.input_byte ()) in
let c = i32ofi (i.input_byte ()) in
let d = i32ofi (i.input_byte ()) in
lor32 (lor32 (lsl32 a 24) (lsl32 b 16)) (lor32 (lsl32 c 8) d)
2022-12-23 16:24:59 +01:00
2022-12-23 17:19:40 +01:00
let read_data l i =
let l = i32toi l in
let b = mkbytes l in
setinit i b 0 l;
b
2022-12-23 16:24:59 +01:00
let read_chunk i =
let chunklen = read_unsigned_4byte i in
let chunktype = read_unsigned_4byte i in
let chunkdata = read_data chunklen i in
let _ (* crc *) = read_unsigned_4byte i in
(string_of_tag chunktype, chunkdata)
2022-12-23 20:27:03 +01:00
let concat_bytes ss =
2023-03-12 17:29:32 +01:00
let total_length = sum (map bytes_size ss) in
2022-12-23 20:27:03 +01:00
let s' = mkbytes total_length in
let p = ref 0 in
iter
(fun s ->
for x = 0 to bytes_size s - 1 do bset_unsafe s' !p (bget s x); incr p done)
ss;
s'
2022-12-23 15:29:47 +01:00
let read_png i =
2022-12-23 16:24:59 +01:00
try
i.seek_in 8;
let ihdr, ihdrdata = read_chunk i in
if ihdr <> "IHDR" then raise (Pdf.PDFError "read_png: first table not IHDR") else
2022-12-23 20:27:03 +01:00
let hdr = input_of_bytes ihdrdata in
let width = read_unsigned_4byte hdr in
let height = read_unsigned_4byte hdr in
let bitdepth = hdr.input_byte () in
if bitdepth <> 8 then failwith "read_png: bit depth not 8" else
let colortype = hdr.input_byte () in
if colortype <> 2 then failwith "read_png: only 24 bit non-alpha PNGs" else
let _ (*compressionmethod*) = hdr.input_byte () in
let _ (*filtermethod*) = hdr.input_byte () in
let interlacemethod = hdr.input_byte () in
if interlacemethod <> 0 then failwith "read_png: interlaced PDFs not supported" else
let idat = ref [] in
2022-12-23 16:24:59 +01:00
begin try
while true do
let chunkname, chunkdata = read_chunk i in
2022-12-23 20:27:03 +01:00
if chunkname = "IDAT" then idat := chunkdata::!idat
2022-12-23 16:24:59 +01:00
done
with
_ -> ()
end;
2022-12-23 20:27:03 +01:00
{width = i32toi width; height = i32toi height; idat = concat_bytes (rev !idat)}
2022-12-23 16:24:59 +01:00
with
e -> raise (Pdf.PDFError (Printf.sprintf "read_png: failed on %s" (Printexc.to_string e)))