dagronf / QRCode

A quick and beautiful macOS/iOS/tvOS/watchOS QR Code generator/detector library for SwiftUI, Swift and Objective-C.
MIT License
438 stars 57 forks source link

Enhancement suggestion: SVG images for examples #20

Closed keremerkan closed 1 year ago

keremerkan commented 1 year ago

I am adding this as an enhancement suggestion.

The best way to display different eye and pixel options to the user is, to present the supplied images (data*), (eye) and (pupil_) as an example. As Xcode can add svg images to asset catalogs now, if these images were in svg format, the examples would be pixel perfect on every screen.

Another option would be to have an "example" variable or function for the shape objects, which would output a UIImage. This way, we can present the options to the user in a menu or in buttons and set the images of the options programmatically like:

button.image = QRCode.EyeShape.RoundedOuter.exampleImage()

Hope this makes sense.

dagronf commented 1 year ago

There is a way of doing this already available -- unfortunately not with SVG output tho but CGImage is

If you look at the documentation project (in the Demo folder) I do this to generate the images for the README.md file

See here

It's not overly elegant (and only supports cgimage elements), but you can do some minor configuration and sizing so that might get you part of the way through.

Adding an SVG version of this would require some time.

eg.

for name in QRCodePupilShapeFactory.shared.availableGeneratorNames.sorted() {
   guard
      let gen = QRCodePupilShapeFactory.shared.named(name),
      let pupilImage = QRCodePupilShapeFactory.shared.image(
         pupilGenerator: gen,
         dimension: imageSize * 2,
         foregroundColor: .black,
         backgroundColor: CGColor(gray: 0.9, alpha: 1))
   else {
      fatalError()
   }

   let nsImage = NSImage(cgImage: pupilImage, size: CGSize(width: imageSize, height: imageSize))
   if let tiff = nsImage.tiffRepresentation, let tiffData = NSBitmapImageRep(data: tiff) {
      let pngData = tiffData.representation(using: .png, properties: [:])
      try! pngData?.write(to: tempURL.appendingPathComponent("pupil_" + name).appendingPathExtension("png"))
   }
}
keremerkan commented 1 year ago

Well, that is good enough for me. I’ll take a look, thanks! :)

dagronf commented 1 year ago

Ah I forgot that I added this in 14.0.0, each of the factories now has a convenience function for generating an array of sample images/generator names that the generator produces.

// Generate sample images for each type
let samples = QRCodePixelShapeFactory.shared.generateSampleImages(
   dimension: 200, 
   foregroundColor: .black, 
   backgroundColor: .white
)

This basically wraps all of the code that I mentioned above :-)

keremerkan commented 1 year ago

Just tested this. Working great. Looks like I'll be able to programmatically display the images now. I'd like to suggest another addition to the

@objc func image(
        pixelGenerator: QRCodePixelShapeGenerator,
        dimension: CGFloat,
        foregroundColor: CGColor,
        backgroundColor: CGColor? = nil,
        isOn: Bool = true
    ) -> CGImage?

function. I see that you are assigning a custom 7x7 boolMatrix when creating the images. Could you add another variable so that we can pass our own custom bool matrix? This way we can pass a 1x1 or 2x2 bool matrix which will be more suitable for small images in a UITableView. Also a dpi option would be great here. Even better, a scale option which can pass UIScreen.main.scale instead of dpi, so that the images are always pixel perfect for the screen they are viewed on.

The same applies to the uiImage function of QRCode(). Instead of

let image = doc.uiImage(CGSize(width: imageSide, height: imageSide), dpi: UIScreen.main.scale*72.0)

we could use something like

let image = doc.uiImage(CGSize(width: imageSide, height: imageSide), scale: UIScreen.main.scale)

Many thanks!

dagronf commented 1 year ago

14.0.4 has the ability to set a custom bool matrix when generating the sample pixel image.

dagronf commented 1 year ago

I think the QRCode.Document already has a scale option?

@objc func uiImage(dimension: Int, scale: CGFloat = 1) -> UIImage? {
dagronf commented 1 year ago

Currently, the sample image generators only generate CGImage, which has no concept of DPI/scale

If you generate the CGImage at double size, then just set the dpi/scale when you're creating the NSImage/UIImage this should solve your issue.

keremerkan commented 1 year ago

I think the QRCode.Document already has a scale option?

@objc func uiImage(dimension: Int, scale: CGFloat = 1) -> UIImage? {

You are right, I have completely missed that. Sorry about it.

dagronf commented 1 year ago

You are right, I have completely missed that. Sorry about it.

No problems!