Skip to content

Commit b4b326a

Browse files
author
Olivier Bonnaure
committed
feat: auto calculate image width & heigth
1 parent 4ca7035 commit b4b326a

File tree

2 files changed

+124
-71
lines changed

2 files changed

+124
-71
lines changed

.lua/pdfgenerator.lua

Lines changed: 123 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,75 @@ local function getNewObjNum()
1919
return num
2020
end
2121

22+
23+
-- Create new PDF document
24+
function PDFGenerator.new(options)
25+
objCounter = 1
26+
local self = {
27+
objects = {},
28+
current_page = 0,
29+
current_page_obj = nil,
30+
page_list = {}, -- Array to store page objects
31+
pages_obj = nil, -- Object number for pages tree
32+
images = {},
33+
contents = {},
34+
catalog = nil,
35+
info = nil,
36+
root = nil,
37+
page_width = 595,
38+
page_height = 842,
39+
header_height = 0,
40+
margin_x = { 50, 50 },
41+
margin_y = { 50, 80 },
42+
current_x = 0,
43+
current_y = 0,
44+
resources = {},
45+
font_metrics = {},
46+
fonts = {},
47+
rgb_colors = {},
48+
last_font = { fontFamily = "helvetica", fontWeight = "normal" },
49+
current_table = {
50+
current_row = {
51+
height = nil,
52+
},
53+
padding_x = 5,
54+
padding_y = 5,
55+
header_columns = nil,
56+
data_columns = nil,
57+
header_options = nil,
58+
data_options = nil,
59+
},
60+
out_of_page = false,
61+
}
62+
63+
self = table.merge(self, options or {})
64+
65+
self.header = function(pageId) end
66+
self.footer = function(pageId)
67+
self.moveY(self, 5)
68+
self:addParagraph("Page %s of %s" % { pageId, #self.page_list }, { fontSize = 8, alignment = "right" })
69+
end
70+
71+
-- Initialize document
72+
self.info = getNewObjNum()
73+
self.root = getNewObjNum()
74+
self.pages_obj = getNewObjNum()
75+
self.basic_font_obj = getNewObjNum()
76+
self.basic_bold_font_obj = getNewObjNum()
77+
78+
-- Initialize resources
79+
self.resources = { fonts = {}, images = {} }
80+
81+
-- Add required PDF objects
82+
self.objects[self.info] = string.format(
83+
"%d 0 obj\n<< /Producer (Lua PDF Generator 1.0) /CreationDate (D:%s) >>\nendobj\n",
84+
self.info,
85+
os.date("!%Y%m%d%H%M%S")
86+
)
87+
88+
return setmetatable(self, { __index = PDFGenerator })
89+
end
90+
2291
function PDFGenerator:getHashValues(hash)
2392
local values = {}
2493
for _, value in pairs(hash) do
@@ -96,6 +165,11 @@ function PDFGenerator:addBasicFont()
96165
"%d 0 obj\n<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding >>\nendobj\n",
97166
self.basic_bold_font_obj
98167
)
168+
169+
self.custom_fonts = {
170+
['helvetica-normal'] = self.basic_bold_font_obj,
171+
['helvetica-bold'] = self.basic_bold_font_obj
172+
}
99173
end
100174

101175
-- Add custom font (TrueType)
@@ -296,6 +370,7 @@ function PDFGenerator:getTextWidth(text, fontSize, fontWeight)
296370
self.font_metrics = self.font_metrics or {}
297371
local fontMetrics = self.font_metrics[self.last_font.fontFamily .. "-" .. fontWeight]
298372

373+
if(fontMetrics == nil) then return end
299374
local width = 0
300375
for i = 1, #text do
301376
local charCode = string.byte(text, i)
@@ -1050,8 +1125,53 @@ function PDFGenerator:drawStar(outerRadius, branches, borderWidth, borderStyle,
10501125
return self
10511126
end
10521127

1128+
1129+
local function get_jpeg_dimensions(data)
1130+
-- Check for JPEG SOI marker (0xFFD8)
1131+
if data:byte(1) ~= 0xFF or data:byte(2) ~= 0xD8 then
1132+
return nil, nil, "Not a valid JPEG file"
1133+
end
1134+
1135+
-- Start parsing from byte 3
1136+
local pos = 3
1137+
local length = #data
1138+
1139+
-- Loop through the JPEG markers
1140+
while pos < length do
1141+
-- Look for marker (starts with 0xFF)
1142+
if data:byte(pos) ~= 0xFF then
1143+
return nil, nil, "Invalid JPEG marker"
1144+
end
1145+
1146+
-- Get marker type
1147+
local marker = data:byte(pos + 1)
1148+
pos = pos + 2
1149+
1150+
-- Check for SOF markers (0xC0 to 0xCF, excluding 0xC4, 0xC8, 0xCC)
1151+
if marker >= 0xC0 and marker <= 0xCF and marker ~= 0xC4 and marker ~= 0xC8 and marker ~= 0xCC then
1152+
-- Skip 2 bytes (length of block) and 1 byte (sample precision)
1153+
pos = pos + 3
1154+
-- Read height (2 bytes)
1155+
local height = data:byte(pos) * 256 + data:byte(pos + 1)
1156+
-- Read width (2 bytes)
1157+
local width = data:byte(pos + 2) * 256 + data:byte(pos + 3)
1158+
return width, height
1159+
else
1160+
-- Read the length of the segment (2 bytes)
1161+
if pos + 1 > length then
1162+
return nil, nil, "Unexpected end of file"
1163+
end
1164+
local segment_length = data:byte(pos) * 256 + data:byte(pos + 1)
1165+
-- Skip the segment
1166+
pos = pos + segment_length
1167+
end
1168+
end
1169+
1170+
return nil, nil, "No SOF marker found"
1171+
end
1172+
10531173
-- Add image to PDF (imgData should be binary data)
1054-
function PDFGenerator:addImage(imgData, width, height, format)
1174+
function PDFGenerator:addImage(imgData, format)
10551175
format = format:lower()
10561176
if format ~= "jpeg" then
10571177
error("Unsupported image format: " .. format)
@@ -1061,6 +1181,8 @@ function PDFGenerator:addImage(imgData, width, height, format)
10611181
local imageObj = getNewObjNum()
10621182
local imgName = string.format("Im%d", #self.resources.images + 1)
10631183

1184+
local width, height, err = get_jpeg_dimensions(imgData)
1185+
10641186
-- Store image information
10651187
self.resources.images[imgName] = {
10661188
obj = imageObj,
@@ -1851,74 +1973,6 @@ function PDFGenerator:BarChart(barData, labels)
18511973
end
18521974
-- /ChartBar
18531975

1854-
-- Create new PDF document
1855-
function PDFGenerator.new(options)
1856-
objCounter = 1
1857-
local self = {
1858-
objects = {},
1859-
current_page = 0,
1860-
current_page_obj = nil,
1861-
page_list = {}, -- Array to store page objects
1862-
pages_obj = nil, -- Object number for pages tree
1863-
images = {},
1864-
contents = {},
1865-
catalog = nil,
1866-
info = nil,
1867-
root = nil,
1868-
page_width = 595,
1869-
page_height = 842,
1870-
header_height = 0,
1871-
margin_x = { 50, 50 },
1872-
margin_y = { 50, 80 },
1873-
current_x = 0,
1874-
current_y = 0,
1875-
resources = {},
1876-
font_metrics = {},
1877-
fonts = {},
1878-
rgb_colors = {},
1879-
last_font = { fontFamily = "Helvetica", fontWeight = "normal" },
1880-
current_table = {
1881-
current_row = {
1882-
height = nil,
1883-
},
1884-
padding_x = 5,
1885-
padding_y = 5,
1886-
header_columns = nil,
1887-
data_columns = nil,
1888-
header_options = nil,
1889-
data_options = nil,
1890-
},
1891-
out_of_page = false,
1892-
}
1893-
1894-
self = table.merge(self, options or {})
1895-
1896-
self.header = function(pageId) end
1897-
self.footer = function(pageId)
1898-
self.moveY(self, 5)
1899-
self:addParagraph("Page %s of %s" % { pageId, #self.page_list }, { fontSize = 8, alignment = "right" })
1900-
end
1901-
1902-
-- Initialize document
1903-
self.info = getNewObjNum()
1904-
self.root = getNewObjNum()
1905-
self.pages_obj = getNewObjNum()
1906-
self.basic_font_obj = getNewObjNum()
1907-
self.basic_bold_font_obj = getNewObjNum()
1908-
1909-
-- Initialize resources
1910-
self.resources = { fonts = {}, images = {} }
1911-
1912-
-- Add required PDF objects
1913-
self.objects[self.info] = string.format(
1914-
"%d 0 obj\n<< /Producer (Lua PDF Generator 1.0) /CreationDate (D:%s) >>\nendobj\n",
1915-
self.info,
1916-
os.date("!%Y%m%d%H%M%S")
1917-
)
1918-
1919-
return setmetatable(self, { __index = PDFGenerator })
1920-
end
1921-
19221976
-- Generate PDF and return as string
19231977
function PDFGenerator:generate()
19241978
local output = {}

app/controllers/welcome_controller.lua

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ local app = {
2626
pdf:addCustomFont("fonts/TitilliumWeb-Regular.ttf", "titillium", "normal")
2727
pdf:addCustomFont("fonts/TitilliumWeb-Bold.ttf", "titillium", "bold")
2828

29-
30-
local imgName = pdf:addImage(LoadAsset("greece.jpg"), 1600, 492, "jpeg")
29+
local imgName = pdf:addImage(LoadAsset("greece.jpg"), "jpeg")
3130
pdf:drawImage(imgName)
3231

3332
pdf:moveY(10)

0 commit comments

Comments
 (0)