I am trying to create a Manga viewer which needs to load JPG images with large sizes like 1000*16000, my application is in delphi FMX and i have already tried using TImage, TImageViewer, TImageControl but all of them use TBitmap which trims the size to 8192 after loading the image
I tried searching for image libraries but i was unable to find anything for FMX (firemonkey)
I was thinking maybe i could load the image in a Memory stream and then copy and draw it in smaller sizes to several bitmaps ? but i don't how can i read and parse the memory stream and only pick to a certain clean height !
In the end i'm looking for a way to load and show these large (1000*16000) images in Delphi FMX
I am using delphi 10.2.3
Thanks.
Edit 01 :
I think i have found a way that might make things easy, i added the Vcl.Imaging.jpeg to uses clause in the FMX (FireMonkey) and then i used TJPEGImage and loaded the image, and i printed the width and height and they are correct and not trimmed ! so i was thinking, maybe i can read each pixel from TJPEGImage.canvas and then print it into FMX TBitmap ?, what do you think about this approach ?, do you know a good way to copy the data inside TJPEGImage to FMX TBitmap ?
Edit 02 :
I have found a new solution, the TBitmapSurface, it seems this class doesn't have the TBitmap limitations and i was able to load the image inside of it without getting trimmed ! but there is a problem! how can i give this to TImage ? if i simply say Image.bitmap.assign(TBitmapsurface), then the image gets trimmed again ! so it seems the only possible way is rewriting the TImage so it uses TBitmapSurface instead of TBitmap, any help regarding this issue is appreciated, thanks.
Here is the code for the TBitmapSurface :
bitmapSurf := TBitmapSurface.Create;
TBitmapCodecManager.LoadFromFile(path, bitmapSurf);
Unlike FMX.Graphics.TBitmap which has a size limitations of 8192 * 8192, FMX.Surface.TBitmapSurface seems to support up to 16k * 16k and possibly even more (i haven't tested), so using FMX.Surface.TBitmapSurface you can load the image without getting trimmed, and then you can easily split it into two FMX.Graphics.TBitmap (or possible more parts using the same approach)
Below you can see the code which first loads the JPG into TBitmapSurface, and then the code which splits that into two TBitmap :
var
srce, dest: TBitmapSurface;
path: string;
scan: integer;
w, h1, h2: integer;
begin
path := 'C:\tmp\Imgs\res.bmp';
srce := TBitmapSurface.Create;
TBitmapCodecManager.LoadFromFile(path, srce);
dest := TBitmapSurface.Create;
// first half
w := srce.Width;
h1 := srce.Height div 2;
dest.SetSize(w, h1, TPixelFormat.RGBA);
for scan := 0 to h1-1 do
Move(srce.Scanline[scan]^, TBitmapSurface(dest).Scanline[scan]^, srce.Width * 4);
Image1.Bitmap.Assign(dest);
// second half
h2 := srce.Height - h1;
dest.SetSize(w, h2, TPixelFormat.RGBA);
for scan := h1 to srce.Height-1 do
Move(srce.Scanline[scan]^, TBitmapSurface(dest).Scanline[scan-h1]^, srce.Width * 4);
Image2.Bitmap.Assign(dest);
end;
This answer was provided using the comments on the first post and the answer to my other question:
How to draw FMX.Surface.TBitmapSurface on FMX.Graphics.TBitmap
Related
So, I'm kind of experimenting with image-manipulation at the byte-level (No 'Image' wrapper or libraries), so the language doesn't matter (I'm using C#) as much as the byte-manipulations, themselves.
I'm now trying to flip a a .jpg image (minus the magic number) over the x- and y-axis, but realized after some trial and error that I think the encoding is getting in the way. This is the code I'm using on a byte[] without the FF D8 or FFD9 includes:
//No magic number included
public class MirrorImgOverXAndYAxes : IFunction
{
//No magic number included
public byte[] Exec(byte[] jpgImage)
{
byte[] resultingImage = new byte[jpgImage.Length];
for (var i = jpgImage.Length - 1; i >= 0; i--)
{
var indexToInsert = jpgImage.Length - 1 - i;
resultingImage[indexToInsert] = jpgImage[i];
}
return resultingImage;
}
}
Right now, my assumption is that it's nowhere near as easy as this, and that I would have to build a full-blown decoder to be able to manipulate the image bytes like this.
Is it possible to create this mirror image without a decoder and would something like what I'm doing work?
Hi I guess just flipping a jpeg by switching the bytes position will not really work here, due to how jpg files are actually structured. if you want to learn more about that, you can look here enter link description here
But you could try to convert the image to a format that actually saves it's pixels within a single byte. For example bitmaps (.bmp).
There is no simple way to do a mirror image that will work in general without decoding.
One problem is that JPEG images are encoded in MCUs that are in turn composed of blocks of eight by eight pixels. For simplicity assume the MCU is an 8x8 block the image width is 15 pixels. That means there will be a dummy column off the edge. If you just flip that, the dummy column will be visible and an image column will be off the edge.
I'm currently working on a little game written in JS using Pixi.js(https://github.com/pixijs). One Problem has occured currently, I'm trying to implement pixel exact collision between shapes, while I was programing a little I noticed that all the pixel RBGA values of my images are just 0.
I searched on the web but for a while but the only reason for those Problems I could find was that the canvas was tainted because of CORS(Pixel RGB values are all zero).
But this can't be the reason in my case because I created the sprites myself, I'm not loading them from other (any) domains or something like that.
Could this be a problem with the images? How do I avoid that? I will append some code that works if I use other images (some images I downloaded for tests).
const app = new PIXI.Application({width: 500, height: 500});
document.body.appendChild(app.view);
PIXI.loader.add("sprites/test.png")
.load(() => {
let img = new PIXI.Sprite(PIXI.loader.resources["sprites/test.png"].texture);
app.stage.addChild(img);
console.log(app.renderer.extract.pixels(img));
});
Edit: I tried getting the RGBA values using a short Java Program btw, same problem. Every single value is zero.
I find ABCPDF is very capable. However, so far I had not managed to find a way to draw one PDF into another with rounded corners - until now. But, the approach I discovered depends on getting the correct PDF object id for the inserted PDF stream, and herein lies the reason for this question.
Anyone who knows ABCPDF will ask why that is an issue ? Does not the addImageDoc() function which embeds one PDF inside another return the PDF object ID ? No - it returns something else - most likely the inserted PDF goes into the document catalogue as an isolated object and what you get in the returned ID is an object that refers to it. Unpacking the document streams seems to bear this out.
Long story short, in my experimenting I found that I needed to insert into the stream a 'Do' call, with the target of that derived as:
imgObjId = addImageDoc(some pdf object) // inserted off-page
insert into stream "/Iabc<imgObjId + 1> Do"
For example, if the returned imgObjId value is 5 then I need it to be 6 to make
/Iabc6 Do
Question: Whilst this works OK, I am relying on adding one to the returned value and I wonder how robust that is going to be. Or is there a correct way to achieve this ?
More info: I have kept the question short but readers may be wondering why the above matters? Because to achieve rounded corners you need to construct a stream of PDF commands which has a clipping region defined. Think of a path for a rectangle with Bezier curves for the corners. Having got that, you need to draw an image, or in my case another PDF, into the same context so as to get the clipping effect. After that you can close and reset the graphics state and be a good PDF stack citizen. However, there is no means, other than my approach above, that I can find in ABCPDF to get a handle on the inserted PDF doc stream in the catalogue so as to be able to ask for it to be drawn somewhere else.
Inserting an image seems to be a similar process, except the getinfo() function can discover the pixmap. There appears to be no like approach for an embedded PDF.
I don't know if you can change the target abcpdf rectangle prior to do a "AddImageDoc".
Maybe you can do a trick, getting a Bitmap from the source, editing it by changing borders, and adding to a new doc. Something like this:
Dim oDoc As New WebSupergoo.ABCpdf10.Doc
Dim oImg As System.Drawing.Bitmap
oDoc.Read("D:\source.pdf")
oImg = oDoc.Rendering.GetBitmap()
' image quality can be improved with .Rendering properties as 'AntiAliasImages', etc.
oDoc.Dispose()
oDoc = Nothing
Dim oGraph As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(oImg)
Dim gPath As New System.Drawing.Drawing2D.GraphicsPath
Dim oBrush As New System.Drawing.SolidBrush(System.Drawing.Color.Red) ' only to see the rectangle... white when be ready
gPath.AddRectangle(New System.Drawing.Rectangle(0, 0, oImg.Width, oImg.Height))
' 2 / 100 it's the percent factor for borders
Dim iLeftBorder As Integer = CInt(2 / 100 * (oImg.Width / 2))
Dim iTopBorder As Integer = CInt(2 / 100 * (oImg.Height / 2))
gPath.AddEllipse(New System.Drawing.Rectangle(iLeftBorder, iTopBorder, oImg.Width - (iLeftBorder * 2) - 1, oImg.Height - (iTopBorder * 2) - 1))
oGraph.FillPath(oBrush, gPath)
oBrush.Dispose()
oGraph.Dispose()
oDoc = New WebSupergoo.ABCpdf10.Doc
oDoc.AddImageBitmap(oImg, False)
oDoc.Save("D:\finalpath.pdf")
oDoc.Dispose()
oDoc = Nothing
But it's only a "trick".
I have such code
source.Picture.LoadFromFile(fName);
buffer.Assign(source.Picture.Bitmap);
buffer.Canvas.CopyRect(rect(0,0,buffer.Width,buffer.Height), target.Canvas, rect(0,0,buffer.Width,buffer.Height));
And it won't work.
There are better ways to load image, but I want to play with them.
The main reason is to load smaller images,
So it's correct to copy canvas rect, but it not shows single pixel...
Objects are initialized and scaled except for target which I want to contain more than one image.
I supose there is no need for writing what types are objects, all needed are classes procedures that shows what are what.
I wonder whats wrong? I tried many ways, but simple nothing.
Please help.
Probably source is TImage, buffer is TBitmap, target is also TImage (you should mention it in your question so we don't have to guess).
In this case, the second line would work only when you load from .BMP because only these have bitmap populated. If you have .png or .jpeg instead, the second line would erase the actual picture and replace it with empty bitmap... Not very intuitive behaviour but it's documented at least.
To work with arbitrary graphic, you should use TCanvas.Draw method which in turn calls TGraphic.Draw(). As you can see from description, it draws the graphic you loaded into the canvas at given rectangle. Something like that:
source.Picture.LoadFromFile(fName);
target.Canvas.Draw(0, 0, source.Picture.Graphic);
UPD.
If you want to scale arbitrary picture, it could be done this way:
source.picture.loadFromFile(fName);
buffer.Width := source.picture.Width;
buffer.Height := source.picture.Height;
buffer.PixelFormat := pf24bit;
buffer.Canvas.Draw(0, 0, source.picture.Graphic);
//so we at last have bitmap containing our image in original size
target.Canvas.CopyRect(Rect(0, 0, NewWidth, NewHeight), buffer.canvas, Rect(0, 0, buffer.Width, buffer.Height));
Here NewWidth and NewHeight are image size we want.
By the way, you don't need source: TImage if it is just temporary object to load from file. TPicture would be enough:
var pic: TPicture;
pic := TPicture.Create;
try
pic.LoadFromFile(fName);
...
buffer.Canvas.Draw(0, 0, pic.Graphic);
finally
pic.free;
end;
I wrote an OPENCV project in VS2010 and the results were not the ones as I expected so I ran the debugger to see where is the problem. When I wanted to see the data inside the image loaded I didn't know how to do it so if I want to see the data inside my images what should I do?
It is pretty simple in matlab for seeing different channel of an image i.e.
a=imread('test.jpg');
p1 = a(:,:,1)
p2 = b(:,:,2)
.
.
In opencv I wrote the same thing but I don't know how to see all the element at once just like Matlab.
a= imread("test.jpg")
split(a,planes);
vector<Mat> T1;
T1 = planes[0];
// How can I see the data inside T1 when debugging the code ?
I think this is what you are looking for - it's a great Visual Studio add-on
https://bitbucket.org/sergiu/opencv-visualizers
Just download the installer, make sure VS is closed, run it, re-open VS and voila! Now, when you point to an OpenCV data structure, all kinds of nice info is showed.
Limitations: I saw some problems with multichannel images (it only shows the first channel) and it also has trouble displaying large matrices. If you want to see raw data in a big matrix, you can use the old good VS trick with debug variables: Stop at a breakpoint, go to Watch tab, and write there
((float*)myMat.data) ,10
Where float is the matrix type, myMat is your matrix, and 10 is the number of values you want to print. It will display the first 10 values at the memory location of myMat.data. If you do not correctly choose the data type, you'll see garbage. In my example, myMat is of type cv::Mat.
And never forget the power of visualizers:
imshow("Image", myMat);
If your data fits into an image. You can use the contrib module's colormap to enhance your visualizers.
I can't actually believe that nobody suggested Image Watch yet. It's the most amazing add-in ever. It shows you a view with all your Mat variables (images (gray and color), matrices) while debugging, there's useful stuff like zooming or contrast-stretching and you can even apply more complex functions directly in the plugin in real-time. It makes debugging of any kind of image operations a breeze and it's immensely helpful if you do calculations and linear algebra stuff with your cv::Mat matrices.
I recommend to use a NativeViewer extension. It actually displays the content of an image in a preview window, not only the properly formatted info.
If you don't want to use a plug-in or extension to Visual Studio, you can access the elements one by one in the debugging watch tab by typing this:
T1.data[T1.step.buf[0]*i + T1.step.buf[1]*j];
where i is the row you want to look at and j is the column.
after downloading imagewatch use the command in watch window
(imagesLoc._Myfirst)[0]
index of image in the vector
You can use the immediate window and the extenshion method like this one
/// <summary>
/// Displays image
/// </summary>
public static void Display (this Mat m, Rect rect = default, string windowName = "")
{
if (string.IsNullOrEmpty(windowName))
{
windowName = m.ToString();
}
var img = rect == default ? m : m.Crop(rect);
double coef = Math.Min(1600d / img.Width, 800d / img.Height);
Cv2.ImShow(windowName, img.Resize(new Size(coef * img.Width, (coef * img.Height) > 1 ? coef * img.Height : 1)));
Cv2.WaitKey();
}
Then you stop at a breakpoint and call yourImage.Display() in the immediate window.
If you can use CLion you can utilize the OpenCV Image Viewer plugin, which displays matrices while debugging just on click.
https://plugins.jetbrains.com/plugin/14371-opencv-image-viewer
Disclaimer: I'm an author of this plugin