Chuyển đổi tàiliệuPDF sang Word 01:07' 22/11/2005 (GMT+7) Word đã trở thành "vua" của các bộ soạn thảo văn bản. Hầu hết các văn bản đều được định dạng và in bằng Word. Tuy nhiên, bạn có một số văn bản bằng PDF (Portable Document Format), bạn muốn chỉnh sửa các tàiliệu này trước khi in ấn. Acrobat Reader không có khả năng chỉnh sửa văn bản, còn Acrobat thì giá cả hơi "mắc" mà lại đòi hỏi tài nguyên khá lớn. Vậy, có phần mềm nào có khả năng chuyển đổi định dạng từ PDF sang Word mà vẫn giữ nguyên định dạng, giá cả cũng chấp nhận được và lại tiêu tốn ít tài nguyên hệ thống ? Thực ra, để giữ nguyên các định dạng tàiliệu sau khi chuyển đổi là rất phức tạp và khó khăn. Đến ngay như phần mềm Acrobat, khi chuyển đổi tập tin PDF sang Word cũng không được hoàn hảo. Tuy nhiên, nếu bạn đã từng sử dụng qua phần mềm SolidPDFConverter của hãng Solid, phần mềm này thật tuyệt vời ! Các tàiliệu phức tạp gồm các nội dung văn bản, hình ảnh, bảng tính . vẫn giữ nguyên định dạng sau khi chuyển đổi sang Word. VietNamNet đã thử nghiệm chuyển đổi tàiliệu phức tạp gồm hình ảnh, bảng biểu , đồ hoạ, văn bản xen kẽ, khoảng 70 trang bằng Adobe Acrobat và SolidDPFConverter. Kết quả là SolidPDFConverter cho tốc độ chuyển đổi tàiliệu nhanh hơn và giữ được định dạng tàiliệu gốc chính xác hơn Acrobat. Tuy nhiên khi chỉnh sửa một số văn bản kết hợp trong các bảng biểu, đồ hoạ cho kết quả chưa được tốt lắm. Mặc dù vậy SolidPDFConverter vẫn là công cụ đáng giá với mức giá tương đối rẻ so với phần mềm đồ sộ tương đối "nặng ký" Acrobat. SolidPDFConverter có đồ thuật đơn giản sẽ giúp bạn chuyển đổi định dạng .pdf sang định dạng .doc nhanh chóng chỉ với 5 bước: Bước 1: Chọn định dạng Bạn hãy chọn tập tin PDF cần chuyển đổi ngay trong khung tìm tàiliệu của SolidPDFConverter. Hãy sử dụng tùy chọn: • Flowing: Với chế độ này, các trang vẫn giữ nguyên cách trình bày, định dạng, đồ họa và các dữ liệu văn bản. • Continuous: Với chế độ này cái mà bạn cần chỉ là nội dung chứ không cần chính xác cách trình bày của tài liệu. Ví dụ: giả sử mục đích là bạn cần nội dung cho những trang có kích thước khác hoặc các phần mềm trình diễn như Power Point hoặc chuyển sang định dạng HTML. Chế độ này sẽ sử dụng cách phân tích trình bày trang và cột để xây dựng lại thứ tự các văn bản nhưng chỉ phục hồi định dạng đoạn, đồ họa, và dữ liệu văn bản. • Plain Text: Nếu bạn chỉ cần văn bản mà không cần định dạng hay trình bày, bạn hãy sử dụng Plain Text. Plain Text sẽ phục hồi các định dạng kí tự, đoạn hoặc đồ họa nhưng chỉ phục hồi văn bản bằng phân tích cột và trình bày trang. • Exact: Nếu bạn cần một tàiliệu Word trông giống hệt như tàiliệu PDF? Bạn cần thay đổi nhỏ các tập tin này? Exact sử dụng các TextBox của Word để đảm bảo chắc chắn văn bản và đồ họa vẫn giống y nguyên bản PDF gốc.Chế độ Exact không nên sử dụng nếu bạn cần chỉnh sửa rất nhiều nội dung từ BridgepatternBridgepattern Bởi: Wiki Pedia Dạng thức bắc cầu dạng thức thiết kế dùng công nghệ phần mềm Dạng thức bắc cầu dùng để "tách riêng tính trừu tượng khỏi thực thể hai thay đổi cách độc lập" (Gamma et al.) Dạng thức bắc cầu dùng tính đóng, tính kết hợp, dùng tính kế thừa để tách riêng việc xử lí (trách nhiệm) giao cho cho lớp khác Khi mà lớp thường xuyên bị thay đổi, đặc tính lập trình hướng đối tượng trở nên hữu ích thay đổi mã lệnh chương trình thực dễ dàng với công sức việc tìm hiểu toàn chương trình Dạng thức bắc cầu hữu ích không thân lớp thay đổi thường xuyên mà công việc mà thực thay đổi Bản thân lớp xem trừu tượng mà lớp thực thực Khi mà trừu tượng thực tách riêng thay đổi không phụ thuộc Một ví dụ hay dạng thức thiết kế bắc cầu tác phẩm Design Patterns Explained: A New Perspective on Object-Oriented Design Shalloway Trott Giả sử bạn có trừu tượng, shapes Bạn muốn có nhiều loại shapes (i.e.: rectangle, triangle, circle ) có thuộc tính riêng có điểm chung, điểm mà shapes có Một chúng shapes tự vẽ (draw) chúng Tuy nhiên, việc vẽ hình lên hình phụ thuộc vào thực đồ họa (hình dáng loại shape) khác hệ điều hành khác Bạn muốn shapes thực thao tác vẽ nhiều loại hệ thống shape tự xử lí toàn hay phải chỉnh sửa shape class để phù hợp cho kiến trúc khác không thực tiễn Dạng thức bắc cầu giúp cho bạn tạo lớp cung cấp thực tác vụ vẽ Lớp trừu tượng, shape, cung cấp phương thức để lấy thông tin kích thước thuộc tính shape lớp thực, vẽ, cung cấp giao diện cho tác vụ vẽ Bây shape cần tạo (một hình tuyết chẳng hạn) hay muốn vẽ hĩnh vẽ bạn hàm đồ họa API việc thêm lớp để xây dựng (implement) đặc tính bạn cần 1/3 Bridgepattern Cấu trúc • Client ◦ Đối tượng cần dùng dạng thức bắc cầu • Abstraction ◦ định abstract interface ◦ quản lí việc tham chiếu đến đối tượng thực cụ thể (Implementor) • Refined Abstraction ◦ Mở rộng interface mà định Abstraction • Implementor ◦ định interface cho lớp thực (Thông thường Abstraction interface định tác vụ mức cao dựa thực interface này.) • ConcreteImplementor ◦ thực Implementor interface Ví dụ Java Chương trình Java sau minh hoạ ví dụ "shapes" nói đưa kết quả: API1.circle at 1.000000:2.000000 radius 7.500000 API2.circle at 5.000000:7.000000 radius 27.500000 /** "Implementor" */ interface DrawingAPI { public void drawCircle(double x, double y, double radius); } /** "ConcreteImplementor" 1/2 */ class DrawingAPI1 implements 2/3 Bridgepattern DrawingAPI { public void drawCircle(double x, double y, double radius) { System.out.printf("API1.circle at %f:%f radius %f\n", x, y, radius); } } /** "ConcreteImplementor" 2/2 */ class DrawingAPI2 implements DrawingAPI { public void drawCircle(double x, double y, double radius) { System.out.printf("API2.circle at %f:%f radius %f\n", x, y, radius); } } /** "Abstraction" */ interface Shape { public void draw(); // low-level public void resizeByPercentage(double pct); // high-level } /** "Refined Abstraction" */ class CircleShape implements Shape { private double x, y, radius; private DrawingAPI drawingAPI; public CircleShape(double x, double y, double radius, DrawingAPI drawingAPI) { this.x = x; this.y = y; this.radius = radius; this.drawingAPI = drawingAPI; } // low-level i.e Implementation specific public void draw() { drawingAPI.drawCircle(x, y, radius); } // high-level i.e Abstraction specific public void resizeByPercentage(double pct) { radius *= pct; } } /** "Client" */ class BridgePattern { public static void main(String[] args) { Shape[] shapes = new Shape[2]; shapes[0] = new CircleShape(1, 2, 3, new DrawingAPI1()); shapes[1] = new CircleShape(5, 7, 11, new DrawingAPI2()); for (Shape shape : shapes) { shape.resizeByPercentage(2.5); shape.draw(); } } } 3/3 CHAPTER 3 ■ OBJECT BASICS
29
function getSummaryLine() {
$base = "{$this->title} ( {$this->producerMainName}, ";
$base .= "{$this->producerFirstName} )";
if ( $this->type == 'book' ) {
$base .= ": page count - {$this->numPages}";
} else if ( $this->type == 'cd' ) {
$base .= ": playing time - {$this->playLength}";
}
return $base;
}
In order to set the $type property, I could test the $numPages argument to the constructor. Still, once
again, the ShopProduct class has become more complex than necessary. As I add more differences to my
formats, or add new formats, these functional differences will become even harder to manage. Perhaps I
should try another approach to this problem.
Since ShopProduct is beginning to feel like two classes in one, I could accept this and create two
types rather than one. Here’s how I might do it:
class CdProduct {
public $playLength;
public $title;
public $producerMainName;
public $producerFirstName;
public $price;
function __construct( $title, $firstName,
$mainName, $price,
$playLength ) {
$this->title = $title;
$this->producerFirstName = $firstName;
$this->producerMainName = $mainName;
$this->price = $price;
$this->playLength = $playLength;
}
function getPlayLength() {
return $this->playLength;
}
function getSummaryLine() {
$base = "{$this->title} ( {$this->producerMainName}, ";
$base .= "{$this->producerFirstName} )";
$base .= ": playing time - {$this->playLength}";
return $base;
}
function getProducer() {
return "{$this->producerFirstName}".
" {$this->producerMainName}";
}
}
class BookProduct {
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
CHAPTER 3 ■ OBJECT BASICS
30
public $numPages;
public $title;
public $producerMainName;
public $producerFirstName;
public $price;
function __construct( $title, $firstName,
$mainName, $price,
$numPages ) {
$this->title = $title;
$this->producerFirstName = $firstName;
$this->producerMainName = $mainName;
$this->price = $price;
$this->numPages = $numPages;
}
function getNumberOfPages() {
return $this->numPages;
}
function getSummaryLine() {
$base = "{$this->title} ( {$this->producerMainName}, ";
$base .= "{$this->producerFirstName} )";
$base .= ": page count - {$this->numPages}";
return $base;
}
function getProducer() {
return "{$this->producerFirstName}".
" {$this->producerMainName}";
}
}
I have addressed the complexity issue, but at a cost. I can now create a getSummaryLine() method for
each format without having to test a flag. Neither class maintains fields or methods that are not relevant
to it.
The cost lies in duplication. The getProducerName() method is exactly the same in each class. Each
constructor sets a number of identical properties in the same way. This is another unpleasant odor you
should train yourself to sniff out.
If I need the getProducer() methods to behave identically for each class, any changes I make to one
implementation will need to be made for the other. Without care, the classes will soon slip out of
synchronization.
Even if I am confident that I can maintain the duplication, my worries are not over. I now have two
types rather than one.
Remember the ShopProductWriter class? Its write() method is designed to work with a single type:
ShopProduct. How can I amend this to work as before? I could remove the class type hint from the
method declaration, but then I must trust to luck that write() is passed an object of the correct type. I
could add my own type checking code to the body of the method:
class ShopProductWriter {
public function write( $shopProduct ) {
if ( ! ( CHAPTER 5 ■ OBJECT TOOLS
79
Neither solution is ideal. By specifying paths in this much detail, you freeze the library file in place.
In using an absolute path, you tie the library to a particular file system. Whenever you install the
project on a new server, all require statements will need changing to account for a new file path.
By using a relative path, you fix the relationship between the script’s working directory and the
library. This can make libraries hard to relocate on the filesystem without editing require() statements
and impractical to share among projects without making copies. In either case, you lose the package
idea in all the additional directories. Is it the business package, or is it the projectlib/business package?
In order to make included libraries work well in your code, you need to decouple the invoking code
from the library so that
business/User.php
can be referenced from anywhere on a system. You can do this by putting the package in one of the
directories to which the include_path directive refers. include_path is usually set in PHP’s central
configuration file, php.ini. It defines a list of directories separated by colons on Unix-like systems and
semicolons on Windows systems.
include_path = ".:/usr/local/lib/php-libraries"
If you’re using Apache you can also set include_path in the server application’s configuration file
(usually called httpd.conf) or a per-directory Apache configuration file (usually called .htaccess) with
this syntax:
php_value include_path value .:/usr/local/lib/php-libraries
■Note .htaccess files are particularly useful in web space provided by some hosting companies, which provide
very limited access to the server environment.
When you use a filesystem function such as fopen() or require() with a nonabsolute path that does
not exist relative to the current working directory, the directories in the include path are searched
automatically, beginning with the first in the list (in the case of fopen() you must include a flag in its
argument list to enable this feature). When the target file is encountered, the search ends, and the file
function completes its task.
So by placing a package directory in an include directory, you need only refer to packages and files
in your require() statements.
You may need to add a directory to the include_path so that you can maintain your own library
directory. To do this, you can, of course, edit the php.ini file (remember that, for the PHP server module,
you will need to restart your server for the changes to take effect).
If you do not have the privileges necessary to work with the php.ini file, you can set the include path
from within your scripts using the set_include_path() function. set_include_path() accepts an include
path (as it would appear in php.ini) and changes the include_path setting for the current process only.
The php.ini file probably already defines a useful value for include_path, so rather than overwrite it, you
can access it using the get_include_path() function and append your own directory. Here’s how you can
add a directory to the current include path:
set_include_path( get_include_path().":/home/john/phplib/");
If you are working on a Windows platform, you should use semicolons rather than colons to
separate each directory path.
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
CHAPTER 5 ■ OBJECT TOOLS
80
Autoload
In some circumstances, you may wish to organize your classes so that each sits in its own file. There is
overhead to this approach (including a file comes with a cost), but this kind of organization can be very
useful, especially if your system needs to expand to accommodate new classes at runtime (see the
Command pattern in Chapters 11 and 12 for more on this kind of strategy). In such cases, each class file
may bear a fixed relationship to the name CHAPTER 12 ■ ENTERPRISE PATTERNS
229
When you need to put your system through its paces, you can use test mode to switch in a fake
registry. This can serve up stubs (objects that fake a real environment for testing purposes) or mocks
(similar objects that also analyze calls made to them and assess them for correctness).
Registry::testMode();
$mockreg = Registry::instance();
You can read more about mock and stub objects in Chapter 18, “Testing with PHPUnit.”
Registry, Scope, and PHP
The term scope is often used to describe the visibility of an object or value in the context of code
structures. The lifetime of a variable can also be measured over time. There are three levels of scope you
might consider in this sense. The standard is the period covered by an HTTP request.
PHP also provides built-in support for session variables. These are serialized and saved to the file
system or the database at the end of a request, and then restored at the start of the next. A session ID
stored in a cookie or passed around in query strings is used to keep track of the session owner. Because
of this, you can think of some variables having session scope. You can take advantage of this by storing
some objects between requests, saving a trip to the database. Clearly, you need to be careful that you
don’t end up with multiple versions of the same object, so you may need to consider a locking strategy
when you check an object that also exists in a database into a session.
In other languages, notably Java and Perl (running on the ModPerl Apache module), there is the
concept of application scope. Variables that occupy this space are available across all instances of the
application. This is fairly alien to PHP, but in larger applications, it is very useful to have access to an
applicationwide space for accessing configuration variables. You can build a registry class that emulates
application scope, though you must be aware of some pretty considerable caveats.
Figure 12–3 shows a possible structure for Registry classes that work on the three levels I have
described.
Figure 12–3.
Implementing registry classes for different scopes
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
CHAPTER 12 ■ ENTERPRISE PATTERNS
230
The base class defines two protected methods, get() and set(). They are not available to client
code, because I want to enforce type for get and set operations. The base class may define other public
methods such as isEmpty(), isPopulated(), and clear(), but I’ll leave those as an exercise for you to do.
■Note In a real-world system, you might want to extend this structure to include another layer of inheritance.
You might keep the concrete get() and set() methods in their respective implementations, but specialize the
public
getAaa() and setAaa() methods into domain-specific classes. The new specializations would become the
singletons. That way you could reuse the core save and retrieve operations across multiple applications.
Here is the abstract class as code:
namespace woo\base;
abstract class Registry {
abstract protected function get( $key );
abstract protected function set( $key, $val );
}
■Note Notice that I’m using namespaces in these examples. Because I will be building a complete, if basic,
system in this chapter, it makes sense to use a package hierarchy, and to take advantage of the brevity and clarity
that namespaces can bring to a project.
The request level class is pretty straightforward. In another variation from my previous example, I
keep the Registry sole instance hidden and provide static methods to set and get objects. Apart from
that, it’s simply a matter of maintaining an associative array.
namespace woo\base;
//
class RequestRegistry extends Registry {
private $values = array();
private static $instance; .. .Bridge pattern Cấu trúc • Client ◦ Đối tượng cần dùng dạng thức bắc cầu • Abstraction ◦ định abstract... double y, double radius); } /** "ConcreteImplementor" 1/2 */ class DrawingAPI1 implements 2/3 Bridge pattern DrawingAPI { public void drawCircle(double x, double y, double radius) { System.out.printf("API1.circle... specific public void resizeByPercentage(double pct) { radius *= pct; } } /** "Client" */ class BridgePattern { public static void main(String[] args) { Shape[] shapes = new Shape[2]; shapes[0] =