scanny / python-pptx

Create Open XML PowerPoint documents in Python
MIT License
2.26k stars 498 forks source link

Set/change font color when working with Hyperlinks is impossible #940

Open Mike3285 opened 5 months ago

Mike3285 commented 5 months ago

Looks like it's not possible to set the color of the font if an hyperlink is present in the same run.

Here is my relevant code:

text_frame = shape.text_frame
p = text_frame.paragraphs[0]
# adding hyperlink
r = p.runs[0]
hlink = r.hyperlink
my_url = data["d_url"]
hlink.address = my_url

r.font.bold = False
r.font.italic = False
r.font.underline = False

r.font.color.rgb = RGBColor(0x00, 0x00, 0x00) # Black

This will still use the "hyperlink theme color" for the link, ignoring my setting.

Please suggest me how to change the hyperlink color or correct me if I am wrong

MartinPacker commented 5 months ago

Do you actually want one hyperlink to look different from the rest? Other than "visited" versus "not" ? That would generally be considered poor for usability.

Mike3285 commented 5 months ago

I just want all the text in the presentation to have the same formatting, both visited and not visited, for hyperlinks and normal text

MartinPacker commented 5 months ago

So the question becomes how to set the hyperlink colours - for visited and unvisited - across the board.

Glad I clarified - but I, personally, don't know how to do this.

scanny commented 5 months ago

Seeing if you can do it from the PowerPoint UI is a good start. If you can't that's a pretty strong indicator it's not supported and if you can it's an absolute indicator the format supports it.

The you can make a short PPTX that doesn't have a custom color, edit it with PowerPoint to color it, save it as a different name, then inspect the XML to see what's different. That's a reliable method to narrow down the XML portion anyway.

MartinPacker commented 5 months ago

@scanny do you know where the theme stuff is stored - and how to edit it (in python-pptx)? Actually, where it's stored would narrow down the XML search space.

(To be honest - as I don't actually need this function in md2pptx - I doubt I'll have the time to prototype anything.)

scanny commented 5 months ago

IIRC there is a theme part, so it would be in the package, probably something like ppt/theme.xml. You could unzip -l a PPTX file to see if you see something like that in there. I don't believe we have a proxy part in the code for that though.

It's been a while, but I vaguely remember that being a pretty simple part, like not that many different element types and not very long.

@Mike3285 If that's where this setting (visited/not-visited link color) is stored then you could accomplish this by using a customized "template" presentation that you gave the color setting you want by hand using the PowerPoint UI. So like: prs = Presentation("my-customized-template.pptx") instead of prs = Presentation() in your code.

MartinPacker commented 5 months ago

This link from Microsoft suggests it can be done in the UI - so must be doable in the file.

MartinPacker commented 5 months ago

But, and this is more hopeful, you can override a hyperlink's colour explicitly. Here is the XML for a run in slide1.xml (in this case):

            <a:r>
              <a:rPr lang="en-US" dirty="0">
                <a:solidFill>
                  <a:schemeClr val="accent5">
                    <a:lumMod val="40000" />
                    <a:lumOff val="60000" />
                  </a:schemeClr>
                </a:solidFill>
                <a:hlinkClick r:id="rId2">
                  <a:extLst>
                    <a:ext uri="{A12FA001-AC4F-418D-AE19-62706E023703}">
                      <ahyp:hlinkClr xmlns:ahyp="http://schemas.microsoft.com/office/drawing/2018/hyperlinkcolor" val="tx" />
                    </a:ext>
                  </a:extLst>
                </a:hlinkClick>
              </a:rPr>
              <a:t>hyperlink</a:t>
            </a:r>

Certainly confectable, using python-pptx as a base. One could do this for all hyperlinks, I think.

Personally, though, I have no need for this. But it might inspire somebody else to write some Python.

MartinPacker commented 5 months ago

By contrast, here's another hyperlink - that I didn't override the colour for:

            <a:r>
              <a:rPr lang="en-US" dirty="0">
                <a:hlinkClick r:id="rId3" />
              </a:rPr>
              <a:t>hyperlink</a:t>
            </a:r>
MartinPacker commented 5 months ago

I looked at the theme. And this XML in ppt/theme/theme1.xml looks significant:

      <a:hlink>
        <a:srgbClr val="467886" />
      </a:hlink>
      <a:folHlink>
        <a:srgbClr val="96607D" />
      </a:folHlink>

The first looks like an unfollowed link and the seconf the followed link (both as RGB colours).

But if, as @scanny said, there's no way within python-pptx to modify this file the theme-wide approach won't work. A pity as it looks simpler.

Mike3285 commented 5 months ago

IIRC there is a theme part, so it would be in the package, probably something like ppt/theme.xml. You could unzip -l a PPTX file to see if you see something like that in there. I don't believe we have a proxy part in the code for that though.

It's been a while, but I vaguely remember that being a pretty simple part, like not that many different element types and not very long.

@Mike3285 If that's where this setting (visited/not-visited link color) is stored then you could accomplish this by using a customized "template" presentation that you gave the color setting you want by hand using the PowerPoint UI. So like: prs = Presentation("my-customized-template.pptx") instead of prs = Presentation() in your code.

Thanks for your reply. At this point, I was referencing the Stackoverflow answer at the following link: Stackoverflow Answer where a kind user directed us to a guide explaining how to adjust the color template in PowerPoint directly.

Setting a theme and using it as a "template" for my presentations is working well, and I have successfully configured the hyperlinks in the desired color. However, this approach is not particularly reliable or elegant, and I am eager to see this functionality incorporated into python-pptx. If we can't override the theme colors for hyperlinks, allowing us to set or modify the PPTX "theme" from within Python may be sufficient.