background:
As mentioned in the previous column, using CGI or fastcgi technology to forward user requests sent by the browser, initiate local DCMTK and Cximage library responses, and then convert the processing results to a regular image back to the browser to implement the Web PACS. This blog post uses the actual code test to verify the feasibility of this model, and raises some questions about the C language writing CGI script.
Challenges:
Plan to refer to the source code of DCMTK's own tool dcm2pnm.exe, convert DCM files to BMP files via Dicomimage, and then return to the browser using CGI technology. Implementation of a simple Web PACs image transmission simulation. The specific code is as follows,
Dcmtk-save-test.cpp: Defines the entry point of the console application. #include "dcmtk/config/osconfig.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk/dcmdata/dcpxitem.h" #include " Dcmtk/dcmjpeg/djdecode.h "#include" dcmtk/dcmjpeg/djencode.h "#include" dcmtk/dcmjpeg/djcodece.h "#include" dcmtk/ Dcmjpeg/djrplol.h "#include" dcmtk/dcmimgle/diutils.h "#include" dcmtk/dcmimgle/dcmimage.h "void Sendimagedcmtk (char * filename) {Dcmfileformat mdcm;mdcm.loadfile (filename); E_transfersyntax Xfer = Mdcm.getdataset ()->getoriginalxfer (); unsigned long mode = Cif_maydetachpixeldata | Cif_takeoverexternaldataset;dicomimage *di = new Dicomimage (&mdcm,xfer,mode,0,0), if (di = = NULL) {print2web ("Can Not open DCM file by dicomimage! ");} printf ("content-type:image/bmp\n\n");d i->writebmp (stdout,24,0);} int main (int argc, char* argv[]) {char* filename= "C:\\TEST.DCM"; SENDIMAGEDCMTK (filename); return 0;}
Compile the CGI program that generates Dcm2bmp.exe, copy it to the CGI directory of the website (my native address is c:\wamp\www\c-cgi), and enter the CGI program on the server by entering Http://localhost/c-cgi/dcm2bmp.exe in the browser. Although the program started smoothly, but did not get the result we wanted-output a strange image, as shown below: The image on the left is the real DCM image seen in the view of PACs, and the picture on the right is the one I failed to transfer to the browser.
Validation Test:
Having obtained the wrong result, at first did not think of a good way to eliminate the wrong, then decided to first confirm the approximate scope of the problem. Since most of the books that introduce CGI are implemented in Perl or PHP, the use of Perl and PHP to implement a normal transfer of images to the browser is a good way to verify that the mechanism is feasible by imitating the examples in the book. The following is the actual test procedure,
(1) Perl version of CGI
#!c:/perl64/bin/perl.exeuse warnings;use strict;binmode stdout;print "content-type:image/bmp\n\n"; open FILE, ' < ', ' C:\test.bmp ' or die ' Can ' t open file, while (my $buf = <FILE>) { print $buf;} Close (FILE);
After testing, you can output the correct image.
(2) PHP version of CGI
<?php$filename= "C:/test.bmp"; $size =getimagesize ($filename); $fp =fopen ($filename, "R"); #echo $size [' MIME '];if ($ Size && $fp) {header ("content-type:image/bmp\n\n"); Fpassthru ($fp); exit;}? >
After testing, you can also output the correct image.
Results Analysis:
Through the above two tests, it is sufficient to demonstrate that wamp+cgi/fastcgi environment is not a problem. Therefore, it can be concluded that the problem appears in the C language of the CGI script program, because the CGI script is the server console program, you can debug directly in the command line, but we use Dicomimage's writebmp function to export the converted BMP image to the stdout, The actual debugging will output a bunch of garbled characters, because stdout default is ASCII format, so the idea of debugging CGI script on the command line is not feasible. So decided to start at the bottom, using the RawCap.exe tool, grab the packet between the browser and the server-side CGI program, and analyze the packet to see where the problem occurred.
1) Rawcap+wireshark Local Grab pack + analysis
Rawcap's operation was introduced in the earlier blog post, which is not described in detail here. After entering RawCap.exe on the command line, select the [2] interface, That is, the local loop 127.0.0.1 packets, you can start to crawl local loop packets, also according to the method of testing CGI in front of the blog, respectively, the output error written in the C language of the CGI program and the output of PHP written in the correct CGI program, the captured packets are Wrongimage.pcap and RI Ghtimage.pcap, to end the crawl, you can enter CTRL + C.
After the crawl is complete, open Wrongimage.pcap and Rightimage.pcap in Wireshark, where you are directly using the statistical analysis tool in Wireshark because you only care about packet problems with the image transmission. To do this, click Statistic in the menu bar, select Session--conversations, and open the session window:
Then click on the TCP protocol, select the session where the data volume is large, click the follow stream below the window to open the CGI script to transfer the image to the service side of the real data stream.
Using follow stream to track data flows in both Wrongimage.pcap and Rightimage.pcap, the comparison results are as follows:
You can see the real image transfer data stream, compare left (correct image) and right (error image), you can see that two data streams indicate that they are BMP files, with 0x42 4D type marker. According to the BMP file structure, it is followed by a color table, as shown in the large red rectangular box. However, careful observation can be seen in the error image of the 0a 0a 0a color table entries into the 0d 0a0d 0a 0d 0a xx, through the search error data flow found that the original data flow in the presence of 0a is replaced by 0d 0a. It is therefore concluded that this should be the cause of the image transmission failure.
For a good understanding of the causes of the above errors, here are some additional basics, which can be found in post-blog URLs.
2) Knowledge point supplement:(1) Text files VS binary files
As we all know, the computer is two, only 0 and 1, anything in the computer is stored in 0 and 1 way, so why also distinguish between text files and binary files? I understand that, although the bottom of the computer is stored in binary format, but we can customize the different interpretation standards, the same 0 and 1 sequence, the interpretation of different ways, the meaning of the expression is different . In fact, the use of different standards to interpret the same sequence of phenomena in the computer field is very common. In a 32-bit machine, the same four-byte 01 sequence may represent an unsigned integer or a signed integer (in the C + + language) or an IP address (in socket programming) or a label or delimiter (the label of an object in the DICOM protocol is in four-byte format, As 0x0002 0010 represents the Transfersyntax UID). The colorful and changeable information world originates from different interpretation standards or interpretation rules. So learn the standards and understand the actual application scenarios.
Text files and binaries can be understood as 01 sequences that apply different standard stores, and text files mean that all information is stored in ASCII format, each byte corresponds to an ASCII character-- ASCII is people can be directly read out (of course, we can recognize the text is also in the computer through a number of conversions, it can be easily understood as a different 01 sequence, the computer to the screen drawing corresponding graphics-graphics generation can be easily understood as a plurality of adjacent crystal light to achieve) Whereas a binary file refers to storing the actual 01 sequence intact, without any processing (which is a way of interpreting it). So the distinction between a text file and a binary file is a declaration, a declaration that tells the 01 sequence to be interpreted. To make an inappropriate analogy, the 01 sequence is like a telegram sent by an enemy, while "text files" and "binary files" represent two cipher books, and the same telegram is translated with different passwords, and the results and meanings are naturally different (of course, there is usually a failure to provide us with valid information).
(2) CRLF
In programming languages, text files and binary files represent different ways of doing things, or simply can be understood as using different functions. Through the above explanation, we can think that the internal function of different functions is to operate on 01 sequences according to different standards (text file standard and binary file standard), such as reading, writing and so on. --there are times when there's no need to tangle with the result of a function, just remember that this is what the definition behind the function is, and there is no need to delve into the standard, in short, a wave of bull-men.
The error two bytes above--0x0d 0x0a--is a very special two bytes in the computer, they represent the carriage return (cr=carriage return) and the line feed (lf=line Feed)respectively. Different systems have different interpretations of CRNL. The first UNIX system used only a newline (that is, \ n) to represent another row of data, and the Windows system uses carriage return + line feeds , while the Mac system uses only carriage returns , which is \ r.
When a file is read from disk to memory (program data area or buffer), in the text and binary mode, the contents of the memory are generally different, which is the substantive difference between the two open methods. because of the different CRLF, under Windows, it will do a processing, that is, when the file is written, the newline character will be converted into a carriage return + newline character exists on the disk file, and read the file on the disk, it will reverse processing, is the file in the continuous carriage return + newline character converted to line feed. therefore, when reading a disk file, the text read to the file content is likely to be shorter than the binary file, because the text read to the carriage return and newline two characters into a character, equivalent to truncate the file. But why is it just possible? Because there may not be a connection in the text of the 0x0d,0x0a two bytes (0x0a is the ASCII code of CR carriage return, 0x0d is the ASCII code of the newline character Cl), there is no "truncated" operation, so read the content is the same. Specifically, file files (written in text form) are best read in text. binary files (written in binary mode), preferably read in binary mode.
(3) stdin, stdout
From (2) The knowledge point can be roughly judged that the Windows system when writing to stdout BMP data stream, will encounter 0x0a replaced with 0x0d 0x0a, he thought here change line. so why would 0x0a be converted to 0x0d 0x0a when writing to the STDOUT data stream? Is there a way to not convert? here is a simple introduction to the standard input and output stream in C, we all know that stdin is bound to the keyboard by default; StdOut is bound to the display by default. In fact, stdin and stdout are the same type of file* that we use to manipulate files, which can be thought of as a buffer between the program and the keyboard and display information. What's special is that in the CGI architecture, stdin and STDOUT are responsible for interacting with the browser and the server.
Since stdin and stdout are no different from ordinary file*, can we control the way we write stdout to restrict the system from converting 0xa to 0x0d 0x0a, based on our understanding of text format and binary format? Because the display by default is the character type of output, inconvenient debugging, we use a file file* instead of stdout, and then through a different writing method to verify the conjecture we just made. The input file of the test (that is, the data we read into the memory first) is a BMP image that is converted using the Dcm2pnm.exe tool, and we select the "RB" binary mode when reading the file in order to limit the conversion of the Windows system to CRLF. The test code is as follows:
As shown, the binary method can be written with the correct image, and the text format is exactly what we encountered in the previous error results. So it can be explained that in the process of writing data to stdout, Dicomimage uses the text format, should be written in binary mode stdout, presumably can get the correct results.
3) Try to modify the C language version of the CGI program:
Now that we have found the root cause of the problem, we will revise the CGI program of C language. Known stdout and file* the same, then directly using the common C language file operation function, the binary way to output data to stdout, to verify our ideas. The test code is as follows:
Dcmtk-save-test.cpp: Defines the entry point of the console application. #include "dcmtk/config/osconfig.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk/dcmdata/dcpxitem.h" #include " Dcmtk/dcmjpeg/djdecode.h "#include" dcmtk/dcmjpeg/djencode.h "#include" dcmtk/dcmjpeg/djcodece.h "#include" dcmtk/ Dcmjpeg/djrplol.h "#include" dcmtk/dcmimgle/diutils.h "#include" dcmtk/dcmimgle/dcmimage.h "#include <stdio.h> #include <iostream> #include <iomanip> #include <bitset> #include <windows.h>using std::cout; Using std::bitset;using std::hex;void print2web (char* msg) {printf ("content-type:text/html\n\n");p rintf ("<HTML >\n ");p rintf (" After many of the above attempts, found that the data is still problematic, so guess the C language file operation function may have a special operation on the stdout write, unable to implement the binary format to write. At this point in the C language environment is still unresolved, if any friend knows the reason, please do not hesitate to enlighten . I will continue to analyze the follow-up and hope to find out the reasons as soon as possible.
To be Continued ...
References:
[1]http://blog.csdn.net/silyvin/article/details/7275037
[2]http://blog.csdn.net/lanbing510/article/details/8183343
[3]http://www.jb51.net/article/31458.htm
[4]http://blog.csdn.net/babygjx/article/details/5832235
Follow-up Column blog introduction:
Using DCMTK to build WML servers
Direct operation of DICOM data with Oracle
Application of the asynchronous programming pattern of C # in fo-dicom
Practical testing of VMware three network connection modes
[email Protected]
Date: 2014-10-27
DICOM Medical Image processing: A preliminary talk on WEB PACs two, image transmission