I'm extracting images from the PDF page using the PDFBox. In the example I used as a basis (PrintImageLocations), the value of 72 dpi is used for calculation. My question is, where does this value 72 come from?
// position in user space units. 1 unit = 1/72 inch at 72 dpi
System.out.println("position in PDF = " + ctmNew.getTranslateX() + ", " + ctmNew.getTranslateY() + " in user space units");
// raw size in pixels
System.out.println("raw image size = " + imageWidth + ", " + imageHeight + " in pixels");
// displayed size in user space units
System.out.println("displayed size = " + imageXScale + ", " + imageYScale + " in user space units");
// displayed size in inches at 72 dpi rendering
imageXScale /= 72;
imageYScale /= 72;
System.out.println("displayed size = " + imageXScale + ", " + imageYScale + " in inches at 72 dpi rendering");
// displayed size in millimeters at 72 dpi rendering
imageXScale *= 25.4;
imageYScale *= 25.4;
System.out.println("displayed size = " + imageXScale + ", " + imageYScale + " in millimeters at 72 dpi rendering");
Not the most technical of answers... but its been a "standard" for some time... one that is arbitrary and rather silly... Here's a random article that talks about its silliness.
https://petapixel.com/2020/02/13/why-wont-the-72dpi-myth-die/
PDF is closer to being a collection of pixels like a bitmap, than it is to being a token based document like a text file. So for sizing elements on the screen/page it has to assume certain resolution... Because 72dpi was so prevalent for images for so long it makes sense that pdf followed suit.
Related
I am working on a program where I take RGB values from a portion of an image. I want to remove the darkness in the color and make it bright. What I do is I use Color.RGBtoHSB I then take the brightness channel and set it to the highest value it can be in range then convert the HSB back to RGB. However, when I do this the color changes completely. Here is an example with dark red and it turning to purple and the code I use to do this.
System.out.println("Before Conversion:");
System.out.println("R: " + rAvg + "\nG :" + gAvg + "\nB :" + bAvg);
Color.RGBtoHSB(rAvg, gAvg, bAvg, hsv);
hsv[2] = 100; //Set to max value
System.out.println("H: " + hsv[0] * 360 + "\nS: " + hsv[1] * 100 + "\nV :" + hsv[2]);
int rgb = Color.HSBtoRGB(hsv[0], hsv[1], hsv[2]);
System.out.println("After conversion");
Color color = new Color(rgb);
System.out.println("R: " + color.getRed());
System.out.println("G: " + color.getGreen());
System.out.println("B: " + color.getBlue());
Output:
Before Conversion:
R: 128
G :39
B :50
H: 352.58426
S: 69.53125
V :100.0
After conversion
R: 158
G: 126
B: 233
The brightness, hsv[2], needs to be a value between 0 and 1. Try these two lines of code:
hsv[2] = 1; //Set to max value
System.out.println("H: " + hsv[0] * 360 + "\nS: " + hsv[1] * 100 + "\nV :" + hsv[2] * 100);
Getting negative imageXScale and imageYScale for some of pdf's
while converting pdf to image and finding its DPI.
Jar used is pdfbox1.8.8 and iText.
Found image Im0
position=602.64,451.08
size=837px,626px size=-212.59799mm,-159.131mm
Position which must be 0 has some value.
unable to detect the problem
The OP mentions he uses pdfbox1.8.8 and iText but offers no further indication how he retrieves values from his PDF using either of these libraries.
Considering the words imageXScale and imageYScale and the position and size outputs, I would assume he has used the PrintImageLocations PDFBox example.
The meaning of the PrintImageLocations outputs
This sample does the following outputs for a bitmap image drawn somewhere on a page:
System.out.println("Found image [" + objectName.getName() + "]");
The name of the image resource
Matrix ctmNew = getGraphicsState().getCurrentTransformationMatrix();
float imageXScale = ctmNew.getScalingFactorX();
float imageYScale = ctmNew.getScalingFactorY();
// position in user space units. 1 unit = 1/72 inch at 72 dpi
System.out.println("position in PDF = " + ctmNew.getTranslateX() + ", " + ctmNew.getTranslateY() + " in user space units");
Position of the anchor point, i.e. where the original bottom left corner of the image is drawn on the page.
// raw size in pixels
System.out.println("raw image size = " + imageWidth + ", " + imageHeight + " in pixels");
The original width and height of the image resource in pixels. Always non-negative.
// displayed size in user space units
System.out.println("displayed size = " + imageXScale + ", " + imageYScale + " in user space units");
The width and height of the image as drawn on the page. Negative values may mean that the image resource is not drawn right and up from the anchor point but instead left and down.
// displayed size in inches at 72 dpi rendering
imageXScale /= 72;
imageYScale /= 72;
System.out.println("displayed size = " + imageXScale + ", " + imageYScale + " in inches at 72 dpi rendering");
The width and height of the image as drawn on the page in inches assuming a user space unit width of 1/72nd inch, the default. Negative values may occur, see above.
// displayed size in millimeters at 72 dpi rendering
imageXScale *= 25.4;
imageYScale *= 25.4;
System.out.println("displayed size = " + imageXScale + ", " + imageYScale + " in millimeters at 72 dpi rendering");
The width and height of the image as drawn on the page in mm assuming a user space unit width of 1/72nd inch, the default. Negative values may occur, see above.
Thus, negative values here have a meaning (a mirroring or 180° rotation) which makes no difference in respect to any DPI properties. So to calculate a DPI value, use the absolute values only, ignore the signs.
Inconsistency in PDFBox
The x and y scaling factors used above are derived from the current transformation matrix like this:
/**
* Returns the x-scaling factor of this matrix. This is calculated from the scale and shear.
*
* #return The x-scaling factor.
*/
public float getScalingFactorX()
{
float xScale = single[0];
/**
* BM: if the trm is rotated, the calculation is a little more complicated
*
* The rotation matrix multiplied with the scaling matrix is:
* ( x 0 0) ( cos sin 0) ( x*cos x*sin 0)
* ( 0 y 0) * (-sin cos 0) = (-y*sin y*cos 0)
* ( 0 0 1) ( 0 0 1) ( 0 0 1)
*
* So, if you want to deduce x from the matrix you take
* M(0,0) = x*cos and M(0,1) = x*sin and use the theorem of Pythagoras
*
* sqrt(M(0,0)^2+M(0,1)^2) =
* sqrt(x2*cos2+x2*sin2) =
* sqrt(x2*(cos2+sin2)) = <- here is the trick cos2+sin2 is one
* sqrt(x2) =
* abs(x)
*/
if( !(single[1]==0.0f && single[3]==0.0f) )
{
xScale = (float)Math.sqrt(Math.pow(single[0], 2)+
Math.pow(single[1], 2));
}
return xScale;
}
(Excerpt from Matrix.java)
While obviously someone did spend some thoughts on this (look at the comment!), the implementation is somewhat inconsistent:
If there are non-zero values in single[1] or single[3], the calculation in the if block results in a non-negative method result.
For zero values in both single[1] and single[3], though, single[0] is returned as-is which may be negative.
A consistent implementation would either always remove the sign or always try to determine a meaningful sign
Furthermore the calculation is somewhat simplistic as it only considers transformation matrices which can be written as product of a scaling and a rotation. These are very common types but by far not all possible ones.
I want to change the slice thickness of my dicom volume data. I'm using
vtkImageViewer2.
For example, the original data spacing is 2 and there are 200 slices, when I
change the slice thickness value to 4 I have to see 100 slices.
Original: 1,2,3,4,5...
Modified: 1, 2, 3...
My code:
if ((modif & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) {
etat = 1;
int nb0 = imageViewer.GetSlice() + 1;
int nb1 = imageViewer.GetSlice() - 1;
int totSlice = imageViewer.GetSliceMax() + 1;
if (p1.y > p2.y) {
String Newligne=System.getProperty("line.separator");
cornerAnnotation.SetText(0,"Slice:" + (nb0 + 1) + "/" + totSlice+Newligne+"Zoom: "+(int)(100)+"%"+Newligne+ "C:" + windowhight + " / W:" +windowlevel+ Newligne+"Pixel:("+xs+":"+ys+")"+Newligne+reader.GetModality()+"("+reader.GetOutput().GetDimensions()[0]+"*"+reader.GetOutput().GetDimensions()[1]+")"+"-Axial"+Newligne);
imageViewer.SetSlice(nb0);
scrollBar.setValue(imageViewer.GetSlice());
} else {
String Newligne=System.getProperty("line.separator");
cornerAnnotation.SetText(0,"Slice:" + (nb1 + 1) + "/" + totSlice+Newligne+"Zoom: "+(int)(100)+"%"+Newligne+ "C:" + windowhight + " / W:" +windowlevel+ Newligne+"Pixel:("+xs+":"+ys+")"+Newligne+reader.GetModality()+"("+reader.GetOutput().GetDimensions()[0]+"*"+reader.GetOutput().GetDimensions()[1]+")"+"-Axial"+Newligne);
imageViewer.SetSlice(nb1);
scrollBar.setValue(imageViewer.GetSlice());
}
}
If you actually change the slice thickness in the DICOM attributes, you likely will have to change the image position (patient) and slice location DICOM attributes as well in order to keep the image volume consistent.
If you are just trying to move slices based on a certain distance (e.g. one click = 4 mm instead of 2 mm), then keep track of the position of the slice instead of the slice number. When the position changes, then compute the new slice for the new position and update to that slice. This will allow more flexibility as well.
If you really just want to step every other slice, then why not just use nb0 = getSlice() + 2 and nb1 = getSlice() -2?
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I'm doing a Java exercise, and I need to display a persons height in both inches and cm, as well as their weight in both pounds and kg.. Here's what I came up with, but I'm getting tons of errors.
Height = 74; // inches
Weight = 180; // pounds
System.out.println( "He's " + Height + " inches or + (Height * 2.54) cm tall "." );
I got the 2.54 by just googling what the conversion was for inches to cm. I basically did the same thing for the weight (see below)
System.out.println( "He's " + Weight + " pounds or + (Weight * 2.20) kg heavy "." );
My goal is to get it to display:
He's 74 inches (or 187.96 cm) tall.
He's 180 pounds (or 81.6466266 kg) heavy.
Any help would be great, and sorry for such a basic question!
There are a couple of glaring syntax errors here:
System.out.println( "He's " + Height + " inches or + (Height * 2.54) cm tall "." );
Notice how the syntax highlighting on this page points them out. (Your IDE really should be doing that too.) You close a string at the end, then have a random . character and open another string which you never close.
You can fix the syntax errors by removing a quote:
System.out.println( "He's " + Height + " inches or + (Height * 2.54) cm tall ." );
However, this doesn't yet give you the output you want. Because this is just a string:
" inches or + (Height * 2.54) cm tall ."
Java isn't going to perform that calculation, as far as Java is concerned this is just text. You need to separate the string just like you already are for your other use of the variable:
System.out.println( "He's " + Height + " inches or " + (Height * 2.54) + " cm tall." );
System.out.println( "He's " + Height + " inches or ("+ (Height * 2.54)+" ) cm tall." );
Remember that you must do the conversion (without Strings quotes) before concatenate with text. The final dot is not needed.
First off, you need to define what datatype your variables are. You can't have "Height", you need to have "int Height".
It's also easier if you set variables for both height and weight in their respective units. So you should have a variable for height in inches, and then a variable for height in centimeters.
Here's my solution:
public static void main(String[] args) {
int inHeight = 74;
double cmHeight = inHeight * 2.54;
int lbWeight = 180;
double kgWeight = lbWeight / 2.2;
System.out.println("He's " + inHeight + " inches (or " + cmHeight + " cm) tall.");
System.out.println("He's " + lbWeight + " pounds (or " + kgWeight + " kg) heavy.");
}
Note: two of the variables are doubles, so if you want to correctly format those to two decimal places, you'll have to use "printf" instead of "println".
You're writing text instead of a variable's value:
System.out.println( "He's " + Height + " inches or + (Height * 2.54) cm tall "." );
Change it to:
System.out.println( "He's " + Height + " inches or (" + (Height * 2.54) + " cm) tall.");
The same goes for the weight line:
System.out.println( "He's " + Weight + " pounds or + (Weight * 2.20) kg heavy "." );
Should be:
System.out.println( "He's " + Weight + " pounds or (" + (Weight * 2.20) + " kg) heavy.");
And please follow Java naming conventions:
Except for variables, all instance, class, and class constants are in mixed case with a lowercase first letter. Internal words start with capital letters. Variable names should not start with underscore _ or dollar sign $ characters, even though both are allowed.
From the above: variable names should start with a lower case
You should also read How to concatenate characters in Java
This might answer your question, it is a bit vague, so I am mostly guessing.
System.out.println( "He's " + Height + " inches or (" + Height * 2.54 + ") cm tall." );
You had formatted your println pretty badly. It is the same for the later one, I suggest having a look at it and figuring that one out by yourself.
Also I have no clue of what unit of measurement you are using for your Weight and Height, I recommend a double for this scenario. If you want more precision you have to look up on BigDecimal.
Normally variables and fields are written in lowerCamelCase in Java.
try this:
System.out.println( "He's " + Height + " inches or " + (Height * 2.54) + " cm tall "." );
Double Height = 74D; // inches
Double Weight = 180D; // pounds
System.out.println( "He's " + Height + " inches or " + (Height * 2.54) + " cm tall "." );
System.out.println( "He's " + Weight + " pounds or " + (Weight * 2.20) + " kg heavy "." );
I need the size of the black part of this image:
I've done some research about how to find it in normal math, and I was pointed to this website: Website
The final answer on getting it was
(from MathWorld - A Wolfram Web Resource: wolfram.com)
where r is the radius of the first circle, R the radius of the second circle, and d the distance between the two centers.
The code I tried to use to get the size of this was the following:
float r = getRadius1();
float R = e.getRadius1();
float deltaX = Math.abs((getX() + getRadius()) - (e.getX() + e.getRadius()));
float deltaY = Math.abs((getY() + getRadius()) - (e.getY() + e.getRadius()));
float d = (float) Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
float part, part2, part3;
//Chopping it in parts, because it's easier.
part = (float) (Math.pow(r,2) * Math.acos(
Math.toRadians((Math.pow(d, 2) + Math.pow(r, 2) - Math.pow(R, 2))/(2*d*r))));
part2 = (float) (Math.pow(R,2) * Math.acos(
Math.toRadians((Math.pow(d, 2) + Math.pow(R, 2) - Math.pow(r, 2))/(2*d*R))));
part3 = (float) (0.5 * Math.sqrt((-d + r + R) * (d+r-R) * (d-r+R) * (d+r+R)));
float res = part + part2 - part3;
Main.log(res + " " + part + " " + part2 + " " + part3+ " "
+ r + " " + R + " " + d);
//logs the data and System.out's it
I did some testing, and the output was this:
1345.9663 621.6233 971.1231 246.78008 20.0 25.0 43.528286
So that indicates that the size of the overlapping part was bigger than the circle itself (which is r^2 * PI).
What did I do wrong?
Just a guess (as stated in my comment): try removing the Math.toRadians(...) conversion.
Since there are no degrees involved in the formula but rather radii, I assume the parameter to cos-1(...) is already a value in radians.
If I remove the conversion and run your code, I get the following overlap area size: 11.163887023925781 which seems plausible since the length of the overlap segment on the line between the two centers is 20 + 25 - 43.5 = 1.5 (approximated)
Edit:
If I set the distance to 5 (the smaller circle is completely contained in the bigger one but touches its edge) I get the overlap area size 1256.63 which is exactly the area of the smaller circle (202 * Π). The calculation doesn't seem to work if the distance is smaller than the difference of the radii (i.e. in your case smaller than 5), but that might just be a problem of numerical representation (the normal datatypes might not be able to represent some of the intermediate results).