Closed objecttothis closed 1 month ago
I suppose another (maybe better) option could be to add another function within BarcodeGeneratorSVG
called getFixedWidthBarcode()
that has the same function signature as 2 but just calculates the needed widthFactor and calls getBarcode with that calculated value.
If you're taking contributions, I could probably submit a PR, but would only want to do that with input as to which option you'd want me to implement.
It would add some complexity to support both ways, and not all generators support a float width so that would make it more complex to explain in the docs.
It is also not really needed, because you can always display the SVG as 250px wide, without the need for the SVG sizing inside the document to add up to 250px.
Maybe for a next big release it will become possible to do the barcode encoding separate from the image encoding, that way you could probably easily do what you suggest here without any extra methods. But that is not something for the coming months.
It would add some complexity to support both ways, and not all generators support a float width so that would make it more complex to explain in the docs.
What I'm suggesting would only be for generators that support floats.
It is also not really needed, because you can always display the SVG as 250px wide, without the need for the SVG sizing inside the document to add up to 250px.
That's what I thought since SVG is vector, I thought it should stretch. I tried wrapping it in a <div style="width:250px, height:50px;">
but that had no effect on the SVG. I think that is because the generator is generating code with width and height attributes, so it doesn't stretch.
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="202" height="50" viewBox="0 0 202 50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<desc>600180220171</desc>
<g id="bars" fill="black" stroke="none">
...
</g>
</svg>
You can see from the code that it's specifying the width
and the viewbox. Just to see if it would work, I tried injecting preserveAspectRatio="none"
as an attribute in the SVG but that had no effect on the barcode for me. I'm open to the idea that I'm doing it wrong, but I don't think I am.
Maybe for a next big release it will become possible to do the barcode encoding separate from the image encoding, that way you could probably easily do what you suggest here without any extra methods. But that is not something for the coming months.
That's what I thought since SVG is vector, I thought it should stretch. I tried wrapping it in a
but that had no effect on the SVG. I think that is because the generator is generating code with width and height attributes, so it doesn't stretch.That is because you need to target the SVG, not the div around it. See here an example how you can size the SVG perfectly with CSS. The first example is only targeting the div, the second example is setting the SVG width to 100%, making it match the outer div.
That's what I thought since SVG is vector, I thought it should stretch. I tried wrapping it in a but that had no effect on the SVG. I think that is because the generator is generating code with width and height attributes, so it doesn't stretch.
That is because you need to target the SVG, not the div around it. See here an example how you can size the SVG perfectly with CSS. The first example is only targeting the div, the second example is setting the SVG width to 100%, making it match the outer div.
@casperbakker I appreciate you going the extra mile to show me targeting the SVG, but even this code isn't correctly doing it. If you look at your codepen you'll see that .barcode2
is scaling by retaining the aspect ratio and this is because the generated barcode does not have preserveAspectRatio='none'
in the svg, so it won't break the aspect ratio to scale properly. Take this code for example:
CSS
.barcode {
width: 250px;
height: 50px;
border: 1px solid red;
}
.barcode svg {
width: 100%;
height: 100%;
}
HTML
<div class='barcode'><?xml version="1.0" standalone="no" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="180" height="30" viewBox="0 0 180 50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<desc>0877842604</desc>
<g id="bars" fill="black" stroke="none">
<rect x="0" y="0" width="4" height="50" />
<rect x="6" y="0" width="2" height="50" />
<rect x="12" y="0" width="6" height="50" />
<rect x="22" y="0" width="2" height="50" />
<rect x="30" y="0" width="4" height="50" />
<rect x="38" y="0" width="2" height="50" />
<rect x="44" y="0" width="8" height="50" />
<rect x="54" y="0" width="6" height="50" />
<rect x="62" y="0" width="2" height="50" />
<rect x="66" y="0" width="2" height="50" />
<rect x="72" y="0" width="8" height="50" />
<rect x="82" y="0" width="2" height="50" />
<rect x="88" y="0" width="6" height="50" />
<rect x="98" y="0" width="2" height="50" />
<rect x="104" y="0" width="4" height="50" />
<rect x="110" y="0" width="2" height="50" />
<rect x="116" y="0" width="2" height="50" />
<rect x="124" y="0" width="4" height="50" />
<rect x="132" y="0" width="6" height="50" />
<rect x="142" y="0" width="2" height="50" />
<rect x="146" y="0" width="4" height="50" />
<rect x="154" y="0" width="4" height="50" />
<rect x="164" y="0" width="6" height="50" />
<rect x="172" y="0" width="2" height="50" />
<rect x="176" y="0" width="4" height="50" />
</g>
</svg>
</div>
You'll notice that it doesn't stretch the width of the barcode. This is because your code is not generating SVG tags with the preserveAspectRatio="none"
attribute. Adding that as <svg preserveAspectRatio="none" width="180" height="30" viewBox="0 0 180 50" version="1.1" xmlns="http://www.w3.org/2000/svg">
causes the barcode to stretch properly.
So even if you don't add the ability to programmatically set the width in px, please consider adding preserveAspectRatio="none"
as an attribute in the generated SVG so that users can target the svg and stretch it to their liking.
Also, when I played around with it, having preserveAspectRatio="none"
appears that it wouldn't likely be a breaking change since not targeting the SVG doesn't distort the SVG even with attribute there. That said, if you wanted to make sure it didn't break existing code you could just add it as an optional parameter . bool $preserveAspectRatio = true)
and only add the preserveAspectRatio="none"
attribute if the value is false
.
@casperbakker if it's a time thing, I'd be happy to submit a PR for adding the attribute with or without the optional parameter in the barcodeGeneratorSVG() function.
@objecttothis Thanks for the example with a bigger container. Weird thing is that if you use a smaller container then the image, it works. And that is how I have always used it:
I don't like to add too many options that are only for very specific use cases. I don't think that preserveAspectRatio deserves it's own setting.
I am in the process of building version 3, where SVG's default method is to give it the desired width and height. If I understand you right, that is what will fix your use case right?
I don't want to add preserveAspectRatio right now, because I am looking into how to support text below the barcode. Maybe that option will interfere with it, but I will keep this in mind for v3. Would be nice if you can scale the image bigger and smaller.
@objecttothis Thanks for the example with a bigger container. Weird thing is that if you use a smaller container then the image, it works. And that is how I have always used it:
Yeah, I'm not sure what's going on there either.
I don't like to add too many options that are only for very specific use cases. I don't think that preserveAspectRatio deserves it's own setting.
I understand about not liking to add too many options, however I respectfully disagree that the desire for fixed width is a specific use case if you mean rare that someone would want that. After all, you're already providing a fixed height option.
I am in the process of building version 3, where SVG's default method is to give it the desired width and height. If I understand you right, that is what will fix your use case right?
Yes, this would fix our use case as it is exactly what we need.
I don't want to add preserveAspectRatio right now, because I am looking into how to support text below the barcode. Maybe that option will interfere with it, but I will keep this in mind for v3. Would be nice if you can scale the image bigger and smaller.
Understood. Last thing anyone needs are breaking changes to their code. We generate our text below the barcode separately and would probably keep it that way even if it were an option since we already know what that text is when feeding it to php-barcode-generator. I suspect that since preserveAspectRatio is an SVG tag attribute that if the text were generated as part of the SVG, it would distort the text. If the text is generated outside of the SVG then preserveAspectRatio likely would have no effect.
If you need anyone to test for you, I have a vested interest in helping, so let me know.
If you need anyone to test for you, I have a vested interest in helping, so let me know.
If you could see if the new setup in v3 is understandable, that would be really helpful. In that v3 branch I have updated the readme with the new setup. Can you create a SVG with a fixed width with the new SvgRenderer?
The more confident I am in the new setup, the sooner I can release it.
I did see the readme note the other day
## Upgrading to v3
There is no need to change anything when upgrading from v2 to v3. Above you find the new preferred way of using this library since v3. But the old style still works.
If you want to convert to the new style, here is an example:
php
// Old style
$generator = new Picqer\Barcode\BarcodeGeneratorSVG();
echo $generator->getBarcode('081231723897', $generator::TYPE_CODE_128);
// New style
$barcode = (new Picqer\Barcode\Types\TypeCode128())->getBarcode('081231723897');
$renderer = new Picqer\Barcode\Renderers\SvgRenderer();
echo $renderer->render($barcode);
The new style seems less readable to me, but I'm assuming that this is so that you can keep backward compatibility with the old style. I looked briefly at the code and if I understand correctly the way I would generate an SVG with width 250px and height 50px is
$barcode = (new Picqer\Barcode\Types\TypeCode128())->getBarcode('081231723897');
$renderer = new Picqer\Barcode\Renderers\SvgRenderer();
echo $renderer->render($barcode, 250, 50);
I usually use npm to install picqer but I assume for the sake of testing I need to move the contents of the V3 branch into my project in place of the existing code. Is that right?
The new style seems less readable to me, but I'm assuming that this is so that you can keep backward compatibility with the old style.
It is a bit more verbose, but the benefits are that we can make all renderers different so they can have their own options. Also you can create your own barcode types or renderers because they are not linked anymore.
Your example is correct.
I usually use npm to install picqer but I assume for the sake of testing I need to move the contents of the V3 branch into my project in place of the existing code. Is that right?
Do you mean installing via Composer? You can try something like (I am in mobile now): composer require picqer/php-barcode-generator@dev-v3
, or change the version in composer.json to 'dev-v3'.
The new style seems less readable to me, but I'm assuming that this is so that you can keep backward compatibility with the old style.
It is a bit more verbose, but the benefits are that we can make all renderers different so they can have their own options. Also you can create your own barcode types or renderers because they are not linked anymore.
Your example is correct.
I usually use npm to install picqer but I assume for the sake of testing I need to move the contents of the V3 branch into my project in place of the existing code. Is that right?
Do you mean installing via Composer? You can try something like (I am in mobile now):
composer require picqer/php-barcode-generator@dev-v3
, or change the version in composer.json to 'dev-v3'.
Sorry, you are correct. I was just interacting with someone trying to get our project's npm build running so I had that on the brain. I'll just do it through composer. I'm working on another project today through Friday but if I can sneak some time in the evening I'll try it out and let you know. Otherwise I'll do it Monday morning.
@casperbakker Looks like dev-v3 isn't a thing, but I was able to get v3.x-dev. The only problem I see so far is that it's requiring php 8.2. We are trying to keep our app backward compatible to at least 8.0. Is this just a dev build requirement or is there a reason for it to require 8.2?
hmmm. @casperbakker For some reason the SVG renderer is generating embedded png, not SVG
{
try
{
$barcode_value = $this->get_barcode_value($item, $barcode_config);
$barcode = (new TypeCode128())->getBarcode($barcode_value);
$renderer = new SvgRenderer();
return $renderer->render($barcode, $barcode_config['barcode_width'], $barcode_config['barcode_height']);
}
There is another problem. In our application the barcode type is stored as a string in our database and this worked because the barcode type was being passed as a parameter.
$generator = new BarcodeGeneratorSVG();
$barcode_value = $this->get_barcode_value($item, $barcode_config);
return $generator->getBarcode($barcode_value, $barcode_config['barcode_type'], 2, $barcode_config['barcode_height']);
The new style calls getBarcode() from the Barcode Type class. If I still want to store the selected barcode type in the database I now have to do something like
// Get the barcode type from the config
$barcode_type = $barcode_config['barcode_type'];
// Create the fully qualified class name
$class_name = "\\Picqer\\Barcode\\Types\\Type" . $barcode_type;
// Check if the class exists
if (!class_exists($class_name)) {
throw new Exception("Barcode type {$barcode_type} is not supported.");
}
// Create an instance of the barcode type class
$barcode_type_instance = new $class_name();
// Generate the barcode
$barcode = $barcode_type_instance->getBarcode($barcode_value);
It also means me adding use statements for all supported barcode types. This is not desirable.
To be clear, the png isn't the correct width either. It is the correct width in the sense that the image is that dimension, but it's padded whitespace rather than the barcode being stretched to fit the width.
@casperbakker did you see my testing results above?
@casperbakker did you see my testing results above?
Yes, thank you for testing it.
The issues that you found are probably down to a mistake in the implementation than with the library. I looked into several times, but it is not possible to get a PNG with the SVG renderer. It also should not add more whitespace, it really stretches the whole image.
The problems with implementing the different types from the database is not something I can fix in the v3 version. The new way is better in a lot of ways, and can certainly also be fed from strings out of a database. But maybe you need to change your code a bit to make it conform to the new version. But it also gives you lot of benefits, like the width definition and in the future the possibility to add margins.
I just released the v3 version. If you want to use the widths, you can use the new way. But it is also fully backwards compatible, so no need to change your code if you don't want to.
For barcode generators which allow float width factors, everything is already there to allow this.
Let's say I want to have an SVG barcode generated to 250px every time (dynamic width factor) In my code I could do this:
then call
$generator->getBarcode($barcode_value, $barcode_type, $widthFactor, $barcode_height]);
The problem with this is thatgetBarcodeData()
is protected so I can't call it outside of theBarcodeGeneratorSVG
class.Please consider adding the ability to send the width in pixels instead of the width factor and do the above calculation in the function.
There are two ways this can be done without breaking existing uses of the function:
getBarcode(string $barcode, $type, float $widthFactor = 2, float $height = 30, string $foregroundColor = 'black', bool $dynamicWidthFactor = false): string
. Then in the function itself if $dynamicWidthFactor is true, assume the value of $widthFactor is in pixels and do the above calculation of what the width factor should be. The rest of the function remains the same. When working with SVGs, pixels can be a float, so widthFactor being a float doesn't break this.getBarcode(string $barcode, $type, int $width, float $height = 30, string $foregroundColor = 'black'): string
and of course the width factor calculation above, but otherwise the function working the same.It seems like it would be a waste to do 2 since the only difference between the two is the width factor being calculated, but it depends on what you're going for.