I am searching for a long time on net. But no use.
Please help or try to give some ideas how to achieve this.
Any help will be appreciated.
I get the Matrix by ImageRenderInfo#GetImageCTM(), and get the X/Y coordiantors.
but it is always 0!
I have tried these api, GetStartPoint(), and GetImageCTM.
However, the X/Y coordinator is always 0 :-(
Note: I have some images in pdf in some positons(not the (0,0) coordinator).
void IRenderListener.RenderImage(ImageRenderInfo imgRenderInfo)
{
Matrix mtx = imgRenderInfo.GetImageCTM();
// x, y
float[] coordinate = new float[] { mtx[Matrix.I31], mtx[Matrix.I32] };
// Why the coordinate[0] and coordinate[1]
// are always be ZERO regardless the positon in Pdf
}
Answer to the question as is
I parsed the page contents of an arbitrary file I had at hands (the example PDF from this question) using a render listener with your implementation code plus output of the coordinates:
public void ExtractImageCoordinatesFromArchmodels()
{
using (PdfReader reader = new PdfReader(#"EVERMOTION ARCHMODELS VOL.78.pdf"))
{
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
ImageCoordinatesRenderListener listener = new ImageCoordinatesRenderListener();
for (var i = 1; i <= reader.NumberOfPages; i++)
{
parser.ProcessContent(i, listener);
}
}
}
internal class ImageCoordinatesRenderListener : IRenderListener
{
public void BeginTextBlock()
{ }
public void EndTextBlock()
{ }
public void RenderText(TextRenderInfo renderInfo)
{ }
public void RenderImage(ImageRenderInfo renderInfo)
{
Matrix mtx = renderInfo.GetImageCTM();
// x, y
float[] coordinate = new float[] { mtx[Matrix.I31], mtx[Matrix.I32] };
Console.WriteLine("Image at {0}, {1}.", coordinate[0], coordinate[1]);
}
}
and the output was
Image at 6,00029, 52,15466.
Image at 19,84251, 363,4501.
Image at 294,091, 361,5604.
Image at 300,0336, 81,089.
Image at 15,59055, 72,94052.
Image at 5,322647, 340,7029.
Image at 288,5311, 386,0621.
Image at 291,7613, 69,35573.
Image at 28,50845, 53,13286.
Image at 41,2021, 380,3172.
Image at 290,8796, 368,9564.
Image at 295,8532, 50,71478.
Image at 19,13385, 49,21146.
Image at 25,5118, 385,9343.
Image at 282,4584, 379,8427.
Image at 293,5927, 65,19702.
Image at 4,535416, 60,35075.
Image at 3,364258, 374,4344.
Image at 288,0557, 373,5591.
Image at 299,9102, 59,13971.
Image at 11,33858, 66,10181.
Image at 11,66959, 380,3134.
Image at 297,1836, 378,4615.
Image at 299,9689, 66,74164.
Image at 10,62991, 53,18137.
Image at 5,180252, 377,7065.
Image at 279,9567, 377,9544.
Image at 289,9219, 69,23323.
Image at 6,400314, 68,17795.
Image at 11,33858, 361,2458.
Image at 297,1935, 373,4553.
Image at 299,8854, 68,30142.
Image at 7,086609, 68,13367.
Image at 3,82518, 352,3451.
Image at 287,9208, 373,4846.
Image at 294,6425, 68,3132.
Image at 41,2271, 68,15968.
Image at 5,709488, 356,2161.
Image at 304,9857, 373,593.
Image at 282,4557, 48,97745.
Image at 5,669281, 53,65367.
Image at 27,34265, 382,0123.
Image at 297,1409, 373,494.
Image at 300,0584, 50,23624.
Image at 7,245102, 68,23528.
Image at 8,503922, 380,1963.
Image at 290,1901, 355,9355.
Image at 287,2598, 60,53516.
Image at 5,102356, 68,01541.
Image at 17,00786, 378,9057.
Image at 296,8928, 373,5667.
Image at 299,9655, 68,04535.
(My locale uses a comma as decimal separator.)
So I cannot reproduce your claim
the X/Y coordinator is always 0
Thus, what you observed is either due to some issue of your remaining code or something special about all your test PDFs; probably they simply indeed all have their images positioned at 0,0
Clarifications from comments
Meanwhile the OP has clarified in comments that the images of interest are located in annotation appearance streams, not in the page content stream.
Coordinates therein are in the respective annotation appearance stream coordinate system which is implied by the appearance's bounding box (its BBox entry). This bounding box then optionally is transformed by the appearance matrix (its Matrix entry). The resulting four sided area then is scaled and moved into the annotation's rectangle (its Rect entry). And depending on page rotation and annotation properties, this rectangle may be rotated by a multiple of 90° relative to the page coordinates.
Thus, a general solution transforming those coordinates into the default user space coordinate system of the page requires some math.
Often, though, bitmaps in annotation appearances are filling the bounding box (nearly) completely. Often there is no appearance matrix. And often annotations rotate with the page.
Thus, an often good approximation is to simply use the annotation rectangle. This also is what the OP now uses.
My question is related to this previous question. What I want to achieve is to stack images (they have transparency), write a string on top, and save the photomontage / photocollage with full resolution.
#Override
protected void beforeMain(Form f) {
Image photoBase = fetchResourceFile().getImage("Voiture_4_3.jpg");
Image watermark = fetchResourceFile().getImage("Watermark.png");
f.setLayout(new LayeredLayout());
final Label drawing = new Label();
f.addComponent(drawing);
// Image mutable dans laquelle on va dessiner (fond blanc)
Image mutableImage = Image.createImage(photoBase.getWidth(), photoBase.getHeight());
drawing.getUnselectedStyle().setBgImage(mutableImage);
drawing.getUnselectedStyle().setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FIT);
// Paint all the stuff
paints(mutableImage.getGraphics(), photoBase, watermark, photoBase.getWidth(), photoBase.getHeight());
// Save the collage
Image screenshot = Image.createImage(photoBase.getWidth(), photoBase.getHeight());
f.revalidate();
f.setVisible(true);
drawing.paintComponent(screenshot.getGraphics(), true);
String imageFile = FileSystemStorage.getInstance().getAppHomePath() + "screenshot.png";
try(OutputStream os = FileSystemStorage.getInstance().openOutputStream(imageFile)) {
ImageIO.getImageIO().save(screenshot, os, ImageIO.FORMAT_PNG, 1);
} catch(IOException err) {
err.printStackTrace();
}
}
public void paints(Graphics g, Image background, Image watermark, int width, int height) {
g.drawImage(background, 0, 0);
g.drawImage(watermark, 0, 0);
g.setColor(0xFF0000);
// Upper left corner
g.fillRect(0, 0, 10, 10);
// Lower right corner
g.setColor(0x00FF00);
g.fillRect(width - 10, height - 10, 10, 10);
g.setColor(0xFF0000);
Font f = Font.createTrueTypeFont("Geometos", "Geometos.ttf").derive(220, Font.STYLE_BOLD);
g.setFont(f);
// Draw a string right below the M from Mercedes on the car windscreen (measured in Gimp)
g.drawString("HelloWorld",
(int) (848 ),
(int) (610)
);
}
This is the saved screenshot I get if I use the Iphone6 skin (the payload image is smaller than the original one and is centered). If I use the Xoom skin this is what I get (the payload image is still smaller than the original image but it has moved to the left).
So to sum it all up : why is the saved screenshot with Xoom skin different from the one I get with Iphone skin ? Is there anyway to directly save the graphics on which I paint in the paints method so that the saved image would have the original dimensions ?
Thanks a lot to anyone that could help me :-)!
Cheers,
You can save an image in Codename one using the ImageIO class. Notice that you can draw a container hierarchy into a mutable image using the paintComponent(Graphics) method.
You can do both approaches with draw image on mutable or via layouts. Personally I always prefer layouts as I like the abstraction but I wouldn't say the mutable image approach is right/wrong.
Notice that if you change/repaint a lot then mutable images are slower (this will not be noticeable for regular code or on the simulator) as they are forced to use the software renderer and can't use the GPU fully.
In the previous question it seems you placed the image with a "FIT" style which naturally drew it smaller than the containing container and then drew the image on top of it manually... This is problematic.
One solution is to draw everything manually but then you will need to do the "fit" aspect of drawing yourself. If you use layouts you should position everything based on the layouts including your drawing/text.
I have searched everywhere and i cannot find any solution after 2 days of trying.
The Problem:
I'm doing an image Viewer with "Fit Image to View" feature. I load a picture of say 3000+ pixels in my GraphicsView (which is a lot smaller ofcourse), scrollbars appear that's good. When i click my btnFitView and executed:
ui->graphicsView->fitInView(scene->sceneRect(),Qt::KeepAspectRatio);
This is down scaling right? After fitInView() all lines are pixelated. It looks like a saw went over the lines on the image.
For example: image of a car has lines, image of a texbook (letters become in very bad quality).
My code sample:
// select file, load image in view
QString strFilePath = QFileDialog::getOpenFileName(
this,
tr("Open File"),
"/home",
tr("Images (*.png *.jpg)"));
imageObject = new QImage();
imageObject->load(strFilePath);
image = QPixmap::fromImage(*imageObject);
scene = new QGraphicsScene(this);
scene->addPixmap(image);
scene->setSceneRect(image.rect());
ui->graphicsView->setScene(scene);
// on_btnFitView_Clicked() :
ui->graphicsView->fitInView(scene->sceneRect(),Qt::KeepAspectRatio);
Just before fitInView(), sizes are:
qDebug()<<"sceneRect = "<< scene->sceneRect();
qDebug()<<"viewRect = " << ui->graphicsView->rect();
sceneRect = QRectF(0,0 1000x750)
viewRect = QRect(0,0 733x415)
If it is necessary i can upload screenshots of original loaded image and fitted in view ?
Am i doing this right? It seems all examples on the Web work with fitInView for auto-fitting. Should i use some other operations on the pixmap perhaps?
SOLUTION
// LOAD IMAGE
bool ImgViewer::loadImage(const QString &strImagePath)
{
m_image = new QImage(strImagePath);
if(m_image->isNull()){
return false;
}
clearView();
m_pixmap = QPixmap::fromImage(*m_image);
m_pixmapItem = m_scene->addPixmap(m_pixmap);
m_scene->setSceneRect(m_pixmap.rect());
this->centerOn(m_pixmapItem);
// preserve fitView if active
if(m_IsFitInView)
fitView();
return true;
}
// TOGGLED FUNCTIONS
void ImgViewer::fitView()
{
if(m_image->isNull())
return;
this->resetTransform();
QPixmap px = m_pixmap; // use local pixmap (not original) otherwise image is blurred after scaling the same image multiple times
px = px.scaled(QSize(this->width(),this->height()),Qt::KeepAspectRatio,Qt::SmoothTransformation);
m_pixmapItem->setPixmap(px);
m_scene->setSceneRect(px.rect());
}
void ImgViewer::originalSize()
{
if(m_image->isNull())
return;
this->resetTransform();
m_pixmap = m_pixmap.scaled(QSize(m_image.width(),m_image.height()),Qt::KeepAspectRatio,Qt::SmoothTransformation);
m_pixmapItem->setPixmap(m_pixmap);
m_scene->setSceneRect(m_pixmap.rect());
this->centerOn(m_pixmapItem); //ensure item is centered in the view.
}
On downshrink this produces good quality. Here are some stats after calling these 2 functions:
// "originalSize()" : IMAGE SIZE = (1152, 2048)
// "originalSize()" : PIXMAP SIZE = (1152, 2048)
// "originalSize()" : VIEW SIZE = (698, 499)
// "originalSize()" : SCENE SIZE = (1152, 2048)
// "fitView()" : IMAGE SIZE = (1152, 2048)
// "fitView()" : PIXMAP SIZE = (1152, 2048)
// "fitView()" : VIEW SIZE = (698, 499)
// "fitView()" : SCENE SIZE = (280, 499)
There is a problem now, after call to fitView() look the size of scene? Much smaller.
And if fitView() is activated, and I now scale the image on wheelEvent (zoomIn/zoomOut), with the views scale function: scale(factor,factor); ..produces terrible result.
This doesn't happen with originalSize() where scene size is equal to image size.
Think of the view as a window into the scene.
Moving the view large amounts, either zooming in or out, will likely create images that don't look great. Rather than the image being scaled as you would expect, the view is just moving away from the scene and doing its best to render the image, but the image has not been scaled, just transformed in the scene.
Rather than using QGraphicsView::fitInView, keep the main image in memory and create a scaled version of the image with QPixamp::scaled, each time FitInView is selected, or the user zooms in / out. Then set this QPixmap on the QGraphicsPixmapItem with setPixmap.
You may also want to think about dropping the scroll bars and allowing the user to drag the image around the screen, which provides a better user interface, in my opinion; though of-course it depends on your requirements.
I am trying to render 3D bar chart in SCNView using ScreenKit framework.
My rendering code is,
int height=10,y=0,x=0;
for (int i=0; i<10; i++) {
SCNBox *box1 = [SCNBox boxWithWidth:4 height:height length:2 chamferRadius:0];
boxNode1 = [SCNNode nodeWithGeometry:box1];
boxNode1.position = SCNVector3Make(x, y, 0);
SCNMaterial *material = [SCNMaterial material];
material.diffuse.contents = (NSColor *)[self.colorArray objectAtIndex:i%6];
material.specular.contents = [NSColor whiteColor];
material.shininess = 1.0;
box1.materials = #[material];
//boxNode1.transform = rot;
[scene.rootNode addChildNode:boxNode1];
x+=6;
height+=10;
y += 5 ;
}
I can render but while re-sizing the view the chart bars goes to the center of the view.
I need to render the chart, which cover the margins of the view and when Re-size it have to change accordingly. The image(s) below shows my problem.
Original Image:
Image where less stretching of both windows:
Can anyone please help me to fix the issue.
The the windows in the image that you had linked to in your original question was very stretched and that made it very hard to see what was going on. When I took that image and made the windows less stretched it was easier to have some idea of what is going on.
I think that you are seeing a general resizing issue. Either you are using springs and struts and have configured flexible margins on the left and right or you are using auto layout with a centered view with fixed width.
I assume that the red boxes that I have drawn in the image below is the bounds of your scene view in both these cases. You can easily see if this is the case by giving the scene view a different background color and resize it again.
My solution to your problem would be to change how your view resizes as the window resizes, to better meet your expectations.
i am trying to rotate a 89x89 image inside the QLabel Widge.
#include "header.h"
disc::disc(QWidget *Parent) : QWidget(Parent)
{
orig_pixmap = new QPixmap();
rotate = new QLabel(this);
showDegrees = new QLabel(this);
orig_pixmap->load("pic.png");
degrees = 0;
rotate->resize(89,89);
rotate->move(100,10);
rotate->setStyleSheet("QLabel{background-color:red;}");
showDegrees->resize(100,100);
showDegrees->move(400,0);
}
void disc::rotate_disc()
{
QString string;
degrees++;
if(degrees == 360) degrees = 0;
QTransform rotate_disc;
rotate_disc.translate( (orig_pixmap->width()-rotate->width())/2 , (orig_pixmap->width()-rotate->height())/2);
rotate_disc.rotate(degrees,Qt::ZAxis);
QPixmap pixmap;
//pixmap = orig_disc->scaled(89,89,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
pixmap = orig_pixmap->transformed(rotate_disc,Qt::SmoothTransformation);
rotate->setPixmap(pixmap);
string.append("Degrees: " + QString::number(degrees) + "*");
showDegrees->setText(string);
}
Even though it rotates. The image's half gets rolled outside the QLabel and hence that side is not visible.How can i make it center rotate at origin(0,0) of the image center.
Here is the file
http://www65.zippyshare.com/v/85775455/file.html
if you look at it you can see that image is like bouncing to the left.how can i make it rotate inside the black area.
i setup a signal timeout at every 10ms to the rotate_disc() function. I am using this to learn Qt indepth.
Thank You!
I've done it like this...
//Move windows's coordinate system to center.
QTransform transform_centerOfWindow( 1, 0, 0, 1, width()/2, height()/2 );
//Rotate coordinate system.
transform_centerOfWindow.rotate( m_LoadingDisk_degrees );
//Draw image with offset to center of image.
QPainter painter( this );
//Transform coordinate system.
painter.setTransform( transform_centerOfWindow );
//Load image.
//Notice: As coordinate system is set at center of window, we have to center the image also... so the minus offset to come to center of image.
painter.drawPixmap( -loadingDisk.width()/2, -loadingDisk.height()/2, loadingDisk );
I think all you're really missing is the initial translation to do the rotation around the centre of the pixmap.
Move it to the origin, rotate, then move it back. And remember, transformations are applied in reverse order from how you'd expect, given how you specify them in the code.
QTransform rotate_disc;
rotate_disc.translate(orig_pixmap->width()/2.0 , orig_pixmap->height()/2.0);
rotate_disc.rotate(degrees);
rotate_disc.translate(-orig_pixmap->width()/2.0 , -orig_pixmap->height()/2.0);
If you are making a loading indicator, animated gif would be much easier. See GIF animation in Qt