Skip to content

Commit

Permalink
Merge pull request #48 from RexWzh/rex-dev
Browse files Browse the repository at this point in the history
track info of format and version
  • Loading branch information
RexWzh authored Dec 3, 2022
2 parents 1b9b802 + d902dc3 commit 826f23b
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 61 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ Manifest.toml
*.gif
*.png
*.jpg
*.jpeg
*.svg
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "QRCoders"
uuid = "f42e9828-16f3-11ed-2883-9126170b272d"
authors = ["Jérémie Gillet <[email protected]> and contributors"]
version = "1.4.1"
version = "1.4.2"

[deps]
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
Expand Down
2 changes: 1 addition & 1 deletion docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ QRCode
```

## Encoding modes
There are five several encoding mode currently supported.
Currently, there are five supported encoding modes.

```@docs
Mode
Expand Down
4 changes: 2 additions & 2 deletions src/QRCoders.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export
# QR code style
unicodeplot, unicodeplotbychar,
imageinqrcode, getfreeinfo, getimagescore,
validaligment, fitimgwidth

validalignment, fitimgwidth, getversioninds,
getformatinds
# Data types in QRCoders
include("types.jl")

Expand Down
41 changes: 21 additions & 20 deletions src/export.jl
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,20 @@ function _resize(matrix::AbstractMatrix, widthpixels::Int = 160)
kron(matrix, trues(scale, scale))
end

"""
Check wheter the path is valid.
"""
function _checkpath(path::AbstractString, supportexts::AbstractVector{<:AbstractString})
if !endswith(path, r"\.\w+")
path *= ".png"
else
ext = last(split(path, '.'))
ext supportexts || throw(EncodeError(
"Unsupported file extension: $ext\n Supported extensions: $supportexts"))
end
return path
end

"""
exportbitmat(matrix::BitMatrix, path::AbstractString; pixels::Int = 160)
Expand All @@ -90,16 +104,12 @@ function exportbitmat( matrix::BitMatrix
; targetsize::Int=0
, pixels::Int=160)
# check whether the image format is supported
supportexts = ["png", "jpg", "gif"]
if !endswith(path, r"\.\w+")
path *= ".png"
else
ext = last(split(path, '.'))
ext supportexts || throw(EncodeError(
"Unsupported file extension: $ext\n Supported extensions: $supportexts"))
end
supportexts = ["png", "jpg", "jpeg", "gif"]
path = _checkpath(path, supportexts)

# resize the matrix
if targetsize > 0 # original keyword -- will be removed in the future
Base.depwarn("keyword `targetsize` will be removed in the future, use `pixels` instead", :exportbitmat)
n = size(matrix, 1)
pixels = ceil(Int, 72 * targetsize / 2.45 / n) * n
end
Expand Down Expand Up @@ -216,25 +226,16 @@ function exportqrcode( codes::AbstractVector{QRCode}
matwidth = qrwidth(first(codes))
all(==(matwidth), qrwidth.(codes)) || throw(EncodeError("The codes should have the same size"))
# check whether the image format is supported
if !endswith(path, r"\.\w+")
path *= ".gif"
else
ext = last(split(path, '.'))
ext == "gif" || throw(EncodeError(
"$ext\n is not a valid format for animated images"))
end
path = _checkpath(path, ["gif"])

# generate frames
if targetsize > 0 # original keyword -- will be removed in the future
Base.depwarn("keyword `targetsize` will be removed in the future, use `pixels` instead", :exportbitmat)
pixels = ceil(Int, 72 * targetsize / 2.45 / matwidth) * matwidth
else
pixels = ceil(Int, pixels / matwidth) * matwidth
end
code = Array{Bool}(undef, pixels, pixels, length(codes))
for (i, c) in enumerate(codes)
code[:,:,i] = _resize(qrcode(c), pixels)
end
save(path, .! code, fps=fps)
save(path, .! cat([_resize(qrcode(code), pixels) for code in codes]..., dims = 3), fps=fps)
end

"""
Expand Down
46 changes: 45 additions & 1 deletion src/styles/locate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,48 @@ function getsegments(v::Int, eclevel::ErrCorrLevel)
end
ind != 0 && throw(ArgumentError("getsegments: not all data is recorded"))
return segments, ecsegments
end
end

"""
validalignment(v::Int, imgx::Int, imgy::Int)
Return the position of alignment pattern that has intersection
with the image.
"""
function validalignment(v::Int, imgI::AbstractSet)
# version 1 does not have alignment pattern
v == 1 && return Tuple{Int, Int}[]
# skip the alignment pattern that has intersection with the time pattern
aligns = filter(>(6), alignmentlocation[v]) .+ 1 # off set 1
# keep the alignment pattern that has intersection with the image
[CartesianIndex(x, y) for x in aligns for y in aligns if CartesianIndex(x, y) in imgI]
end

"""
getversioninds(v::Int)
Get indexes of the version information.
"""
function getversioninds(v::Int)
# version ≤ 6 does not have version information
v 6 && throw(ArgumentError("The version $v should be larger than 6."))
# get indexes of the version information
n = 17 + 4 * v
vcat([CartesianIndex(i, j) for j in 1:6 for i in n - 10:n-8], # left bottom
[CartesianIndex(i, j) for i in 1:6 for j in n - 10:n-8]) # right top
end
getversioninds(code::QRCode) = getversioninds(code.version)

"""
getformatinds(v::Int)
Get indexes of the format information.
"""
function getformatinds(v::Int)
n = 17 + 4 * v
return vcat([CartesianIndex(9, i) for i in [1:6;8]],
[CartesianIndex(i, 9) for i in [9,8,6:-1:1...]],
[CartesianIndex(i, 9) for i in n:-1:n-6],
[CartesianIndex(9, i) for i in n-7:n])
end
getformatinds(code::QRCode) = getformatinds(code.version)
30 changes: 8 additions & 22 deletions src/styles/plotimage.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
; rate::Real=1
, singlemask::Bool=true
, leftop::Tuple{Int, Int}=(-1, -1)
, fillaligment::Bool=false
, fillalignment::Bool=false
) where T <: Union{Bool, Nothing}
Plot image inside QR code.
Expand All @@ -23,16 +23,16 @@ function imageinqrcode( code::QRCode
; rate::Real=1
, singlemask::Bool=true
, leftop::Tuple{Int, Int}=(-1, -1)
, fillaligment::Bool=false
, fillalignment::Bool=false
) where T <: Union{Bool, Nothing}
imageinqrcode!(copy(code), img; rate=rate, singlemask=singlemask, leftop=leftop, fillaligment=fillaligment)
imageinqrcode!(copy(code), img; rate=rate, singlemask=singlemask, leftop=leftop, fillalignment=fillalignment)
end
function imageinqrcode!( code::QRCode
, img::AbstractMatrix{T}
; rate::Real=1
, singlemask::Bool=true
, leftop::Tuple{Int,Int}=(-1, -1)
, fillaligment::Bool=false
, fillalignment::Bool=false
) where T <: Union{Bool, Nothing}
## 1. check input
border, code.border = code.border, 0 # set border to 0
Expand Down Expand Up @@ -66,6 +66,7 @@ function imageinqrcode!( code::QRCode

## 5. information of free blocks
npureblock, nfreeblock, nfreebyte = getfreeinfo(code)
# nfreebyte = 0 # set zero to skip the partial free block
npurebyte = (npureblock nb1 ? nc2 : nc1) - nfreebyte # message bytes in the partial free block

## 6. sort bytes by the intersection area with the image
Expand All @@ -85,6 +86,7 @@ function imageinqrcode!( code::QRCode
bestmat, bestpenalty = nothing, Inf
distance(mat) = @views sum(mat[imgI] == img)
for mask in masks
code.mask = mask
stdmat = qrcode(code)
_filldata!(stdmat, canvas, bitblockinds, byteblockinds, setimgI, sortbytes,
npureblock, nfreeblock, npurebyte, necwords, modify, mask, version)
Expand All @@ -94,9 +96,9 @@ function imageinqrcode!( code::QRCode
end
end
# 8. fill alignment patterns
if fillaligment
if fillalignment
rad = CartesianIndex(2, 2) # radius of alignment patterns
centers = validaligment(version, setimgI)
centers = validalignment(version, setimgI)
for c in centers
inds = filter((setimgI), Ref(c) .+ (-rad:rad))
bestmat[inds] = canvas[inds]
Expand Down Expand Up @@ -204,22 +206,6 @@ function sortindsample(scores::AbstractVector, msglen::Int)
end
end

"""
validaligment(v::Int, imgx::Int, imgy::Int)
Return the position of aligment pattern that has intersection
with the image.
"""
function validaligment(v::Int, imgI::AbstractSet)
# version 1 does not have aligment pattern
v == 1 && return Tuple{Int, Int}[]
qrlen = 17 + 4 * v
# skip the aligment pattern that has intersection with the time pattern
aligns = filter(>(6), alignmentlocation[v]) .+ 1 # off set 1
# keep the aligment pattern that has intersection with the image
[CartesianIndex(x, y) for x in aligns for y in aligns if CartesianIndex(x, y) in imgI]
end

"""
fitimgwidth(code::QRCode)
Expand Down
5 changes: 3 additions & 2 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ using ImageTransformations
using TestImages
using StatsBase
using QRDecoders.Syndrome: fillerasures!
using QRDecoders: qrdecode
using QRDecoders

using QRCoders:
# build
Expand All @@ -26,7 +26,8 @@ using QRCoders:
bitarray2int, int2bitarray, bits2bytes,
# style
unicodeplot, getindexes, getsegments, getecinfo,
gauss_elimination, fillblank, getimagescore
gauss_elimination, fillblank, getimagescore,
getversioninds, getformatinds

using QRCoders.Polynomial:
# operator for GF(256) integers
Expand Down
1 change: 1 addition & 0 deletions test/tst_construct.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ end
exportqrcode("Hello, world!", imgpath * "qrcode-helloworld.png")
exportqrcode("Hello, world!", imgpath * "qrcode-helloworld.gif")
exportqrcode("Hello, world!", imgpath * "qrcode-helloworld.jpg")
exportqrcode("Hello, world!", imgpath * "qrcode-helloworld.jpeg")
@test true
@test_throws EncodeError exportqrcode("Hello, world!", imgpath * "qrcode-helloworld.svg")

Expand Down
Loading

2 comments on commit 826f23b

@RexWzh
Copy link
Member Author

@RexWzh RexWzh commented on 826f23b Dec 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/73384

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v1.4.2 -m "<description of version>" 826f23b031a3da8fb0b9b9abd330f70394c03757
git push origin v1.4.2

Please sign in to comment.