[PHP/GD] Hoe maak ik een transparante stippellijn?

Pagina: 1
Acties:
  • 369 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Neem als voorbeeld de serverstats van T.net:

Afbeeldingslocatie: http://www.tweakers.net/ext/statschart.dsp?Action=Pageviews&Col=Totaal&Time=&Server=&Dagen=2
Dwars door de barchart lopen een aantal gestippelde gridlines. Deze zijn transparant: de "stippel" is zwart, maar tussen twee stippels in neemt de lijn de achtergrondkleur (wit of een kleur blauw) aan.

Ik probeer nu hetzelfde te bereiken en begon aan de volgende functie om een stippellijn te maken:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Stippellijn van (x1,y1) tot (x2,y2) met stippellengte dist en kleur col

function imagelinedotted($im, $x1, $y1, $x2, $y2, $dist, $col) {
  $transp = imagecolortransparent($im);
  $style = array($col);
  
  for ($i = 0; $i < $dist; $i++) {
    array_push($style, $transp);
  }
  
  imagesetstyle($im, $style);
  return (int) imageline($im, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED);
  imagesetstyle($im, array($col));
}

Het resultaat is echter:

Afbeeldingslocatie: http://www.danandan.luna.nl/got/barchart.png

Ik heb imagelinedotted() aangeroepen met de kleur wit als $col. De stippels zijn zoals verwacht, wit. De afstand tussen 2 stippels is 3 pixels, zoals opgegeven in de functiecall. Echter, de ruimte tussen de stippels wordt grijs gemaakt, terwijl ik deze graag transparant zou hebben. Wat doe ik verkeerd?

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Cavorka
  • Registratie: April 2003
  • Laatst online: 27-03-2018

Cavorka

Internet Entrepreneur

Heeft het hier iets mee te maken:
When you use palette images (created with imagecreate()), the first color allocated is the background color. This color cannot be used for transparency. So if you want to make the background transparent, first allocate a dummy background color, then allocate the real background color and declare this is as transparent.
Orde van kleur declareren doet soms nogal vaag, ik heb het probleem wat jij beschrijft ook al een paar keer gehad en als ik het me goed herinner opgelost door volgordes te veranderen of kleur allocaties op andere plekken te doen.

[ Voor 23% gewijzigd door Cavorka op 05-02-2007 00:20 ]

the-blueprints.com - The largest free blueprint collection on the internet: 50000+ drawings.


Acties:
  • 0 Henk 'm!

  • WormLord
  • Registratie: September 2003
  • Laatst online: 01-08 12:04

WormLord

Devver

Volgens mij komt het omdat er expliciet transparante pixels getekend worden in de gaten, in plaats van 'niets'. De originele pixels worden dus vervangen door transparante pixels. Ik heb helaas geen oplossing voor je probleem.

En er is ook onbereikbare code gedetecteerd op regel 13.

Acties:
  • 0 Henk 'm!

  • xces
  • Registratie: Juli 2001
  • Laatst online: 08-09 17:20

xces

To got or not to got..

Je zou kunnen kijken wat de breedte is tussen x1 en x2, en zo iedere keer 3 of 4 pixels tekenen, opschuiven.. etc.

Acties:
  • 0 Henk 'm!

  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 13:16
Die code is knip- en plakwerk van php.net: http://nl2.php.net/manual/nl/function.imageline.php#62606, inclusief unreachable statement :P.

Hoe belangrijk is het dat je lijntjes ook diagonaal getekend kunnen worden, want anders zou ik zeggen bak een functie die zelf een horizontale stippellijn tekent op hoogte y:
PHP:
1
2
3
4
5
6
7
8
function imagelinedashed($im, $y, $dist, $col) {
    $width = imagesx($im);
    $nextX = $dist * 2;

    for ($i = 0; $i <= $width; $i += $nextX) {
        imageline($im, $i, $y, $i + $dist - 1, $y, $col);
    }
}

Anders wordt de code wat lastiger en moet je zelf uit gaan zoeken hoe je een diagonale lijn tekent.

[ Voor 9% gewijzigd door Jaap-Jan op 05-02-2007 12:37 ]

| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett


Acties:
  • 0 Henk 'm!

  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

Het ligt puur aan de volgorde waarin je tekent, je moet eerst die lijnen tekenen en pas daarna je grafiek.
Precies hetzelfde als dat je een schilderij gaat maken.

Acties:
  • 0 Henk 'm!

  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 13:16
Erkens schreef op maandag 05 februari 2007 @ 12:35:
Het ligt puur aan de volgorde waarin je tekent, je moet eerst die lijnen tekenen en pas daarna je grafiek.
Precies hetzelfde als dat je een schilderij gaat maken.
Euhm nee. In dit geval liggen de stippellijnen over de grafiek heen, want anders zou de grafiek bij het tekenen over de stippellijnen heen getekend worden :).

| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett


Acties:
  • 0 Henk 'm!

  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

ehm, right. Het is maandag zeker? :+

je kan idd al die kleine streepjes gaan tekenen, of twee images mergen

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Ik zou de streepjes/stippels gewoon één voor één tekenen, en die transparante kleur gewoon helemaal niet gebruiken. :)

Overigens vraag ik me wel af wat je met regel 13 wil bereiken, Reveller? :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
-NMe- schreef op maandag 05 februari 2007 @ 13:12:
Ik zou de streepjes/stippels gewoon één voor één tekenen, en die transparante kleur gewoon helemaal niet gebruiken. :)
Mja, maar optimaal is anders :X
Het moet toch kunnen lijkt me? Ligt het niet gewoon aan het pallette (of misschien is het wel een anti-aliasing iets ofzo?)
-NMe- schreef op maandag 05 februari 2007 @ 13:12:
Overigens vraag ik me wel af wat je met regel 13 wil bereiken, Reveller? :)
Dat was al vaker opgemerkt ;)
WormLord schreef op maandag 05 februari 2007 @ 08:36:
En er is ook onbereikbare code gedetecteerd op regel 13.
Jaap-Jan schreef op maandag 05 februari 2007 @ 12:31:
Die code is knip- en plakwerk van php.net: http://nl2.php.net/manual/nl/function.imageline.php#62606, inclusief unreachable statement :P.

[ Voor 26% gewijzigd door RobIII op 05-02-2007 13:29 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • WormLord
  • Registratie: September 2003
  • Laatst online: 01-08 12:04

WormLord

Devver

Ik ben even aan het knutselen geslagen en heb ontdekt dat het wel goed gaat bij truecolour afbeeldingen.

Hier is een werkend voorbeeld.
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
// Set the content-type
header("Content-type: image/png");

// Create the image
$im = imagecreatetruecolor(701, 355);

$c1 = imagecolorallocate($im, 255, 128, 0);
$c2 = imagecolorallocate($im, 0, 255, 255);
$c3 = imagecolorallocate($im, 255, 255, 0);
$c4 = imagecolorallocatealpha($im, 255, 255, 0, 127);

imagefilledrectangle($im, 20, 30, 220, 300, $c1);
imagefilledrectangle($im, 300, 40, 410, 290, $c2);


$style = array($c4, $c4, $c4, $c4, $c4, $c4, $c3, $c3, $c3, $c3, $c3, $c3);
imagesetstyle($im, $style);
imagesetthickness($im, 2);

imageline($im, 5, 172, 696, 172, IMG_COLOR_STYLED);
imageline($im, 5, 176, 696, 176, $c3);

// Using imagepng() results in clearer text compared with imagejpeg()
imagepng($im);
imagedestroy($im);
?>

Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Bedankt iedereen! Ik heb uiteindelijk de functie van Jaap-Jan gepakt en uitgebreid met een $leftmargin parameter, zodat de stippellijnen niet meteen aan de linkerkant van het plaatje beginnen:

PHP:
1
2
3
4
5
6
7
8
function imagelinedotted($im, $leftmargin, $y, $dist, $col) {
  $width = imagesx($im) - $leftmargin;
  $nextX = $dist * 2;

  for ($i = 0; $i <= $width; $i += $nextX) {
    imageline($im, ($i + $leftmargin), $y, ($i + $dist + $leftmargin), $y, $col);
  }
}

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 13:16
Ik heb even een benchmark geschreven die de algoritmes van mij en WormLord test. Niet geheel onverwacht presteert het (door mij lichtelijk aangepaste) algoritme van WormLord een stuk beter :).

Wat er getest wordt zijn verschillende plaatjesgroottes (500x500, 1000x1000 en 2000x2000) en verschillende lijnbreedtes (1px, 3px en 5px). De beide algoritmes genereren identieke plaatjes. In het ergste geval (2000x2000 met een lijnbreedte van 1px) zit er een factor 11 verschil in snelheid:

De plaatjes zijn hier te downloaden: http://members.home.nl/jjvdveen/got/prg/test.tar.bz2.

De output van de benchmark (zelf ver-RML'd):
Size (W x H in px)Line size (px)Algorithm Time (s)
500 x 500110.727959156036
500 x 500120.0841469764709
500 x 500310.285812139511
500 x 500320.0916259288788
500 x 500510.183984041214
500 x 500520.100760936737
1000 x 1000112.8917529583
1000 x 1000120.291742801666
1000 x 1000311.11330986023
1000 x 1000320.306399106979
1000 x 1000510.709635972977
1000 x 1000520.325173139572
2000 x 20001111.5034019947
2000 x 2000121.07882213593
2000 x 2000314.42734599113
2000 x 2000321.10389494896
2000 x 2000512.80113005638
2000 x 2000521.15941286087


De gebruikte benchmarkcode en functies voor het tekenen van lijntjes:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<title></title>
<table>
<tr>
    <th>Size (W x H in px)</th>
    <th>Line size (px)</th>
    <th>Algorithm </th>
    <th>Time (s)</th>
</tr>
<?php
//write images to disk?
$saveimages = true;

//the line color for the dashed line
$color = hexdec('777777');

//verschillende groottes van de plaatjes (500x500, 1000x1000, 2000x2000)
for ($size = 500; $size <= 2000; $size *= 2) {

    //verschillende lijnlengtes (1, 3, & 5)
    for ($dashed = 1; $dashed <= 5; $dashed += 2) {

        //plaatje creeren
        $im = gettruecolorimage($size);

        //algoritme 1 benchmarken
        $startTime = getmicrotime();
        for ($i = 0; $i < $size; $i++) {
            imagelinedashed($im, $i, $dashed, $GLOBALS['color']);
        }
        $stopTime = getmicrotime();
        printresult($size, $dashed, 1, $stopTime - $startTime);

        //plaatje opslaan
        saveimage($im, $size, $dashed, 1);

        //plaatje creeren
        $im = gettruecolorimage($size);

        //algoritme 2 benchmarken
        $startTime = getmicrotime();
        for ($i = 0; $i < $size; $i++) {
            imagelinedashed2($im, 0, $i, $size, $i, $dashed, $GLOBALS['color']);
        }
        $stopTime = getmicrotime();
        printresult($size, $dashed, 2, $stopTime - $startTime);

        //plaatje opslaan
        saveimage($im, $size, $dashed, 2);
    }
}

function printresult($size, $linesize, $algo, $time) {
    echo
    '<tr>' .
        '<td>' . $size . ' x ' . $size . '</td>' .
        '<td>' . $linesize . '</td>' .
        '<td>' . $algo . '</td>' .
        '<td>' . $time . '</td>' .
        '</tr>';
}

function getmicrotime() {
    list($usec, $sec) = explode(" ",microtime());
    return ((float)$usec + (float)$sec);
}

function gettruecolorimage($size) {
    $im = imagecreatetruecolor($size, $size);

    $c1 = imagecolorallocate($im, 255, 128, 0);
    $c2 = imagecolorallocate($im, 0, 255, 255);
    imagefilledrectangle($im, 20, 30, 220, 300, $c1);
    imagefilledrectangle($im, 300, 40, 410, 290, $c2);
    return $im;
}

function saveimage($im, $size, $dist, $algo) {
    if ($GLOBALS['saveimages']) {
        $path = 'test/';
        $filename = $size . 'x' . $size . ' ' . $dist . 'px ' . $algo . '.png';
        imagepng($im, $path . $filename);
        imagedestroy($im);
    }
}

function imagelinedashed($im, $y, $dist, $col) {
    $width = imagesx($im);
    $nextX = $dist * 2;

    for ($i = 0; $i <= $width; $i += $nextX) {
        imageline($im, $i, $y, $i + $dist - 1, $y, $col);
    }
}

function imagelinedashed2($im, $x0, $y0, $x1, $y1, $dist, $col) {
    $trans = imagecolorallocatealpha($im, 255, 255, 0, 127);

    $style = array($col);

    for ($i = 0; $i < $dist - 1; $i++) {
        array_push($style, $col);
    }
    for ($i = 0; $i < $dist; $i++) {
        array_push($style, $trans);
    }

    imagesetstyle($im, $style);
    imageline($im, $x0, $y0, $x1, $y1, IMG_COLOR_STYLED);
}
?>

</table>
</html>

| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett


Acties:
  • 0 Henk 'm!

  • xces
  • Registratie: Juli 2001
  • Laatst online: 08-09 17:20

xces

To got or not to got..

Oke, en iemand al geprobeerd om datgene te doen wat hierboven gesuggereerd wordt:
je kan idd al die kleine streepjes gaan tekenen, of twee images mergen
D.w.z. teken de streepjes (met bijv. KNALroze als transparante kleur) en merge ze. Probleem is wel dat je dan weinig tot geen anti-aliased zooi hebt, maar het zou moeten werken, toch?

Acties:
  • 0 Henk 'm!

  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 13:16
xces schreef op maandag 05 februari 2007 @ 22:28:
Oke, en iemand al geprobeerd om datgene te doen wat hierboven gesuggereerd wordt:

[...]


D.w.z. teken de streepjes (met bijv. KNALroze als transparante kleur) en merge ze. Probleem is wel dat je dan weinig tot geen anti-aliased zooi hebt, maar het zou moeten werken, toch?
Ik snap niet helemaal wat de bedoeling is met het mergen. Wat is het verschil tussen het tekenen in de huidige tekening en een nieuwe tekening ernaast te maken en die te mergen? Als je een voorbeeldje kunt geven...

| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett


Acties:
  • 0 Henk 'm!

  • Engineer
  • Registratie: Juni 2001
  • Laatst online: 03-07 23:56

Engineer

Software

.

[ Voor 116% gewijzigd door Engineer op 13-10-2018 10:29 ]


Acties:
  • 0 Henk 'm!

  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

Engineer schreef op maandag 05 februari 2007 @ 23:09:
Ze bedoelen dat je een plaatje maakt ter grote van je grafiek, met daarop alleen alle lijnen en stippel lijntjes die altijd statisch op dezelfde plek zitten, en die 'merge' je dan over je dynamische plaatje heen. Zoiets kan nog wel eens performance schelen als dat nodig is ;)

Maar als performance niet nodig is zou ik gewoon de al gegeven code van hierboven gebruiken als dat goed werkt.
Ik denk niet dat mergen de performance goed zal doen ;)
Daarnaast vergt dat ook 2x zoveel geheugen als ik me niet vergis. Nee gewoon een van de twee andere manieren gebruiken, immers als performance een issue is dan zou ik in eerste plaats eens kijken naar caching in dit geval.
Pagina: 1