[Solved] Retrieve XShape position relative to page when anchor ≠ AT_PAGE

Creating a macro - Writing a Script - Using the API (OpenOffice Basic, Python, BeanShell, JavaScript)
Locked
wcdr
Posts: 9
Joined: Fri Nov 29, 2024 5:36 pm

[Solved] Retrieve XShape position relative to page when anchor ≠ AT_PAGE

Post by wcdr »

Hi,

I have iterated the forum to find a solution to my problem without success.
I work in C++ but if your solution is on another language it's not a problem the API is very close.

My problem is that I'm exporting the text and images of a document (.odt/.docx) to JSON, but I'm having a problem with the position of the images (xshape/png).

When the anchor is AT_PAGE, “HoriOrientPosition” and “VertOrientPosition” contain the shape coordinates related to the page.
> That's great, that's exactly what I need!

But there are other cases, and for the moment I've concentrated on the default anchor “AT_CHARACTER”.
When I read the position, the result is linked to the anchor.
So, using XTextContentI, I can call getAnchor.
https://api.libreoffice.org/docs/idl/re ... 4483a877d3
I can get "the text range to which the content is attached."
Using XTextRange interface and XTextViewCursor
I can create a cursor and move it to the start of the xshape.
I can call getPosition and it's supposed to return “the coordinates of the cursor relative to the top left position of the first page of the document”. But the value is too small
>> What did I miss <<.

I tried another approach, I changed the anchor type to AT_PAGE, the position values after the anchor change remain the same, so the xshape is no longer located in the same place (jump to the top of the page).
>> How can I do the same thing as when in the user interface I change the anchor type from AT_CHARACTER to AT_PAGE, the xshape stays in the same place and the position is the one I need. <<
> I searched the source code but couldn't find the location of this operation.

Thanks for your help
Last edited by MrProgrammer on Sun Dec 22, 2024 3:18 am, edited 2 times in total.
Reason: ≈edi
Libreoffice 7.6.3.1 on Linux
JeJe
Volunteer
Posts: 3127
Joined: Wed Mar 09, 2016 2:40 pm

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by JeJe »

If you provide a stripped down sample document to illustrate the problem where the jump to the top of the page occurs.

I test this line on a simple one page document and its fine for me.

Code: Select all

thiscomponent.graphicobjects.getbyindex(0).anchortype = com.sun.star.text.TextContentAnchorType.AT_PAGE
You could also try the macro recorder version of this operation, which is also fine for me.

Edit: and also another or the same document to illustrate the getposition value not being what's expected.
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
wcdr
Posts: 9
Joined: Fri Nov 29, 2024 5:36 pm

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by wcdr »

Hi, thanks for replying, this forum doesn't seem to have any attachment capability, so I put it on an external source :
https://drive.google.com/drive/folders/ ... sp=sharing

Because gdrive doesn't interpret the document correctly ^_^, the image isn't in the right place “y to small”, I've also put a screenshot of LO and another with my version rendered from json to HTML (the document has a 2 cm margin for scale).

Data are exported in cm :
[{ "flip-h": false,
"flip-v": false,
"height": 5.445,
"mime": "image/png",
"name": "Image1",
"page": 0,
"position": { "x": 13.046, "y": 0.522 },
"rotate": 0,
"type": "image",
"uid": "a4d95c94-0619-4a81-a018-9bea8950c629",
"width": 3.828,
"wrap": "all",
"z-order": 0 }]

For the macro, I tried but LO doesn't record anything when I switch from AT_CHAR to AT_PAGE.
When I do another change type, it records, but the image position changes on LO...
I've also put a screenshot of my rendering with LO side by side to compare the export with AT_PAGE set manually from the user interface.

For anchor changing by code position(read) before and after are the same: Before: 13046 522 / After: 13046 522
I don't have the result of the document because I don't modify the source document...
I checked the anchor type after the change and it was applied correctly.

// Extract position before changing anchor.
auto x1 { GetValue<sal_Int32, int32_t>( xPropertySet, "HoriOrientPosition" )};
auto y1 { GetValue<sal_Int32, int32_t>( xPropertySet, "VertOrientPosition" )};

// Force anchor type to page (simplify coordinate management).
SetAnchorType ( xPropertySet, TextContentAnchorType_t::TextContentAnchorType_AT_PAGE );

// Extract position after changing anchor.
auto x2 { GetValue<sal_Int32, int32_t>( xPropertySet, "HoriOrientPosition" )};
auto y2 { GetValue<sal_Int32, int32_t>( xPropertySet, "VertOrientPosition" )};

With:
template<class T> using Ref_t = com::sun::star::uno::Reference<T>;
using XPropertySetRef_t = Ref_t<com::sun::star::beans::XPropertySet>;
using TextContentAnchorType_t = com::sun::star::text::TextContentAnchorType;

template<class T1, typename T2 = T1>
inline T2 GetValue ( XPropertySetRef_t const & xPropertySet, char const * const pcszLabel, T1 const def = {})
{
T1 value { def };
xPropertySet->getPropertyValue ( ToString ( pcszLabel )) >>= value;
return static_cast<T2>( value );
}

inline void SetAnchorType ( XPropertySetRef_t const & xPropertySet, TextContentAnchorType_t const & eType )
{ xPropertySet->setPropertyValue ( "AnchorType", Any_t ( eType )); }
Libreoffice 7.6.3.1 on Linux
ms777
Volunteer
Posts: 208
Joined: Mon Oct 08, 2007 1:33 am

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by ms777 »

I am a bit afraid that you have a fundamental problem here. If your anchor is "To Paragraph", "To Character", or "As Character", the absolute position relative to the page border is only available after word wrapping. So it critically depends on properties not available in the XShape model.
I believe you have to go through CurrentController / Component Window / window properties to find out your actual shape position after word wrap
User avatar
floris v
Volunteer
Posts: 4593
Joined: Wed Nov 28, 2007 1:21 pm
Location: Netherlands

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by floris v »

Hi, thanks for replying, this forum doesn't seem to have any attachment capability
You add attachments with the Attachments tab below the text area where you enter your post. It's only visible in the full editor (recommended for use when you are new here).
LibreOffice 24.2.7.2 on Ubuntu Linux
If your problem has been solved or your question has been answered, please edit the first post in this thread and add [Solved] to the title bar.
Nederlandstalig forum
JeJe
Volunteer
Posts: 3127
Joined: Wed Mar 09, 2016 2:40 pm

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by JeJe »

Works fine in OO but in LO there's no macro record and the position changes and the OO recorded macro doesn't have any effect.

Perhaps, make a copy of your document, open it in OO, change everything with a macro there and read off the positions and apply those to your LO original?
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
JeJe
Volunteer
Posts: 3127
Joined: Wed Mar 09, 2016 2:40 pm

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by JeJe »

This seems to adjust for that example - adding the page margins and the anchor y position

Code: Select all

vc = thiscomponent.currentcontroller.viewcursor
gobj= thiscomponent.graphicobjects(0)
vc.gotorange(gobj.getanchor.getstart,false)
gvc = vc.position
x1= gobj.HoriOrientPosition
y1 = gobj.VertOrientPosition
gobj.anchortype = com.sun.star.text.TextContentAnchorType.AT_PAGE

 gobj.HoriOrientPosition =x1 + 2000 'add left page margin
 gobj.VertOrientPosition =y1 + 2000 + gvc.y 'add top page margin and the anchor y position

Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
JeJe
Volunteer
Posts: 3127
Joined: Wed Mar 09, 2016 2:40 pm

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by JeJe »

For other pages you might need jumpToPage for the viewcursor to also get the y position at the top of the page and subtract that.
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
wcdr
Posts: 9
Joined: Fri Nov 29, 2024 5:36 pm

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by wcdr »

Hi, thank you for your reply. I added some code to save the document in ODT format after changing the anchor type and the result is the same as the one I obtained (JSON/HTML).
I've also added another image to check that the margins don't play a role, this isn't the case, the space between the upper limit of the page and the image is equal to the space between the anchor and the image before changing the anchor type, and afterwards it remains the same as the x,y result indicated so the image jumps to the top of the page.
As suggested I'm going to try to switch to OpenOffice(Apache), last weekend I tried to upgrade to LO 24.x and the sdk examples don't work properly, after a few changes, it crashes when loading....
I'll share my findings here.
Libreoffice 7.6.3.1 on Linux
wcdr
Posts: 9
Joined: Fri Nov 29, 2024 5:36 pm

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by wcdr »

Is there a way to retrieve the element associated with an anchor, such as a character or paragraph?
Libreoffice 7.6.3.1 on Linux
JeJe
Volunteer
Posts: 3127
Joined: Wed Mar 09, 2016 2:40 pm

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by JeJe »

Get MRI and explore the objects you're interested with that. You can see with it, that the anchor, if its to character or paragraph is a textrange - so you can enumerate for the paragraph. The character appears to be the one on the left of the anchor position.

viewtopic.php?t=49294
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
wcdr
Posts: 9
Joined: Fri Nov 29, 2024 5:36 pm

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by wcdr »

Hi, thanks, I used to use xray but this one seems easier to use.
Libreoffice 7.6.3.1 on Linux
wcdr
Posts: 9
Joined: Fri Nov 29, 2024 5:36 pm

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by wcdr »

Hi,

I review my work and do corrections according to Jeje tips and other information from old posts.
Your right position needs to be corrected by margins (2000 in my case).

I have two questions:
1 - Why not add the x anchor offset and add the y anchor offset (it's right but why)?
2 - I have a fixed y offset ~+426 per previous page.
* First page offset: 0.
* Second page offset; -( height page 0 + 426 ).
* Third page offset: -(( height page 0 + 426)+( height page 1 + 426)).

According to the documentation: "The cursor's coordinates relative to the top left position of the first page of the document."
So I correct the shape offset using the previous page height in my case: 29700 but the right value is ~30126
> Is it possible that page height must include and UI separator (the grey part between each page) or a border?

// Get shape position (ref: [left,top] anchor).
auto const x1 { GetValue<sal_Int32, int32_t>( xPropertySet, "HoriOrientPosition" )};
auto const y1 { GetValue<sal_Int32, int32_t>( xPropertySet, "VertOrientPosition" )};

// Force position before to keep shape at the same position on the page.
SetValue<sal_Int32>( xPropertySet, "HoriOrientPosition", ctxPage.m_leftMargin + x1 );
SetValue<sal_Int32>( xPropertySet, "VertOrientPosition", -ctxPage.m_yOffset + ctxPage.m_topMargin + posAnchor.Y + y1 );

// Force anchor type to page (simplify coordinate management).
SetAnchorType ( xPropertySet, TextContentAnchorType_t::TextContentAnchorType_AT_PAGE );

I update the drive : with doc before and after + screenshoot (don't take care of gdrive preview it's completely buggy).

If I change the font size of the document, the image moves; the larger the font, the greater the gap...
Libreoffice 7.6.3.1 on Linux
JeJe
Volunteer
Posts: 3127
Joined: Wed Mar 09, 2016 2:40 pm

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by JeJe »

The value given by the viewcursor position depends on the layout... you can see this by switching to a multipage view and looking at the values... so the gap between pages does look to be included in the measurement. The added value for each page is about 500 for me so varies from yours.
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
wcdr
Posts: 9
Joined: Fri Nov 29, 2024 5:36 pm

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by wcdr »

LO therefore mixes user interface and document information!
In this case, without device independent measurement, it is impossible to extract the relevant information to display a facsimile of the document using UNO.
It may explain why ODT can't be display correctly on other software...
Sad!

Is there a way, from the point of view of an LO extension, to access more relevant information (without having to recompile and hack LO)?
Libreoffice 7.6.3.1 on Linux
JeJe
Volunteer
Posts: 3127
Joined: Wed Mar 09, 2016 2:40 pm

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by JeJe »

I don't understand why you can't solve the original problem of the position of the picture? An odt is information about paragraphs and so on, the position information isn't in that file - that gets worked out when its loaded - and is given through the viewcursor.

There is information available via the accessiblecontext of where every character of text that can be seen is placed but its similar to what the viewcursor tells you and I don't see how it would make any difference here.
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
wcdr
Posts: 9
Joined: Fri Nov 29, 2024 5:36 pm

Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE...

Post by wcdr »

Hi, thank you for your reply

“The position information is not in this file - it is calculated when it is loaded - and it is given by the view cursor.
This is my basic assumption, which is why I don't want to read the document from a file using a library/specification but use LO to do the job.


Yes, the view cursor gives a position relative to the first page, but there is an offset between pages that is variable and relative to the user interface.
I don't understand the design behind this, but it's not important...

In my imagination, somewhere in the API there is information to get the dependency chain:
shape -> character -> paragraph -> page (-> document)
And for each child/parent pair, something to retrieve the distance between child and parent (x/y Independent UI in document unit 100th/mm).

So far, I haven't found anything like that...

A long time ago, I wrote my own PDF reader from scratch using the ISO specification and antigrain as a primitive renderer: https://drive.google.com/file/d/1A-7aMj ... drive_link

This time I'm trying to use LO to simplify my life ^_^...
I have a lot of work this week, so I'll continue this personal project next weekend.

Thanks for your help/time,
Regards.
Libreoffice 7.6.3.1 on Linux
wcdr
Posts: 9
Joined: Fri Nov 29, 2024 5:36 pm

[SOLUTION][CLOSED] Re: UNO API (or VBScript) how retrieve XShape position relative to page when anchor diff from AT_PAGE

Post by wcdr »

Solution pseudocode:

1 - Get page [X,Y] offset :

Code: Select all

  * For all pages
  	* Put TextViewCursor at the beginning of the page
    * Push page info in an array/vector [index;xOffset;yOffset]	
	* With:
		* x-offset = Page property-set : LeftMargin
		* y-offset = cursor.getPosition.Y - page property-set: TopMargin
Warning: Offset between two page is not equal to page height!

2 - Export all shapes position :

Code: Select all

  * Get type using shape property-set: "AnchorType"	
  * For AT_PAGE: use shape property-set [HoriOrientPosition;VertOrientPosition]
  * For AT_PARAGRAPH & AT_CHARACTER :
	* Get shape anchor y position. 
	* Get shape position [x,y] - Using shape property-set: HoriOrientPosition & VertOrientPosition.
	* Update shape position with:
		* HoriOrientPosition: ( page xOffset ) + ( shape x )
		* VertOrientPosition: ( anchor y ) - ( page yOffset ) + ( shape y )
	* Change anchor type to AT_PAGE
	* Export shape as an AT_PAGE
Note: I only use the margins of the page for corrections, but it is possible that the margins of the 1st paragraph of the page are needed to correct the position, the future will tell me!

:super: Many thanks JeJe for your help!!!
Libreoffice 7.6.3.1 on Linux
Locked